From 13341f4c6b6fa470a97781703ac6fe356e307194 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 9 Mar 2017 13:45:52 +0100 Subject: [PATCH 001/662] Reword the non-dropping of `src` for `ptr::write{,_unaligned}` --- src/libcore/ptr.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 260fdab9d58fb..0b7aa4fa9117c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -191,9 +191,8 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// -/// It does not immediately drop the contents of `src` either; it is rather -/// *moved* into the memory location `dst` and will be dropped whenever that -/// location goes out of scope. +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. @@ -233,6 +232,9 @@ pub unsafe fn write(dst: *mut T, src: T) { /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. /// From c7db40f23256c14f2ef6d43e3091135791e5e153 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 9 Mar 2017 21:05:56 +0200 Subject: [PATCH 002/662] Rename expected_types_for_fn_args to expected_inputs_for_expected_output. --- src/librustc_typeck/check/callee.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 4b88f5acf42da..529ee107c46ce 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -254,7 +254,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Call the generic checker. let expected_arg_tys = - self.expected_types_for_fn_args(call_expr.span, + self.expected_inputs_for_expected_output(call_expr.span, expected, fn_sig.output(), fn_sig.inputs()); @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // do know the types expected for each argument and the return // type. - let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, + let expected_arg_tys = self.expected_inputs_for_expected_output(call_expr.span, expected, fn_sig.output().clone(), fn_sig.inputs()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8957bad0986c..847aea553534d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2321,7 +2321,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method_fn_ty.sty { ty::TyFnDef(def_id, .., ref fty) => { // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_types_for_fn_args( + let expected_arg_tys = self.expected_inputs_for_expected_output( sp, expected, fty.0.output(), @@ -2674,14 +2674,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TypeAndSubsts { substs: substs, ty: substd_ty } } - /// Unifies the return type with the expected type early, for more coercions - /// and forward type information on the argument expressions. - fn expected_types_for_fn_args(&self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: Ty<'tcx>, - formal_args: &[Ty<'tcx>]) - -> Vec> { + /// Unifies the output type with the expected type early, for more coercions + /// and forward type information on the input expressions. + fn expected_inputs_for_expected_output(&self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: Ty<'tcx>, + formal_args: &[Ty<'tcx>]) + -> Vec> { let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { // Attempt to apply a subtyping relationship between the formal @@ -2704,7 +2704,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }).collect()) }).ok() }).unwrap_or(vec![]); - debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})", + debug!("expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", formal_args, formal_ret, expected_args, expected_ret); expected_args From 50aee36d26dd78ddc78670b2ad63d276c5faa646 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 9 Mar 2017 21:06:18 +0200 Subject: [PATCH 003/662] Propagate expected type hints through struct literals. --- src/librustc_typeck/check/mod.rs | 29 +++++++++++++++++++++-------- src/test/run-pass/issue-31260.rs | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/issue-31260.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 847aea553534d..f43dcefb84591 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3061,14 +3061,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_struct_fields(&self, adt_ty: Ty<'tcx>, + expected: Expectation<'tcx>, expr_id: ast::NodeId, span: Span, variant: &'tcx ty::VariantDef, ast_fields: &'gcx [hir::Field], check_completeness: bool) { let tcx = self.tcx; - let (substs, adt_kind, kind_name) = match adt_ty.sty { - ty::TyAdt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()), + + let adt_ty_hint = + self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]) + .get(0).cloned().unwrap_or(adt_ty); + + let (substs, hint_substs, adt_kind, kind_name) = match (&adt_ty.sty, &adt_ty_hint.sty) { + (&ty::TyAdt(adt, substs), &ty::TyAdt(_, hint_substs)) => { + (substs, hint_substs, adt.adt_kind(), adt.variant_descr()) + } _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3083,10 +3091,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Typecheck each field. for field in ast_fields { - let expected_field_type; + let final_field_type; + let field_type_hint; if let Some(v_field) = remaining_fields.remove(&field.name.node) { - expected_field_type = self.field_ty(field.span, v_field, substs); + final_field_type = self.field_ty(field.span, v_field, substs); + field_type_hint = self.field_ty(field.span, v_field, hint_substs); seen_fields.insert(field.name.node, field.span); @@ -3098,7 +3108,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } else { error_happened = true; - expected_field_type = tcx.types.err; + final_field_type = tcx.types.err; + field_type_hint = tcx.types.err; if let Some(_) = variant.find_field_named(field.name.node) { let mut err = struct_span_err!(self.tcx.sess, field.name.span, @@ -3120,7 +3131,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue typechecking - self.check_expr_coercable_to_type(&field.expr, expected_field_type); + let ty = self.check_expr_with_hint(&field.expr, field_type_hint); + self.demand_coerce(&field.expr, ty, final_field_type); } // Make sure the programmer specified correct number of fields. @@ -3230,6 +3242,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_struct(&self, expr: &hir::Expr, + expected: Expectation<'tcx>, qpath: &hir::QPath, fields: &'gcx [hir::Field], base_expr: &'gcx Option>) -> Ty<'tcx> @@ -3248,7 +3261,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::QPath::TypeRelative(ref qself, _) => qself.span }; - self.check_expr_struct_fields(struct_ty, expr.id, path_span, variant, fields, + self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, struct_ty); @@ -3793,7 +3806,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::ExprStruct(ref qpath, ref fields, ref base_expr) => { - self.check_expr_struct(expr, qpath, fields, base_expr) + self.check_expr_struct(expr, expected, qpath, fields, base_expr) } hir::ExprField(ref base, ref field) => { self.check_field(expr, lvalue_pref, &base, field) diff --git a/src/test/run-pass/issue-31260.rs b/src/test/run-pass/issue-31260.rs new file mode 100644 index 0000000000000..e771fc7464d00 --- /dev/null +++ b/src/test/run-pass/issue-31260.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +pub struct Struct { + pub field: K, +} + +// Partial fix for #31260, doesn't work without {...}. +static STRUCT: Struct<&'static [u8]> = Struct { + field: {&[1]} +}; + +fn main() {} From e2b4824b886d6a809bcd29f901c5bf62ab56f727 Mon Sep 17 00:00:00 2001 From: Joshua Horwitz Date: Tue, 7 Mar 2017 23:04:59 -0500 Subject: [PATCH 004/662] Removed RustFMT changes --- src/libstd/process.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index f846ef3e69e09..e5ce30c5539fc 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -343,6 +343,23 @@ impl Command { /// Add an argument to pass to the program. /// + /// Only one argument can be passed per use. So instead of: + /// + /// ```ignore + /// .arg("-C /path/to/repo") + /// ``` + /// + /// usage would be: + /// + /// ```ignore + /// .arg("-C") + /// .arg("/path/to/repo") + /// ``` + /// + /// To pass multiple arguments see [`args`]. + /// + /// [`args`]: #method.args + /// /// # Examples /// /// Basic usage: @@ -364,6 +381,10 @@ impl Command { /// Add multiple arguments to pass to the program. /// + /// To pass a single argument see [`arg`]. + /// + /// [`arg`]: #method.arg + /// /// # Examples /// /// Basic usage: From 560944b982385623655f1e8503af5e7b4ca0a436 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Mon, 13 Feb 2017 20:37:42 -0500 Subject: [PATCH 005/662] Add From> implementations. --- src/libcollections/string.rs | 16 +++++++++++++++ src/libcollections/vec.rs | 16 +++++++++++++++ src/libstd/ffi/c_str.rs | 33 ++++++++++++++++++++++++------- src/libstd/ffi/os_str.rs | 34 +++++++++++++++++++++++++------- src/libstd/path.rs | 34 +++++++++++++++++++++++++------- src/libstd/sys/redox/os_str.rs | 6 ++++++ src/libstd/sys/unix/os_str.rs | 6 ++++++ src/libstd/sys/windows/os_str.rs | 6 ++++++ src/libstd/sys_common/wtf8.rs | 6 ++++++ 9 files changed, 136 insertions(+), 21 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 43323676ab459..13c99a2d59bed 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1974,6 +1974,22 @@ impl<'a> From<&'a str> for String { } } +// note: test pulls in libstd, which causes errors here +#[cfg(not(test))] +#[stable(feature = "string_from_box", since = "1.17.0")] +impl From> for String { + fn from(s: Box) -> String { + s.into_string() + } +} + +#[stable(feature = "box_from_str", since = "1.17.0")] +impl Into> for String { + fn into(self) -> Box { + self.into_boxed_str() + } +} + #[stable(feature = "string_from_cow_str", since = "1.14.0")] impl<'a> From> for String { fn from(s: Cow<'a, str>) -> String { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d38c9f6e1cf80..e4a6af33409e1 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1897,6 +1897,22 @@ impl<'a, T> From> for Vec where [T]: ToOwned> { } } +// note: test pulls in libstd, which causes errors here +#[cfg(not(test))] +#[stable(feature = "vec_from_box", since = "1.17.0")] +impl From> for Vec { + fn from(s: Box<[T]>) -> Vec { + s.into_vec() + } +} + +#[stable(feature = "box_from_vec", since = "1.17.0")] +impl Into> for Vec { + fn into(self) -> Box<[T]> { + self.into_boxed_slice() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Vec { fn from(s: &'a str) -> Vec { diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index bc678fcb8385b..a3f4154ba4af7 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -304,7 +304,7 @@ impl CString { } /// Converts this `CString` into a boxed `CStr`. - #[unstable(feature = "into_boxed_c_str", issue = "0")] + #[unstable(feature = "into_boxed_c_str", issue = "40380")] pub fn into_boxed_c_str(self) -> Box { unsafe { mem::transmute(self.into_inner()) } } @@ -394,6 +394,20 @@ impl<'a> From<&'a CStr> for Box { } } +#[stable(feature = "c_string_from_box", since = "1.17.0")] +impl From> for CString { + fn from(s: Box) -> CString { + s.into_c_string() + } +} + +#[stable(feature = "box_from_c_string", since = "1.17.0")] +impl Into> for CString { + fn into(self) -> Box { + self.into_boxed_c_str() + } +} + #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { @@ -694,6 +708,12 @@ impl CStr { pub fn to_string_lossy(&self) -> Cow { String::from_utf8_lossy(self.to_bytes()) } + + /// Converts a `Box` into a `CString` without copying or allocating. + #[unstable(feature = "into_boxed_c_str", issue = "40380")] + pub fn into_c_string(self: Box) -> CString { + unsafe { mem::transmute(self) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -888,12 +908,11 @@ mod tests { fn into_boxed() { let orig: &[u8] = b"Hello, world!\0"; let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let cstring = cstr.to_owned(); - let box1: Box = Box::from(cstr); - let box2 = cstring.into_boxed_c_str(); - assert_eq!(cstr, &*box1); - assert_eq!(box1, box2); - assert_eq!(&*box2, cstr); + let boxed: Box = Box::from(cstr); + let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); + assert_eq!(cstr, &*boxed); + assert_eq!(&*boxed, &*cstring); + assert_eq!(&*cstring, cstr); } #[test] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 7b8bf42e0a74a..c9c207d8b8eb4 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -206,7 +206,7 @@ impl OsString { } /// Converts this `OsString` into a boxed `OsStr`. - #[unstable(feature = "into_boxed_os_str", issue = "0")] + #[unstable(feature = "into_boxed_os_str", issue = "40380")] pub fn into_boxed_os_str(self) -> Box { unsafe { mem::transmute(self.inner.into_box()) } } @@ -442,6 +442,13 @@ impl OsStr { self.inner.inner.len() } + /// Converts a `Box` into an `OsString` without copying or allocating. + #[unstable(feature = "into_boxed_os_str", issue = "40380")] + pub fn into_os_string(self: Box) -> OsString { + let inner: Box = unsafe { mem::transmute(self) }; + OsString { inner: Buf::from_box(inner) } + } + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is private, to avoid @@ -458,6 +465,20 @@ impl<'a> From<&'a OsStr> for Box { } } +#[stable(feature = "os_string_from_box", since = "1.17.0")] +impl<'a> From> for OsString { + fn from(boxed: Box) -> OsString { + boxed.into_os_string() + } +} + +#[stable(feature = "box_from_c_string", since = "1.17.0")] +impl Into> for OsString { + fn into(self) -> Box { + self.into_boxed_os_str() + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { @@ -766,12 +787,11 @@ mod tests { fn into_boxed() { let orig = "Hello, world!"; let os_str = OsStr::new(orig); - let os_string = os_str.to_owned(); - let box1: Box = Box::from(os_str); - let box2 = os_string.into_boxed_os_str(); - assert_eq!(os_str, &*box1); - assert_eq!(box1, box2); - assert_eq!(&*box2, os_str); + let boxed: Box = Box::from(os_str); + let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); + assert_eq!(os_str, &*boxed); + assert_eq!(&*boxed, &*os_string); + assert_eq!(&*os_string, os_str); } #[test] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 245a6d945b5a3..49b01bc085373 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1196,7 +1196,7 @@ impl PathBuf { } /// Converts this `PathBuf` into a boxed `Path`. - #[unstable(feature = "into_boxed_path", issue = "0")] + #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_boxed_path(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_os_str()) } } @@ -1210,6 +1210,20 @@ impl<'a> From<&'a Path> for Box { } } +#[stable(feature = "path_buf_from_box", since = "1.17.0")] +impl<'a> From> for PathBuf { + fn from(boxed: Box) -> PathBuf { + boxed.into_path_buf() + } +} + +#[stable(feature = "box_from_path_buf", since = "1.17.0")] +impl Into> for PathBuf { + fn into(self) -> Box { + self.into_boxed_path() + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { @@ -2089,6 +2103,13 @@ impl Path { pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } + + /// Converts a `Box` into a `PathBuf` without copying or allocating. + #[unstable(feature = "into_boxed_path", issue = "40380")] + pub fn into_path_buf(self: Box) -> PathBuf { + let inner: Box = unsafe { mem::transmute(self) }; + PathBuf { inner: OsString::from(inner) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3703,12 +3724,11 @@ mod tests { fn into_boxed() { let orig: &str = "some/sort/of/path"; let path = Path::new(orig); - let path_buf = path.to_owned(); - let box1: Box = Box::from(path); - let box2 = path_buf.into_boxed_path(); - assert_eq!(path, &*box1); - assert_eq!(box1, box2); - assert_eq!(&*box2, path); + let boxed: Box = Box::from(path); + let path_buf = path.to_owned().into_boxed_path().into_path_buf(); + assert_eq!(path, &*boxed); + assert_eq!(&*boxed, &*path_buf); + assert_eq!(&*path_buf, path); } #[test] diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 0f967863899cb..90b8289524e26 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -99,6 +99,12 @@ impl Buf { pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_slice()) } } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } } impl Slice { diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index 938bcfc6d162e..225924168a5b2 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -99,6 +99,12 @@ impl Buf { pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_slice()) } } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } } impl Slice { diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 04e45dcf54963..810b67b785b5c 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -93,6 +93,12 @@ impl Buf { pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_box()) } } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box = unsafe { mem::transmute(boxed) }; + Buf { inner: Wtf8Buf::from_box(inner) } + } } impl Slice { diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 1d61181a4ee0f..28cab10e8f9cc 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -346,6 +346,12 @@ impl Wtf8Buf { pub fn into_box(self) -> Box { unsafe { mem::transmute(self.bytes.into_boxed_slice()) } } + + /// Converts a `Box` into a `Wtf8Buf`. + pub fn from_box(boxed: Box) -> Wtf8Buf { + let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Wtf8Buf { bytes: bytes.into_vec() } + } } /// Create a new WTF-8 string from an iterator of code points. From e31e264c55be03e7ca9477bfb32ffa03387ac8a2 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Thu, 9 Mar 2017 17:49:37 +0900 Subject: [PATCH 006/662] rustbuild: Make save-analysis an option --- configure | 1 + src/bootstrap/config.rs | 4 ++++ src/bootstrap/config.toml.example | 3 +++ src/bootstrap/dist.rs | 10 +--------- src/bootstrap/lib.rs | 2 +- src/ci/run.sh | 1 + 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/configure b/configure index d8861dacafac1..fae457e9c0b15 100755 --- a/configure +++ b/configure @@ -645,6 +645,7 @@ 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 "check if the LLVM version is supported, build anyway" opt codegen-tests 1 "run the src/test/codegen tests" +opt save-analysis 0 "save API analysis data" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" opt locked-deps 0 "force Cargo.lock to be up to date" diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 87c35e0502ce6..b652770354989 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -73,6 +73,7 @@ pub struct Config { pub rustc_default_ar: Option, pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, + pub rust_save_analysis: bool, pub rust_dist_src: bool, pub build: String, @@ -223,6 +224,7 @@ struct Rust { optimize_tests: Option, debuginfo_tests: Option, codegen_tests: Option, + save_analysis: Option, } /// TOML representation of how each build target is configured. @@ -347,6 +349,7 @@ impl Config { set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); + set(&mut config.rust_save_analysis, rust.save_analysis); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); @@ -453,6 +456,7 @@ impl Config { ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), ("CODEGEN_TESTS", self.codegen_tests), + ("SAVE_ANALYSIS", self.rust_save_analysis), ("LOCKED_DEPS", self.locked_deps), ("VENDOR", self.vendor), ("FULL_BOOTSTRAP", self.full_bootstrap), diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 776bd729119e2..42cf3dcabf4ea 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -229,6 +229,9 @@ # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true +# Flag indicating whether the API analysis data should be saved. +#save-analysis = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 5c4b718490c0c..30f4f6b33df4a 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -313,16 +313,8 @@ pub fn rust_src_location(build: &Build) -> PathBuf { pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { println!("Dist analysis"); - if build.config.channel != "nightly" { - println!("\tskipping - not on nightly channel"); - return; - } if compiler.host != build.config.build { - println!("\tskipping - not a build host"); - return - } - if compiler.stage != 2 { - println!("\tskipping - not stage2"); + println!("\tskipping, not a build host"); return } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4831b38083740..f234db98bc3f4 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -524,7 +524,7 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } - if self.config.channel == "nightly" && compiler.is_final_stage(self) { + if self.config.rust_save_analysis && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } diff --git a/src/ci/run.sh b/src/ci/run.sh index 4c4836d7ca230..55c6196b1ae73 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -42,6 +42,7 @@ fi if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=nightly" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-save-analysis" if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" From 5a88c7e5a16227bb74d78d36ba4f37ebf5dec8d4 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Fri, 10 Mar 2017 09:35:17 +0900 Subject: [PATCH 007/662] rustbuild: Skip saving analysis when disabled --- src/bootstrap/dist.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 30f4f6b33df4a..b44f0834f3039 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -311,6 +311,10 @@ pub fn rust_src_location(build: &Build) -> PathBuf { /// Creates a tarball of save-analysis metadata, if available. pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { + if !build.config.rust_save_analysis { + return + } + println!("Dist analysis"); if compiler.host != build.config.build { From d4040c3a3fa9cc416f2f997b52946d6cd6b17e48 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sat, 11 Mar 2017 20:00:01 +0900 Subject: [PATCH 008/662] rustbuild: Add save-analysis to install --- src/bootstrap/install.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index ba8442ebd8c37..249f241a151bb 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -49,6 +49,10 @@ pub fn install(build: &Build, stage: u32, host: &str) { install_sh(&build, "docs", "rust-docs", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } + if build.config.rust_save_analysis { + install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, + &docdir, &libdir, &mandir, &empty_dir); + } install_sh(&build, "std", "rust-std", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); install_sh(&build, "rustc", "rustc", stage, host, &prefix, From 6ba494b68bede3bd8d1288f53137c8895260bec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 11 Mar 2017 11:11:50 -0800 Subject: [PATCH 009/662] Point to let when modifying field of immutable variable Point at the immutable local variable when trying to modify one of its fields. Given a file: ```rust struct Foo { pub v: Vec } fn main() { let f = Foo { v: Vec::new() }; f.v.push("cat".to_string()); } ``` present the following output: ``` error: cannot borrow immutable field `f.v` as mutable --> file.rs:7:13 | 6 | let f = Foo { v: Vec::new() }; | - this should be `mut` 7 | f.v.push("cat".to_string()); | ^^^ error: aborting due to previous error ``` --- src/librustc/middle/mem_categorization.rs | 15 +++++++++++++++ src/librustc_borrowck/borrowck/mod.rs | 12 ++++++++++++ src/test/ui/did_you_mean/issue-39544.stderr | 2 ++ 3 files changed, 29 insertions(+) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b0c85e2ef4cd4..7db206296933b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -195,6 +195,21 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; impl<'tcx> cmt_<'tcx> { + pub fn get_def(&self) -> Option { + match self.cat { + Categorization::Deref(ref cmt, ..) | + Categorization::Interior(ref cmt, _) | + Categorization::Downcast(ref cmt, _) => { + if let Categorization::Local(nid) = cmt.cat { + Some(nid) + } else { + None + } + } + _ => None + } + } + pub fn get_field(&self, name: ast::Name) -> Option { match self.cat { Categorization::Deref(ref cmt, ..) | diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 47b614a81ae25..04036d6c6b9e7 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -659,6 +659,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { let span = err.span.clone(); let mut immutable_field = None; + let mut local_def = None; let msg = &match err.code { err_mutbl => { @@ -708,6 +709,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } None }); + local_def = err.cmt.get_def() + .and_then(|nid| { + if !self.tcx.hir.is_argument(nid) { + Some(self.tcx.hir.span(nid)) + } else { + None + } + }); format!("cannot borrow {} as mutable", descr) } @@ -738,6 +747,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some((span, msg)) = immutable_field { db.span_label(span, &msg); } + if let Some(span) = local_def { + db.span_label(span, &"this should be `mut`"); + } db } diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index c0088f39ad3e1..1cd322efab57d 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -1,6 +1,8 @@ error: cannot borrow immutable field `z.x` as mutable --> $DIR/issue-39544.rs:21:18 | +20 | let z = Z { x: X::Y }; + | - this should be `mut` 21 | let _ = &mut z.x; | ^^^ From d95c5437222fd63d7b12676bc7916dbeb720f131 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 17 Feb 2017 15:12:47 -0800 Subject: [PATCH 010/662] Add catch expr to AST and disallow catch as a struct name --- src/librustc/hir/lowering.rs | 37 +++++++++++++++++-- src/libsyntax/ast.rs | 2 + src/libsyntax/feature_gate.rs | 6 +++ src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 35 ++++++++++++++++++ src/libsyntax/print/pprust.rs | 5 +++ src/libsyntax/symbol.rs | 3 +- src/libsyntax/visit.rs | 3 ++ .../compile-fail/catch-empty-struct-name.rs | 15 ++++++++ src/test/compile-fail/catch-enum-variant.rs | 17 +++++++++ src/test/compile-fail/catch-struct-name.rs | 15 ++++++++ .../compile-fail/catch-tuple-struct-name.rs | 15 ++++++++ .../compile-fail/feature-gate-catch_expr.rs | 17 +++++++++ src/test/run-pass/catch-expr.rs | 30 +++++++++++++++ 14 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/catch-empty-struct-name.rs create mode 100644 src/test/compile-fail/catch-enum-variant.rs create mode 100644 src/test/compile-fail/catch-struct-name.rs create mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs create mode 100644 src/test/compile-fail/feature-gate-catch_expr.rs create mode 100644 src/test/run-pass/catch-expr.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index aa6614b0af4f7..d92eaee6f0c8e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -84,6 +84,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -123,6 +124,7 @@ pub fn lower_crate(sess: &Session, trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), exported_macros: Vec::new(), + catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -261,6 +263,21 @@ impl<'a> LoweringContext<'a> { span } + fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.catch_scopes.len(); + self.catch_scopes.push(catch_id); + + let result = f(self); + assert_eq!(len + 1, self.catch_scopes.len(), + "catch scopes should be added and removed in stack order"); + + self.catch_scopes.pop().unwrap(); + + result + } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -295,15 +312,17 @@ impl<'a> LoweringContext<'a> { result } - fn with_new_loop_scopes(&mut self, f: F) -> T + fn with_new_scopes(&mut self, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; + let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new()); let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); let result = f(self); - mem::replace(&mut self.loop_scopes, loop_scopes); + self.catch_scopes = catch_scopes; + self.loop_scopes = loop_scopes; self.is_in_loop_condition = was_in_loop_condition; @@ -1065,7 +1084,7 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { let body = this.lower_block(body); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); @@ -1665,13 +1684,17 @@ impl<'a> LoweringContext<'a> { this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } + ExprKind::Catch(ref body) => { + // FIXME(cramertj): Add catch to HIR + self.with_catch_scope(e.id, |this| hir::ExprBlock(this.lower_block(body))) + } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { let expr = this.lower_expr(body); hir::ExprClosure(this.lower_capture_clause(capture_clause), @@ -2069,6 +2092,12 @@ impl<'a> LoweringContext<'a> { // Err(err) => #[allow(unreachable_code)] // return Carrier::from_error(From::from(err)), // } + + // FIXME(cramertj): implement breaking to catch + if !self.catch_scopes.is_empty() { + bug!("`?` in catch scopes is unimplemented") + } + let unstable_span = self.allow_internal_unstable("?", e.span); // Carrier::translate() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 981667337d59a..f4e5fd0783b14 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -935,6 +935,8 @@ pub enum ExprKind { Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), + /// A catch block (`catch { ... }`) + Catch(P), /// An assignment (`a = foo()`) Assign(P, P), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7bf16eae9ee6..15913d56d162f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -339,6 +339,9 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + + // Allows the `catch {...}` expression + (active, catch_expr, "1.17.0", Some(31436)), ); declare_features! ( @@ -1287,6 +1290,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } + ast::ExprKind::Catch(_) => { + gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb4eb19be2b15..fe54328026406 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1268,6 +1268,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu }; } ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), + ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, id: folder.new_id(id), span: folder.new_span(span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6446d38e5ef70..c0ee778b7ee9e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -602,6 +602,12 @@ impl<'a> Parser<'a> { } } + pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { + if ident.name == keywords::Catch.name() { + self.span_err(self.span, "cannot use `catch` as the name of a type"); + } + } + /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2273,6 +2279,11 @@ impl<'a> Parser<'a> { BlockCheckMode::Unsafe(ast::UserProvided), attrs); } + if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Catch)); + let lo = self.prev_span.lo; + return self.parse_catch_expr(lo, attrs); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -3092,6 +3103,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } + /// Parse a `catch {...}` expression (`catch` token already eaten) + pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + -> PResult<'a, P> + { + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + let hi = body.span.hi; + Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + } + // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; @@ -3699,6 +3720,14 @@ impl<'a> Parser<'a> { }) } + fn is_catch_expr(&mut self) -> bool { + self.token.is_keyword(keywords::Catch) && + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + + // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. + !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) + } + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) @@ -4875,6 +4904,8 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. @@ -4924,6 +4955,8 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(keywords::Where) { @@ -5440,6 +5473,7 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; + self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5481,6 +5515,7 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; + self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3efadbd00d1e0..c44153d0d3245 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2279,6 +2279,11 @@ impl<'a> State<'a> { self.print_expr(e)?; word(&mut self.s, "?")? } + ast::ExprKind::Catch(ref blk) => { + self.head("catch")?; + space(&mut self.s)?; + self.print_block_with_attrs(&blk, attrs)? + } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c278171aa109a..6642c60d256b3 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,9 +221,10 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + (56, Catch, "catch") // A virtual keyword that resolves to the crate root when used in a lexical scope. - (56, CrateRoot, "{{root}}") + (57, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ee7dd18247b21..a5333f3bb6a6e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -779,6 +779,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } + ExprKind::Catch(ref body) => { + visitor.visit_block(body) + } } visitor.visit_expr_post(expression) diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs new file mode 100644 index 0000000000000..257cb802cc0f8 --- /dev/null +++ b/src/test/compile-fail/catch-empty-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs new file mode 100644 index 0000000000000..7aa162750d189 --- /dev/null +++ b/src/test/compile-fail/catch-enum-variant.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +enum Enum { + catch {} //~ ERROR cannot use `catch` as the name of a type +} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs new file mode 100644 index 0000000000000..63661ccf607a0 --- /dev/null +++ b/src/test/compile-fail/catch-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs new file mode 100644 index 0000000000000..1a8866d85430d --- /dev/null +++ b/src/test/compile-fail/catch-tuple-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs new file mode 100644 index 0000000000000..8a1a5ceae89e0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +pub fn main() { + let catch_result = catch { //~ ERROR `catch` expression is experimental + let x = 5; + x + }; + assert_eq!(catch_result, 5); +} diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs new file mode 100644 index 0000000000000..c70b6100efe4f --- /dev/null +++ b/src/test/run-pass/catch-expr.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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(catch_expr)] + +pub fn main() { + let catch_result = catch { + let x = 5; + x + }; + assert_eq!(catch_result, 5); + + let mut catch = true; + while catch { catch = false; } + assert_eq!(catch, false); + + catch = if catch { false } else { true }; + assert_eq!(catch, true); + + match catch { + _ => {} + }; +} From ea4e8b0a81171d4d6c28a61fa0d1c4d74837bb65 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 3 Mar 2017 14:41:07 -0800 Subject: [PATCH 011/662] Temporarily prefix catch block with do keyword --- src/libsyntax/parse/parser.rs | 18 +++++------------- src/libsyntax/parse/token.rs | 1 + src/libsyntax/print/pprust.rs | 2 +- .../compile-fail/catch-empty-struct-name.rs | 15 --------------- src/test/compile-fail/catch-enum-variant.rs | 17 ----------------- src/test/compile-fail/catch-struct-name.rs | 15 --------------- .../compile-fail/catch-tuple-struct-name.rs | 15 --------------- .../compile-fail/feature-gate-catch_expr.rs | 2 +- src/test/run-pass/catch-expr.rs | 4 +++- 9 files changed, 11 insertions(+), 78 deletions(-) delete mode 100644 src/test/compile-fail/catch-empty-struct-name.rs delete mode 100644 src/test/compile-fail/catch-enum-variant.rs delete mode 100644 src/test/compile-fail/catch-struct-name.rs delete mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c0ee778b7ee9e..252b4ec4660f3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -602,12 +602,6 @@ impl<'a> Parser<'a> { } } - pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { - if ident.name == keywords::Catch.name() { - self.span_err(self.span, "cannot use `catch` as the name of a type"); - } - } - /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2280,6 +2274,7 @@ impl<'a> Parser<'a> { attrs); } if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); let lo = self.prev_span.lo; return self.parse_catch_expr(lo, attrs); @@ -3103,7 +3098,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } - /// Parse a `catch {...}` expression (`catch` token already eaten) + /// Parse a `do catch {...}` expression (`do catch` token already eaten) pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) -> PResult<'a, P> { @@ -3721,8 +3716,9 @@ impl<'a> Parser<'a> { } fn is_catch_expr(&mut self) -> bool { - self.token.is_keyword(keywords::Catch) && - self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + self.token.is_keyword(keywords::Do) && + self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) @@ -4904,7 +4900,6 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -4955,7 +4950,6 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -5473,7 +5467,6 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; - self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5515,7 +5508,6 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; - self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b81c..25601f2420e8a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -86,6 +86,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { !ident_token.is_any_keyword() || ident_token.is_path_segment_keyword() || [ + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), keywords::Continue.name(), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c44153d0d3245..83753f398a376 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2280,7 +2280,7 @@ impl<'a> State<'a> { word(&mut self.s, "?")? } ast::ExprKind::Catch(ref blk) => { - self.head("catch")?; + self.head("do catch")?; space(&mut self.s)?; self.print_block_with_attrs(&blk, attrs)? } diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs deleted file mode 100644 index 257cb802cc0f8..0000000000000 --- a/src/test/compile-fail/catch-empty-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs deleted file mode 100644 index 7aa162750d189..0000000000000 --- a/src/test/compile-fail/catch-enum-variant.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 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_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -enum Enum { - catch {} //~ ERROR cannot use `catch` as the name of a type -} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs deleted file mode 100644 index 63661ccf607a0..0000000000000 --- a/src/test/compile-fail/catch-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs deleted file mode 100644 index 1a8866d85430d..0000000000000 --- a/src/test/compile-fail/catch-tuple-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs index 8a1a5ceae89e0..5568a5cf0aac2 100644 --- a/src/test/compile-fail/feature-gate-catch_expr.rs +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let catch_result = catch { //~ ERROR `catch` expression is experimental + let catch_result = do catch { //~ ERROR `catch` expression is experimental let x = 5; x }; diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index c70b6100efe4f..a9b28a534a348 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -10,8 +10,10 @@ #![feature(catch_expr)] +struct catch {} + pub fn main() { - let catch_result = catch { + let catch_result = do catch { let x = 5; x }; From b1aa99352a69e328094e096bbbd1741b68c0667f Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 6 Mar 2017 18:16:57 -0800 Subject: [PATCH 012/662] Add compile-fail tests for catch expr in match or condition --- src/test/compile-fail/catch-in-match.rs | 15 +++++++++++++++ src/test/compile-fail/catch-in-while.rs | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/compile-fail/catch-in-match.rs create mode 100644 src/test/compile-fail/catch-in-while.rs diff --git a/src/test/compile-fail/catch-in-match.rs b/src/test/compile-fail/catch-in-match.rs new file mode 100644 index 0000000000000..9f9968e81242a --- /dev/null +++ b/src/test/compile-fail/catch-in-match.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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(catch_expr)] + +fn main() { + match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do` +} diff --git a/src/test/compile-fail/catch-in-while.rs b/src/test/compile-fail/catch-in-while.rs new file mode 100644 index 0000000000000..cb8613ee60b42 --- /dev/null +++ b/src/test/compile-fail/catch-in-while.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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(catch_expr)] + +fn main() { + while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do` +} From 97a1b6a055d69cf21faa9773133725bdfddc5196 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 14:13:35 -0400 Subject: [PATCH 013/662] Update usages of 'OSX' (and other old names) to 'macOS'. As of last year with version 'Sierra', the Mac operating system is now called 'macOS'. --- RELEASES.md | 2 +- src/bootstrap/bin/rustc.rs | 2 +- src/bootstrap/check.rs | 2 +- src/bootstrap/compile.rs | 2 +- src/bootstrap/lib.rs | 2 +- src/bootstrap/sanity.rs | 4 ++-- src/doc/book/src/testing.md | 2 +- src/liballoc_jemalloc/lib.rs | 2 +- src/librustc/middle/cstore.rs | 2 +- src/librustc/session/config.rs | 2 +- src/librustc_back/target/apple_base.rs | 8 ++++---- src/librustc_back/target/mod.rs | 4 ++-- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/diagnostics.rs | 2 +- src/librustc_metadata/encoder.rs | 2 +- src/librustc_trans/back/link.rs | 6 +++--- src/librustc_trans/back/linker.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 4 ++-- src/librustdoc/plugins.rs | 2 +- src/libstd/os/macos/mod.rs | 2 +- src/libstd/os/macos/raw.rs | 2 +- src/libstd/rand/mod.rs | 4 ++-- src/libstd/sys/redox/fast_thread_local.rs | 6 +++--- src/libstd/sys/redox/process.rs | 2 +- src/libstd/sys/unix/backtrace/mod.rs | 8 ++++---- src/libstd/sys/unix/ext/net.rs | 2 +- src/libstd/sys/unix/fast_thread_local.rs | 8 ++++---- src/libstd/sys/unix/fd.rs | 2 +- src/libstd/sys/unix/fs.rs | 4 ++-- src/libstd/sys/unix/process/process_common.rs | 4 ++-- src/libstd/sys/unix/process/process_unix.rs | 2 +- src/libstd/sys/unix/stack_overflow.rs | 2 +- src/libstd/thread/local.rs | 6 +++--- src/libterm/terminfo/searcher.rs | 4 ++-- src/test/compile-fail/allocator-dylib-is-system.rs | 2 +- src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs | 2 +- src/test/compile-fail/manual-link-framework.rs | 2 +- src/test/compile-fail/osx-frameworks.rs | 2 +- src/test/run-pass/simd-intrinsic-generic-cast.rs | 2 +- src/tools/compiletest/src/raise_fd_limit.rs | 2 +- 41 files changed, 63 insertions(+), 63 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 606936778c49a..16257c3e9c04c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5056,7 +5056,7 @@ Version 0.1 (2012-01-20) * Compiler works with the following configurations: * Linux: x86 and x86_64 hosts and targets - * MacOS: x86 and x86_64 hosts and targets + * macOS: x86 and x86_64 hosts and targets * Windows: x86 hosts and targets * Cross compilation / multi-target configuration supported. diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61650..ba85e81ff4fc4 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -182,7 +182,7 @@ fn main() { if env::var("RUSTC_RPATH") == Ok("true".to_string()) { let rpath = if target.contains("apple") { - // Note that we need to take one extra step on OSX to also pass + // Note that we need to take one extra step on macOS to also pass // `-Wl,-instal_name,@rpath/...` to get things to work right. To // do that we pass a weird flag to the compiler to get it to do // so. Note that this is definitely a hack, and we should likely diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 68b3623a53f25..0d962bd3b0c93 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -176,7 +176,7 @@ pub fn compiletest(build: &Build, cmd.arg("--docck-python").arg(build.python()); if build.config.build.ends_with("apple-darwin") { - // Force /usr/bin/python on OSX for LLDB tests because we're loading the + // Force /usr/bin/python on macOS for LLDB tests because we're loading the // LLDB plugin's compiled module which only works with the system python // (namely not Homebrew-installed python) cmd.arg("--lldb-python").arg("/usr/bin/python"); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 3459c1d2b8425..4201475c60c12 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -249,7 +249,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) { cargo.env("CFG_LLVM_ROOT", s); } // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or OSX + // not for MSVC or macOS if build.config.llvm_static_stdcpp && !target.contains("windows") && !target.contains("apple") { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 618e4d67705da..75a8b78024846 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -846,7 +846,7 @@ impl Build { .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) .collect::>(); - // If we're compiling on OSX then we add a few unconditional flags + // If we're compiling on macOS then we add a few unconditional flags // indicating that we want libc++ (more filled out than libstdc++) and // we want to compile for 10.7. This way we can ensure that // LLVM/jemalloc/etc are all properly compiled. diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index bc439d6f7826d..235ce9360eff4 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -151,10 +151,10 @@ pub fn check(build: &mut Build) { } for target in build.config.target.iter() { - // Can't compile for iOS unless we're on OSX + // Can't compile for iOS unless we're on macOS if target.contains("apple-ios") && !build.config.build.contains("apple-darwin") { - panic!("the iOS target is only supported on OSX"); + panic!("the iOS target is only supported on macOS"); } // Make sure musl-root is valid if specified diff --git a/src/doc/book/src/testing.md b/src/doc/book/src/testing.md index 291c4481d5513..b4f580fcdfbef 100644 --- a/src/doc/book/src/testing.md +++ b/src/doc/book/src/testing.md @@ -147,7 +147,7 @@ And that's reflected in the summary line: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured ``` -We also get a non-zero status code. We can use `$?` on OS X and Linux: +We also get a non-zero status code. We can use `$?` on macOS and Linux: ```bash $ echo $? diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index a496ab870c63b..a7a67ef76d4f7 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -30,7 +30,7 @@ pub use imp::*; mod imp { use libc::{c_int, c_void, size_t}; - // Note that the symbols here are prefixed by default on OSX and Windows (we + // Note that the symbols here are prefixed by default on macOS and Windows (we // don't explicitly request it), and on Android and DragonFly we explicitly // request it as unprefixing cause segfaults (mismatches in allocators). extern "C" { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index e9fb4632fa178..225d6fc9bb2b2 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -123,7 +123,7 @@ pub enum LinkagePreference { pub enum NativeLibraryKind { NativeStatic, // native static library (.a archive) NativeStaticNobundle, // native static library, which doesn't get bundled into .rlibs - NativeFramework, // OSX-specific + NativeFramework, // macOS-specific NativeUnknown, // default way to specify a dynamic library } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5fff03dabcece..d7a765fb82215 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -971,7 +971,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, always_encode_mir: bool = (false, parse_bool, [TRACKED], "encode MIR of all functions into the crate metadata"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], - "pass `-install_name @rpath/...` to the OSX linker"), + "pass `-install_name @rpath/...` to the macOS linker"), sanitizer: Option = (None, parse_sanitizer, [TRACKED], "Use a sanitizer"), } diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs index 21a2d4293df77..3a551a2b124b7 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_back/target/apple_base.rs @@ -13,12 +13,12 @@ use std::env; use target::TargetOptions; pub fn opts() -> TargetOptions { - // ELF TLS is only available in OSX 10.7+. If you try to compile for 10.6 + // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 // either the linker will complain if it is used or the binary will end up - // segfaulting at runtime when run on 10.6. Rust by default supports OSX + // segfaulting at runtime when run on 10.6. Rust by default supports macOS // 10.7+, but there is a standard environment variable, // MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older - // versions of OSX. For example compiling on 10.10 with + // versions of macOS. For example compiling on 10.10 with // MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate // warnings about the usage of ELF TLS. // @@ -33,7 +33,7 @@ pub fn opts() -> TargetOptions { }).unwrap_or((10, 7)); TargetOptions { - // OSX has -dead_strip, which doesn't rely on function_sections + // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, executables: true, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 0c179469448fe..559418d2c4f5f 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -318,8 +318,8 @@ pub struct TargetOptions { /// Whether the target toolchain is like OpenBSD's. /// Only useful for compiling against OpenBSD, for configuring abi when returning a struct. pub is_like_openbsd: bool, - /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in - /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. + /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS, + /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. pub is_like_osx: bool, /// Whether the target toolchain is like Solaris's. /// Only useful for compiling against Illumos/Solaris, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 49dcffb4830a1..63c14a0035f1a 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -99,7 +99,7 @@ fn register_native_lib(sess: &Session, } let is_osx = sess.target.target.options.is_like_osx; if lib.kind == cstore::NativeFramework && !is_osx { - let msg = "native frameworks are only available on OSX targets"; + let msg = "native frameworks are only available on macOS targets"; match span { Some(span) => span_err!(sess, span, E0455, "{}", msg), None => sess.err(msg), diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index d3a2b6f1683e2..fbdc4695cf826 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -27,7 +27,7 @@ name. Example: "##, E0455: r##" -Linking with `kind=framework` is only supported when targeting OS X, +Linking with `kind=framework` is only supported when targeting macOS, as frameworks are specific to that operating system. Erroneous code example: diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 8ddc1642d9e1c..0c31e30671dc2 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1404,7 +1404,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // // And here we run into yet another obscure archive bug: in which metadata // loaded from archives may have trailing garbage bytes. Awhile back one of -// our tests was failing sporadically on the OSX 64-bit builders (both nopt +// our tests was failing sporadically on the macOS 64-bit builders (both nopt // and opt) by having ebml generate an out-of-bounds panic when looking at // metadata. // diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index a1703b1c155eb..cf1e10b317b1e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -583,7 +583,7 @@ fn link_rlib<'a>(sess: &'a Session, } // After adding all files to the archive, we need to update the - // symbol table of the archive. This currently dies on OSX (see + // symbol table of the archive. This currently dies on macOS (see // #11162), and isn't necessary there anyway if !sess.target.target.options.is_like_osx { ab.update_symbols(); @@ -764,7 +764,7 @@ fn link_natively(sess: &Session, // pain to land PRs when they spuriously fail due to a segfault. // // The issue #38878 has some more debugging information on it as well, but - // this unfortunately looks like it's just a race condition in OSX's linker + // this unfortunately looks like it's just a race condition in macOS's linker // with some thread pool working in the background. It seems that no one // currently knows a fix for this so in the meantime we're left with this... info!("{:?}", &cmd); @@ -841,7 +841,7 @@ fn link_natively(sess: &Session, } - // On OSX, debuggers need this utility to get run to do some munging of + // On macOS, debuggers need this utility to get run to do some munging of // the symbols if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { match Command::new("dsymutil").arg(out_filename).output() { diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 830d1d0d3a558..80801e8161cd0 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -139,7 +139,7 @@ impl<'a> Linker for GnuLinker<'a> { .arg("-l").arg(lib) .arg("-Wl,--no-whole-archive"); } else { - // -force_load is the OSX equivalent of --whole-archive, but it + // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. let mut v = OsString::from("-Wl,-force_load,"); v.push(&archive::find_library(lib, search_path, &self.sess)); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 20338e4f6afb0..fe58bc8f5f28b 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -351,7 +351,7 @@ fn mangle>(path: PI, hash: &str) -> String { // Follow C++ namespace-mangling style, see // http://en.wikipedia.org/wiki/Name_mangling for more info. // - // It turns out that on OSX you can actually have arbitrary symbols in + // It turns out that on macOS you can actually have arbitrary symbols in // function names (at least when given to LLVM), but this is not possible // when using unix's linker. Perhaps one day when we just use a linker from LLVM // we won't need to do this name mangling. The problem with name mangling is diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 6933f15825620..1d4aebf135b9e 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -164,9 +164,9 @@ pub fn finalize(cx: &CrateContext) { llvm::LLVMRustDIBuilderFinalize(DIB(cx)); llvm::LLVMRustDIBuilderDispose(DIB(cx)); // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than OS X currently understands. We can + // version of dwarf than macOS currently understands. We can // instruct LLVM to emit an older version of dwarf, however, - // for OS X to understand. For more info see #11352 + // for macOS to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. // Android has the same issue (#22398) if cx.sess().target.target.options.is_like_osx || diff --git a/src/librustdoc/plugins.rs b/src/librustdoc/plugins.rs index b8be84825c9cc..a38ef2b2518ed 100644 --- a/src/librustdoc/plugins.rs +++ b/src/librustdoc/plugins.rs @@ -42,7 +42,7 @@ impl PluginManager { /// Load a plugin with the given name. /// /// Turns `name` into the proper dynamic library filename for the given - /// platform. On windows, it turns into name.dll, on OS X, name.dylib, and + /// platform. On windows, it turns into name.dll, on macOS, name.dylib, and /// elsewhere, libname.so. pub fn load_plugin(&mut self, name: String) { let x = self.prefix.join(libname(name)); diff --git a/src/libstd/os/macos/mod.rs b/src/libstd/os/macos/mod.rs index 4e995358fd876..c9406f7310039 100644 --- a/src/libstd/os/macos/mod.rs +++ b/src/libstd/os/macos/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! MacOS-specific definitions +//! macOS-specific definitions #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/src/libstd/os/macos/raw.rs b/src/libstd/os/macos/raw.rs index 8f9b29462c4f9..8ffddf638b10c 100644 --- a/src/libstd/os/macos/raw.rs +++ b/src/libstd/os/macos/raw.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! MacOS-specific raw type definitions +//! macOS-specific raw type definitions #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated(since = "1.8.0", diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index b853e83de5d6c..4f33d72639816 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -52,7 +52,7 @@ //! If an application does not have `getrandom` and likely to be run soon after first booting, //! or on a system with very few entropy sources, one should consider using `/dev/random` via //! `ReaderRng`. -//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference +//! - On some systems (e.g. FreeBSD, OpenBSD and macOS) there is no difference //! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` //! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) @@ -195,7 +195,7 @@ impl Rng for ThreadRng { /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: /// -/// - Unix-like systems (Linux, Android, Mac OSX): read directly from +/// - Unix-like systems (Linux, Android, macOS): read directly from /// `/dev/urandom`, or from `getrandom(2)` system call if available. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index 6eeae2d90ea0e..f6414673dace1 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -96,17 +96,17 @@ pub unsafe extern fn destroy_value(ptr: *mut u8) { // `None`. (*ptr).dtor_running.set(true); - // The OSX implementation of TLS apparently had an odd aspect to it + // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor // is running. Specifically if a TLS destructor re-accesses TLS it may // trigger a re-initialization of all TLS variables, paving over at // least some destroyed ones with initial values. // - // This means that if we drop a TLS value in place on OSX that we could + // This means that if we drop a TLS value in place on macOS that we could // revert the value to its original state halfway through the // destructor, which would be bad! // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) // instead of drop_in_place. if cfg!(target_os = "macos") { ptr::read((*ptr).inner.get()); diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 60dc03fcf47e2..707b4cbc6acaf 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -249,7 +249,7 @@ impl Command { // mutex, and then after the fork they unlock it. // // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but // all collected backtraces point at malloc/free traffic in the // child spawned process. // diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index 29d4012dcdf98..bf52da2ed4ac5 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -13,7 +13,7 @@ /// Some methods of getting a backtrace: /// /// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on OSX, and the address to symbol portion of it +/// well for green threads on macOS, and the address to symbol portion of it /// suffers problems that are described below. /// /// * Using libunwind. This is more difficult than it sounds because libunwind @@ -51,9 +51,9 @@ /// /// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() /// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on OSX. It appears dladdr() +/// Conveniently, this method works fantastically on macOS. It appears dladdr() /// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for OSX, this is the +/// in the dynamic symbol table anyway. Regardless, for macOS, this is the /// method used for translation. It's provided by the system and easy to do.o /// /// Sadly, all other systems have a dladdr() implementation that does not @@ -75,7 +75,7 @@ /// * Use `libbacktrace`. It turns out that this is a small library bundled in /// the gcc repository which provides backtrace and symbol translation /// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not OSX, so this is the +/// and we only really need this on everything that's not macOS, so this is the /// chosen route for now. /// /// In summary, the current situation uses libgcc_s to get a trace of stack diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 1ba4a104e515c..8a15f7ec68232 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -204,7 +204,7 @@ impl SocketAddr { let len = self.len as usize - sun_path_offset(); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - // OSX seems to return a len of 16 and a zeroed sun_path for unnamed addresses + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index f4f73646e1b7e..07d76a93dd150 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -128,7 +128,7 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { register_dtor_fallback(t, dtor); } -// OSX's analog of the above linux function is this _tlv_atexit function. +// macOS's analog of the above linux function is this _tlv_atexit function. // The disassembly of thread_local globals in C++ (at least produced by // clang) will have this show up in the output. #[cfg(target_os = "macos")] @@ -154,17 +154,17 @@ pub unsafe extern fn destroy_value(ptr: *mut u8) { // `None`. (*ptr).dtor_running.set(true); - // The OSX implementation of TLS apparently had an odd aspect to it + // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor // is running. Specifically if a TLS destructor re-accesses TLS it may // trigger a re-initialization of all TLS variables, paving over at // least some destroyed ones with initial values. // - // This means that if we drop a TLS value in place on OSX that we could + // This means that if we drop a TLS value in place on macOS that we could // revert the value to its original state halfway through the // destructor, which would be bad! // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) // instead of drop_in_place. if cfg!(target_os = "macos") { ptr::read((*ptr).inner.get()); diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index c690fd467ee41..405fac2b9d743 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -29,7 +29,7 @@ fn max_len() -> usize { // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". // - // On OSX, however, apparently the 64-bit libc is either buggy or + // On macOS, however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index d0fb96b1ff15d..e893a139094a1 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -439,7 +439,7 @@ impl File { // Linux kernel then the flag is just ignored by the OS, so we continue // to explicitly ask for a CLOEXEC fd here. // - // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc + // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc // that we support, so we only do this on Linux currently. if cfg!(target_os = "linux") { fd.set_cloexec()?; @@ -573,7 +573,7 @@ impl fmt::Debug for File { #[cfg(target_os = "macos")] fn get_path(fd: c_int) -> Option { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because OS X defines `fcntl` with + // is inevitable in this case because macOS defines `fcntl` with // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index a4536520376e8..5f1a6c2f74651 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -434,8 +434,8 @@ mod tests { } // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the OSX, so to prevent this - // test from being flaky we ignore it on OSX. + // newly spawned process may just be raced in the macOS, so to prevent this + // test from being flaky we ignore it on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl. diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index bbc987209e300..a213273aac8fd 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -129,7 +129,7 @@ impl Command { // mutex, and then after the fork they unlock it. // // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but // all collected backtraces point at malloc/free traffic in the // child spawned process. // diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 22d47ba0f620d..51adbc24ae047 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -187,7 +187,7 @@ mod imp { let stack = libc::stack_t { ss_sp: ptr::null_mut(), ss_flags: SS_DISABLE, - // Workaround for bug in MacOS implementation of sigaltstack + // Workaround for bug in macOS implementation of sigaltstack // UNIX2003 which returns ENOMEM when disabling a stack while // passing ss_size smaller than MINSIGSTKSZ. According to POSIX // both ss_sp and ss_size should be ignored in this case. diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 66f09a7069c13..e2b22b1d89f04 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -74,7 +74,7 @@ use mem; /// destroyed, but not all platforms have this guard. Those platforms that do /// not guard typically have a synthetic limit after which point no more /// destructors are run. -/// 3. On OSX, initializing TLS during destruction of other TLS slots can +/// 3. On macOS, initializing TLS during destruction of other TLS slots can /// sometimes cancel *all* destructors for the current thread, whether or not /// the slots have already had their destructors run or not. #[stable(feature = "rust1", since = "1.0.0")] @@ -524,9 +524,9 @@ mod tests { } // Note that this test will deadlock if TLS destructors aren't run (this - // requires the destructor to be run to pass the test). OSX has a known bug + // requires the destructor to be run to pass the test). macOS has a known bug // where dtors-in-dtors may cancel other destructors, so we just ignore this - // test on OSX. + // test on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] fn dtors_in_dtors_in_dtors() { diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 011d06b1c0f21..c9bde8b7b33f2 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -67,7 +67,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option { p.pop(); // on some installations the dir is named after the hex of the char - // (e.g. OS X) + // (e.g. macOS) p.push(&format!("{:x}", first_char as usize)); p.push(term); if fs::metadata(&p).is_ok() { @@ -82,7 +82,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option { #[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")] fn test_get_dbpath_for_term() { // woefully inadequate test coverage - // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's) + // note: current tests won't work with non-standard terminfo hierarchies (e.g. macOS's) use std::env; // FIXME (#9639): This needs to handle non-utf8 paths fn x(t: &str) -> String { diff --git a/src/test/compile-fail/allocator-dylib-is-system.rs b/src/test/compile-fail/allocator-dylib-is-system.rs index 4c576de22021c..31009554c690d 100644 --- a/src/test/compile-fail/allocator-dylib-is-system.rs +++ b/src/test/compile-fail/allocator-dylib-is-system.rs @@ -30,7 +30,7 @@ extern crate allocator_dylib; // that this just passes on those platforms we link in some other allocator to // ensure we get the same error. // -// So long as we CI linux/OSX we should be good. +// So long as we CI linux/macOS we should be good. #[cfg(any(target_os = "linux", target_os = "macos"))] extern crate alloc_jemalloc; #[cfg(not(any(target_os = "linux", target_os = "macos")))] diff --git a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs index 5d566c0e0b4c7..68e01bad96bb2 100644 --- a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs +++ b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs @@ -28,7 +28,7 @@ extern crate allocator_dylib2; // that this just passes on those platforms we link in some other allocator to // ensure we get the same error. // -// So long as we CI linux/OSX we should be good. +// So long as we CI linux/macOS we should be good. #[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")), target_os = "macos"))] extern crate alloc_system; diff --git a/src/test/compile-fail/manual-link-framework.rs b/src/test/compile-fail/manual-link-framework.rs index 97176a533d2bd..1ecf63813e9ab 100644 --- a/src/test/compile-fail/manual-link-framework.rs +++ b/src/test/compile-fail/manual-link-framework.rs @@ -11,7 +11,7 @@ // ignore-macos // ignore-ios // compile-flags:-l framework=foo -// error-pattern: native frameworks are only available on OSX targets +// error-pattern: native frameworks are only available on macOS targets fn main() { } diff --git a/src/test/compile-fail/osx-frameworks.rs b/src/test/compile-fail/osx-frameworks.rs index aba5fb3bc03ef..026ef3c95f663 100644 --- a/src/test/compile-fail/osx-frameworks.rs +++ b/src/test/compile-fail/osx-frameworks.rs @@ -12,7 +12,7 @@ #[link(name = "foo", kind = "framework")] extern {} -//~^^ ERROR: native frameworks are only available on OSX +//~^^ ERROR: native frameworks are only available on macOS fn main() { } diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs index d32fa01c7b945..ede2325b51c2f 100644 --- a/src/test/run-pass/simd-intrinsic-generic-cast.rs +++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs @@ -94,7 +94,7 @@ fn main() { // (E.g. negative float to unsigned integer goes through a // library routine on the default i686 platforms, and the // implementation of that routine differs on e.g. Linux - // vs. OSX, resulting in different answers.) + // vs. macOS, resulting in different answers.) if $from::is_float() { if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index e2629ffd8f54a..fcc5a727cf2d6 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X +/// darwin_fd_limit exists to work around an issue where launchctl on macOS /// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256 /// ends up being far too low for our multithreaded scheduler testing, depending /// on the number of cores available. From 38b5b29c57fc86aae5a1bc8d1319cc08907d9ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 12 Mar 2017 13:49:28 -0700 Subject: [PATCH 014/662] Change label to "consider changing this to `mut f`" Change the wording of mutable borrow on immutable binding from "this should be `mut`" to "consider changing this to `mut f`". --- src/librustc_borrowck/borrowck/mod.rs | 4 +++- src/test/ui/did_you_mean/issue-39544.stderr | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 04036d6c6b9e7..073ebe24de924 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -748,7 +748,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { db.span_label(span, &msg); } if let Some(span) = local_def { - db.span_label(span, &"this should be `mut`"); + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { + db.span_label(span, &format!("consider changing this to `mut {}`", snippet)); + } } db } diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index 1cd322efab57d..3eb3e9a4c3b0a 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable field `z.x` as mutable --> $DIR/issue-39544.rs:21:18 | 20 | let z = Z { x: X::Y }; - | - this should be `mut` + | - consider changing this to `mut z` 21 | let _ = &mut z.x; | ^^^ From b38992c63d2f92b2874619c6683b32ecdc59b333 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Mon, 13 Mar 2017 02:12:13 +0200 Subject: [PATCH 015/662] some style fixes --- src/librustc/cfg/construct.rs | 32 ++++++----- src/librustc/dep_graph/dep_tracking_map.rs | 2 +- src/librustc/dep_graph/visit.rs | 9 ++-- src/librustc/lint/context.rs | 14 +++-- src/librustc/session/code_stats.rs | 5 +- src/librustc/traits/specialize/mod.rs | 4 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/item_path.rs | 3 +- src/librustc/ty/maps.rs | 2 +- src/librustc/ty/sty.rs | 62 +++++++++++----------- src/librustc/ty/util.rs | 30 +++++------ src/librustc/util/common.rs | 7 +-- src/librustc/util/fs.rs | 2 +- 13 files changed, 91 insertions(+), 83 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 4567795184e4d..7a70eda955b69 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -52,14 +52,16 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: tables, graph: graph, fn_exit: fn_exit, - loop_scopes: Vec::new() + loop_scopes: Vec::new(), }; body_exit = cfg_builder.expr(&body.value, entry); cfg_builder.add_contained_edge(body_exit, fn_exit); - let CFGBuilder {graph, ..} = cfg_builder; - CFG {graph: graph, - entry: entry, - exit: fn_exit} + let CFGBuilder { graph, .. } = cfg_builder; + CFG { + graph: graph, + entry: entry, + exit: fn_exit, + } } impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { @@ -81,7 +83,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(id, &[exit]) } - hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => { + hir::StmtExpr(ref expr, id) | + hir::StmtSemi(ref expr, id) => { let exit = self.expr(&expr, pred); self.add_ast_node(id, &[exit]) } @@ -95,9 +98,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.pat(&local.pat, init_exit) } - hir::DeclItem(_) => { - pred - } + hir::DeclItem(_) => pred, } } @@ -107,9 +108,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { PatKind::Path(_) | PatKind::Lit(..) | PatKind::Range(..) | - PatKind::Wild => { - self.add_ast_node(pat.id, &[pred]) - } + PatKind::Wild => self.add_ast_node(pat.id, &[pred]), PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) | @@ -125,8 +124,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } PatKind::Struct(_, ref subpats, _) => { - let pats_exit = - self.pats_all(subpats.iter().map(|f| &f.node.pat), pred); + let pats_exit = self.pats_all(subpats.iter().map(|f| &f.node.pat), pred); self.add_ast_node(pat.id, &[pats_exit]) } @@ -385,7 +383,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { let method_call = ty::MethodCall::expr(call_expr.id); let fn_ty = match self.tables.method_map.get(&method_call) { Some(method) => method.ty, - None => self.tables.expr_ty_adjusted(func_or_rcvr) + None => self.tables.expr_ty_adjusted(func_or_rcvr), }; let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); @@ -556,7 +554,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { from_index: CFGIndex, to_loop: LoopScope, to_index: CFGIndex) { - let mut data = CFGEdgeData {exiting_scopes: vec![] }; + let mut data = CFGEdgeData { exiting_scopes: vec![] }; let mut scope = self.tcx.region_maps.node_extent(from_expr.id); let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id); while scope != target_scope { @@ -591,7 +589,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } span_bug!(expr.span, "no loop scope for id {}", loop_id); } - Err(err) => span_bug!(expr.span, "loop scope error: {}", err) + Err(err) => span_bug!(expr.span, "loop scope error: {}", err), } } } diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 9f45e66f0d937..0f3108df9a822 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -39,7 +39,7 @@ impl DepTrackingMap { DepTrackingMap { phantom: PhantomData, graph: graph, - map: FxHashMap() + map: FxHashMap(), } } diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index a34a3591c151d..93f6e3a83a0c2 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -29,7 +29,7 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> { tcx: TyCtxt<'visit, 'tcx, 'tcx>, dep_node_fn: &'visit mut F, - visitor: &'visit mut V + visitor: &'visit mut V, } impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V> @@ -70,13 +70,16 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> let mut tracking_visitor = TrackingVisitor { tcx: tcx, dep_node_fn: &mut dep_node_fn, - visitor: visitor + visitor: visitor, }; krate.visit_all_item_likes(&mut tracking_visitor) } pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) - where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), + where C: Fn(/* body_owner */ + DefId, + /* body id */ + hir::BodyId) { let krate = tcx.hir.krate(); for &body_id in &krate.body_ids { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9279f24a57ab3..708a74c791af7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -113,13 +113,19 @@ impl<'a, S: Into> IntoEarlyLint for (S, &'a str) { let (span, msg) = self; let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); diagnostic.set_span(span); - EarlyLint { id: id, diagnostic: diagnostic } + EarlyLint { + id: id, + diagnostic: diagnostic, + } } } impl IntoEarlyLint for Diagnostic { fn into_early_lint(self, id: LintId) -> EarlyLint { - EarlyLint { id: id, diagnostic: self } + EarlyLint { + id: id, + diagnostic: self, + } } } @@ -146,7 +152,7 @@ enum TargetLint { enum FindLintError { NotFound, - Removed + Removed, } impl LintStore { @@ -1127,7 +1133,7 @@ enum CheckLintNameResult { NoLint, // The lint is either renamed or removed. This is the warning // message. - Warning(String) + Warning(String), } /// Checks the name of a lint for its existence, and whether it was diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs index a042b2abf3a29..215539de6766e 100644 --- a/src/librustc/session/code_stats.rs +++ b/src/librustc/session/code_stats.rs @@ -25,7 +25,10 @@ pub struct VariantInfo { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum SizeKind { Exact, Min } +pub enum SizeKind { + Exact, + Min, +} #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct FieldInfo { diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 79df7de04f540..2c99ee21b0f73 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -37,7 +37,7 @@ pub mod specialization_graph; pub struct OverlapError { pub with_impl: DefId, pub trait_desc: String, - pub self_desc: Option + pub self_desc: Option, } /// Given a subst for the requested impl, translate it to a subst @@ -274,7 +274,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } pub struct SpecializesCache { - map: FxHashMap<(DefId, DefId), bool> + map: FxHashMap<(DefId, DefId), bool>, } impl SpecializesCache { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 44a3aabc0560a..5a696446b4bb6 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -23,7 +23,7 @@ use hir; #[derive(Clone, Copy, Debug)] pub struct ExpectedFound { pub expected: T, - pub found: T + pub found: T, } // Data structures used in type unification diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 448be7fe9a149..874e032bc4644 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -374,14 +374,13 @@ impl LocalPathBuffer { fn new(root_mode: RootMode) -> LocalPathBuffer { LocalPathBuffer { root_mode: root_mode, - str: String::new() + str: String::new(), } } fn into_string(self) -> String { self.str } - } impl ItemPathBuffer for LocalPathBuffer { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index fcfdda8721f52..af05c0c43113b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -85,7 +85,7 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { pub struct CycleError<'a> { span: Span, - cycle: RefMut<'a, [(Span, Query)]> + cycle: RefMut<'a, [(Span, Query)]>, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e686d62019145..0e3005847bc2c 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -45,7 +45,7 @@ pub struct TypeAndMut<'tcx> { /// at least as big as the scope `fr.scope`". pub struct FreeRegion { pub scope: region::CodeExtent, - pub bound_region: BoundRegion + pub bound_region: BoundRegion, } #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, @@ -65,7 +65,7 @@ pub enum BoundRegion { // Anonymous region for the implicit env pointer parameter // to a closure - BrEnv + BrEnv, } /// When a region changed from late-bound to early-bound when #32330 @@ -320,7 +320,7 @@ impl<'tcx> Slice> { pub fn principal(&self) -> Option> { match self.get(0) { Some(&ExistentialPredicate::Trait(tr)) => Some(tr), - _ => None + _ => None, } } @@ -520,13 +520,13 @@ impl Binder { ty::Binder(&self.0) } - pub fn map_bound_ref(&self, f: F) -> Binder + pub fn map_bound_ref(&self, f: F) -> Binder where F: FnOnce(&T) -> U { self.as_ref().map_bound(f) } - pub fn map_bound(self, f: F) -> Binder + pub fn map_bound(self, f: F) -> Binder where F: FnOnce(T) -> U { ty::Binder(f(self.0)) @@ -790,22 +790,22 @@ pub struct TyVid { #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct IntVid { - pub index: u32 + pub index: u32, } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct FloatVid { - pub index: u32 + pub index: u32, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct RegionVid { - pub index: u32 + pub index: u32, } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct SkolemizedRegionVid { - pub index: u32 + pub index: u32, } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -819,7 +819,7 @@ pub enum InferTy { /// `infer::freshen` for more details. FreshTy(u32), FreshIntTy(u32), - FreshFloatTy(u32) + FreshFloatTy(u32), } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. @@ -827,7 +827,7 @@ pub enum InferTy { pub struct ExistentialProjection<'tcx> { pub trait_ref: ExistentialTraitRef<'tcx>, pub item_name: Name, - pub ty: Ty<'tcx> + pub ty: Ty<'tcx>, } pub type PolyExistentialProjection<'tcx> = Binder>; @@ -860,9 +860,9 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), - item_name: self.item_name + item_name: self.item_name, }, - ty: self.ty + ty: self.ty, } } } @@ -899,7 +899,7 @@ impl Region { match *self { ty::ReEarlyBound(..) => true, ty::ReLateBound(..) => true, - _ => false + _ => false, } } @@ -969,7 +969,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_nil(&self) -> bool { match self.sty { TyTuple(ref tys, _) => tys.is_empty(), - _ => false + _ => false, } } @@ -1047,7 +1047,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_ty_var(&self) -> bool { match self.sty { TyInfer(TyVar(_)) => true, - _ => false + _ => false, } } @@ -1071,7 +1071,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_self(&self) -> bool { match self.sty { TyParam(ref p) => p.is_self(), - _ => false + _ => false, } } @@ -1088,7 +1088,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_structural(&self) -> bool { match self.sty { TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true, - _ => self.is_slice() | self.is_trait() + _ => self.is_slice() | self.is_trait(), } } @@ -1096,7 +1096,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_simd(&self) -> bool { match self.sty { TyAdt(def, _) => def.repr.simd, - _ => false + _ => false, } } @@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_region_ptr(&self) -> bool { match self.sty { TyRef(..) => true, - _ => false + _ => false, } } @@ -1145,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_unsafe_ptr(&self) -> bool { match self.sty { TyRawPtr(_) => return true, - _ => return false + _ => return false, } } @@ -1189,7 +1189,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_trait(&self) -> bool { match self.sty { TyDynamic(..) => true, - _ => false + _ => false, } } @@ -1205,7 +1205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyInfer(FreshTy(_)) => true, TyInfer(FreshIntTy(_)) => true, TyInfer(FreshFloatTy(_)) => true, - _ => false + _ => false, } } @@ -1219,7 +1219,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_char(&self) -> bool { match self.sty { TyChar => true, - _ => false + _ => false, } } @@ -1237,7 +1237,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_signed(&self) -> bool { match self.sty { TyInt(_) => true, - _ => false + _ => false, } } @@ -1245,7 +1245,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { match self.sty { TyInt(ast::IntTy::Is) | TyUint(ast::UintTy::Us) => false, TyInt(..) | TyUint(..) | TyFloat(..) => true, - _ => false + _ => false, } } @@ -1276,7 +1276,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { }, TyRef(_, mt) => Some(mt), TyRawPtr(mt) if explicit => Some(mt), - _ => None + _ => None, } } @@ -1284,7 +1284,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn builtin_index(&self) -> Option> { match self.sty { TyArray(ty, _) | TySlice(ty) => Some(ty), - _ => None + _ => None, } } @@ -1307,7 +1307,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_fn(&self) -> bool { match self.sty { TyFnDef(..) | TyFnPtr(_) => true, - _ => false + _ => false, } } @@ -1316,14 +1316,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()), TyAdt(def, _) => Some(def.did), TyClosure(id, _) => Some(id), - _ => None + _ => None, } } pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { match self.sty { TyAdt(adt, _) => Some(adt), - _ => None + _ => None, } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index a81c3a177f885..fd95724990941 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -16,7 +16,7 @@ use infer::InferCtxt; use hir::map as hir_map; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; -use ty::{ParameterEnvironment}; +use ty::ParameterEnvironment; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; use ty::TypeVariants::*; @@ -39,13 +39,13 @@ use hir; type Disr = ConstInt; - pub trait IntTypeExt { +pub trait IntTypeExt { fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) -> Option; fn assert_ty_matches(&self, val: Disr); fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr; - } +} macro_rules! typed_literal { @@ -133,7 +133,7 @@ impl IntTypeExt for attr::IntType { pub enum CopyImplementationError<'tcx> { InfrigingField(&'tcx ty::FieldDef), NotAnAdt, - HasDestructor + HasDestructor, } /// Describes whether a type is representable. For types that are not @@ -159,14 +159,14 @@ impl<'tcx> ParameterEnvironment<'tcx> { tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| { let (adt, substs) = match self_type.sty { ty::TyAdt(adt, substs) => (adt, substs), - _ => return Err(CopyImplementationError::NotAnAdt) + _ => return Err(CopyImplementationError::NotAnAdt), }; let field_implements_copy = |field: &ty::FieldDef| { let cause = traits::ObligationCause::dummy(); match traits::fully_normalize(&infcx, cause, &field.ty(tcx, substs)) { Ok(ty) => !infcx.type_moves_by_default(ty, span), - Err(..) => false + Err(..) => false, } }; @@ -198,7 +198,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } - _ => () + _ => (), } false } @@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { adt.variants[0].fields.get(i).map(|f| f.ty(self, substs)) } (&TyTuple(ref v, _), None) => v.get(i).cloned(), - _ => None + _ => None, } } @@ -245,11 +245,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { while let TyAdt(def, substs) = ty.sty { if !def.is_struct() { - break + break; } match def.struct_variant().fields.last() { Some(f) => ty = f.ty(self, substs), - None => break + None => break, } } ty @@ -267,14 +267,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let (mut a, mut b) = (source, target); while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) { if a_def != b_def || !a_def.is_struct() { - break + break; } match a_def.struct_variant().fields.last() { Some(f) => { a = f.ty(self, a_substs); b = f.ty(self, b_substs); } - _ => break + _ => break, } } (a, b) @@ -373,7 +373,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let dtor_did = match dtor_did { Some(dtor) => dtor, - None => return None + None => return None, }; // RFC 1238: if the destructor method is tagged with the @@ -725,9 +725,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type(a, b)) } - _ => { - a == b - } + _ => a == b, } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 4ddccbfd4c597..7b5e2253109aa 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -94,7 +94,7 @@ pub fn to_readable_str(mut val: usize) -> String { if val == 0 { groups.push(format!("{}", group)); - break + break; } else { groups.push(format!("{:03}", group)); } @@ -142,7 +142,8 @@ fn get_resident() -> Option { type HANDLE = *mut u8; use libc::size_t; use std::mem; - #[repr(C)] #[allow(non_snake_case)] + #[repr(C)] + #[allow(non_snake_case)] struct PROCESS_MEMORY_COUNTERS { cb: DWORD, PageFaultCount: DWORD, @@ -184,7 +185,7 @@ pub fn indent(op: F) -> R where } pub struct Indenter { - _cannot_construct_outside_of_this_module: () + _cannot_construct_outside_of_this_module: (), } impl Drop for Indenter { diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index 3b4b3998c5745..da6a202e5afb2 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -116,7 +116,7 @@ pub fn create_dir_racy(path: &Path) -> io::Result<()> { match fs::create_dir(path) { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(ref e) if e.kind() == io::ErrorKind::NotFound => (), Err(e) => return Err(e), } match path.parent() { From 064477391c086d4ea26d880bc0f5e1a5c4cb1383 Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 13 Mar 2017 00:14:42 -0400 Subject: [PATCH 016/662] Remove doc about highlighting code in other languages #40301 --- src/doc/book/src/documentation.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/doc/book/src/documentation.md b/src/doc/book/src/documentation.md index 69d49e2f96aa8..551c393be775e 100644 --- a/src/doc/book/src/documentation.md +++ b/src/doc/book/src/documentation.md @@ -183,24 +183,6 @@ To write some Rust code in a comment, use the triple graves: # fn foo() {} ``` -If you want something that's not Rust code, you can add an annotation: - -```rust -/// ```c -/// printf("Hello, world\n"); -/// ``` -# fn foo() {} -``` - -This will highlight according to whatever language you're showing off. -If you're only 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 in a -library crate, 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: From 6b7b26228894a88bae0d1168777cc227cf7281da Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 13 Mar 2017 01:01:32 -0400 Subject: [PATCH 017/662] Updating README.md to point to the correct doc location --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79f11144a073d..dc9362ca2f0b8 100644 --- a/README.md +++ b/README.md @@ -161,8 +161,9 @@ If you’d like to build the documentation, it’s almost the same: $ ./x.py doc ``` -The generated documentation will appear in a top-level `doc` directory, -created by the `make` rule. +The generated documentation will appear under `doc` in the `build` directory for +the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will be +`build\x86_64-pc-windows-msvc\doc`. ## Notes From f27bd73fd2716899ae35865978c9ad5a88daa708 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Mar 2017 12:47:37 -0700 Subject: [PATCH 018/662] appveyor: Turn down sccache logging Let's not have it be quite so verbose --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 744ef2b2b24e4..94a5efb3a2ffb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -131,7 +131,7 @@ install: - handle.exe -accepteula -help # Attempt to debug sccache failures - - set RUST_LOG=sccache + - set RUST_LOG=sccache=debug - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: From eb203d597f6bed9bb6a7103649a36f19a087a2ab Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 13 Mar 2017 18:37:21 -0400 Subject: [PATCH 019/662] Adjust wording #40301 --- src/doc/book/src/documentation.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/book/src/documentation.md b/src/doc/book/src/documentation.md index 551c393be775e..176a7e508c0ac 100644 --- a/src/doc/book/src/documentation.md +++ b/src/doc/book/src/documentation.md @@ -170,8 +170,6 @@ more than one section: # 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: @@ -183,6 +181,9 @@ To write some Rust code in a comment, use the triple graves: # fn foo() {} ``` +This will add code highlighting. If you are only showing plain text, put `text` +instead of `rust` after the triple graves (see below). + ## Documentation as tests Let's discuss our sample example documentation: From adba642a388cf14b6ffa9dd917443957c94e82fb Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 13 Mar 2017 23:56:27 +0100 Subject: [PATCH 020/662] fix format grammar --- src/libcollections/fmt.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index dfd292176d2f9..1ec1749c3aa64 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -306,7 +306,8 @@ //! `%`. The actual grammar for the formatting syntax is: //! //! ```text -//! format_string := [ format ] * +//! format_string := [ maybe-format ] * +//! maybe-format := '{' '{' | '}' '}' | //! format := '{' [ argument ] [ ':' format_spec ] '}' //! argument := integer | identifier //! From 5e49f79b068517ae238c7454f93cba6df31e47c0 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 10 Mar 2017 16:06:07 -0600 Subject: [PATCH 021/662] Add test for issue #29595 --- src/test/ui/span/issue-29595.rs | 19 +++++++++++++++++++ src/test/ui/span/issue-29595.stderr | 10 ++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/ui/span/issue-29595.rs create mode 100644 src/test/ui/span/issue-29595.stderr diff --git a/src/test/ui/span/issue-29595.rs b/src/test/ui/span/issue-29595.rs new file mode 100644 index 0000000000000..79704619ccd37 --- /dev/null +++ b/src/test/ui/span/issue-29595.rs @@ -0,0 +1,19 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] + +trait Tr { + const C: Self; +} + +fn main() { + let a: u8 = Tr::C; //~ ERROR the trait bound `u8: Tr` is not satisfied +} diff --git a/src/test/ui/span/issue-29595.stderr b/src/test/ui/span/issue-29595.stderr new file mode 100644 index 0000000000000..abbac245f89f6 --- /dev/null +++ b/src/test/ui/span/issue-29595.stderr @@ -0,0 +1,10 @@ +error[E0277]: the trait bound `u8: Tr` is not satisfied + --> $DIR/issue-29595.rs:18:17 + | +18 | let a: u8 = Tr::C; //~ ERROR the trait bound `u8: Tr` is not satisfied + | ^^^^^ the trait `Tr` is not implemented for `u8` + | + = note: required by `Tr::C` + +error: aborting due to previous error + From 11d3344562e8197cce5441d36bec636f917be5f2 Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 13 Mar 2017 19:13:26 -0400 Subject: [PATCH 022/662] Using X headings #39850 --- src/doc/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/index.md b/src/doc/index.md index 1f262b360e3ed..1294c1a8c59e7 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -11,18 +11,18 @@ Other unofficial documentation may exist elsewhere; for example, the [Rust Learning] project collects documentation from the community, and [Docs.rs] builds documentation for individual Rust packages. -## API Documentation +# API Documentation Rust provides a standard library with a number of features; [we host its documentation here][api]. -## Extended Error Documentation +# Extended Error Documentation Many of Rust's errors come with error codes, and you can request extended diagnostics from the compiler on those errors. We also [have the text of those extended errors on the web][err], if you prefer to read them that way. -## The Rust Bookshelf +# The Rust Bookshelf Rust provides a number of book-length sets of documentation, collectively nicknamed 'The Rust Bookshelf.' From 8b9b3b6d8b1b683dbc4bd2c2d5000cb87eb8b1a2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 13 Mar 2017 20:36:41 -0400 Subject: [PATCH 023/662] Fix sidebar not extending to the bottom of the page Fixes #40459 --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 4047f6045bcc5..3df120eece9c5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -167,7 +167,7 @@ nav.sub { position: absolute; left: 0; top: 0; - min-height: 100vh; + min-height: 100%; } .sidebar .current { From 5b7f330588a09593bd48eef9be610338fb1dc199 Mon Sep 17 00:00:00 2001 From: Eric Findlay Date: Tue, 14 Mar 2017 10:21:26 +0900 Subject: [PATCH 024/662] Corrected very minor documentation detail about Unicode and Japanese --- src/libstd_unicode/char.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 4269ce8534bd0..f5dfd9fa471f1 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -829,7 +829,7 @@ impl char { /// // Sometimes the result is more than one character: /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); /// - /// // Japanese scripts do not have case, and so: + /// // Japanese kanji characters do not have case, and so: /// assert_eq!('山'.to_lowercase().to_string(), "山"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -889,7 +889,7 @@ impl char { /// // Sometimes the result is more than one character: /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); /// - /// // Japanese does not have case, and so: + /// // Japanese kanji characters do not have case, and so: /// assert_eq!('山'.to_uppercase().to_string(), "山"); /// ``` /// From e06c51553ddc202a79f2c0b76822ad56c4a30f80 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 11 Mar 2017 17:10:05 -0500 Subject: [PATCH 025/662] Rust unstable book: basic desc and example for `const_fn`. --- cargo | 2 +- src/doc/unstable-book/src/const-fn.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cargo b/cargo index 4a3c0a63b07e9..5f3b9c4c6a7be 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4a3c0a63b07e9a4feb41cb11de37c92a09db5a60 +Subproject commit 5f3b9c4c6a7be1f177d6024cb83d150b6479148a diff --git a/src/doc/unstable-book/src/const-fn.md b/src/doc/unstable-book/src/const-fn.md index 9b7942c408a24..d5a2243683862 100644 --- a/src/doc/unstable-book/src/const-fn.md +++ b/src/doc/unstable-book/src/const-fn.md @@ -6,5 +6,24 @@ The tracking issue for this feature is: [#24111] ------------------------ +The `const_fn` feature allows marking free functions and inherent methods as +`const`, enabling them to be called in constants contexts, with constant +arguments. +## Examples +```rust +#![feature(const_fn)] + +const fn double(x: i32) -> i32 { + x * 2 +} + +const FIVE: i32 = 5; +const TEN: i32 = double(FIVE); + +fn main() { + assert_eq!(5, FIVE); + assert_eq!(10, TEN); +} +``` From 327e8e9196b638c4ed35ab2d57d550a3138a628b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 11 Mar 2017 17:34:41 -0500 Subject: [PATCH 026/662] Rust unstable book: basic desc and example for `conservative_impl_trait`. --- .../src/conservative-impl-trait.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/doc/unstable-book/src/conservative-impl-trait.md b/src/doc/unstable-book/src/conservative-impl-trait.md index 7d8bda439bd34..62a7f8c16a0a7 100644 --- a/src/doc/unstable-book/src/conservative-impl-trait.md +++ b/src/doc/unstable-book/src/conservative-impl-trait.md @@ -6,5 +6,61 @@ The tracking issue for this feature is: [#34511] ------------------------ +The `conservative_impl_trait` feature allows a conservative form of abstract +return types. +Abstract return types allow a function to hide a concrete return type behind a +trait interface similar to trait objects, while still generating the same +statically dispatched code as with concrete types. +## Examples + +```rust +#![feature(conservative_impl_trait)] + +fn even_iter() -> impl Iterator { + (0..).map(|n| n * 2) +} + +fn main() { + let first_four_even_numbers = even_iter().take(4).collect::>(); + assert_eq!(first_four_even_numbers, vec![0, 2, 4, 6]); +} +``` + +## Background + +In today's Rust, you can write function signatures like: + +````rust,ignore +fn consume_iter_static>(iter: I) { } + +fn consume_iter_dynamic(iter: Box>) { } +```` + +In both cases, the function does not depend on the exact type of the argument. +The type held is "abstract", and is assumed only to satisfy a trait bound. + +* In the `_static` version using generics, each use of the function is + specialized to a concrete, statically-known type, giving static dispatch, + inline layout, and other performance wins. +* In the `_dynamic` version using trait objects, the concrete argument type is + only known at runtime using a vtable. + +On the other hand, while you can write: + +````rust,ignore +fn produce_iter_dynamic() -> Box> { } +```` + +...but you _cannot_ write something like: + +````rust,ignore +fn produce_iter_static() -> Iterator { } +```` + +That is, in today's Rust, abstract return types can only be written using trait +objects, which can be a significant performance penalty. This RFC proposes +"unboxed abstract types" as a way of achieving signatures like +`produce_iter_static`. Like generics, unboxed abstract types guarantee static +dispatch and inline data layout. From 0dd03ffaf72d317d7fed27562fa2c76061cd3aff Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 11 Mar 2017 20:50:18 -0500 Subject: [PATCH 027/662] Rust unstable book: basic desc and example for `const_indexing`. --- src/doc/unstable-book/src/const-indexing.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/doc/unstable-book/src/const-indexing.md b/src/doc/unstable-book/src/const-indexing.md index bd92b0b1b478f..42d46ce15f676 100644 --- a/src/doc/unstable-book/src/const-indexing.md +++ b/src/doc/unstable-book/src/const-indexing.md @@ -6,5 +6,14 @@ The tracking issue for this feature is: [#29947] ------------------------ +The `const_indexing` feature allows the constant evaluation of index operations +on constant arrays and repeat expressions. +## Examples +```rust +#![feature(const_indexing)] + +const ARR: [usize; 5] = [1, 2, 3, 4, 5]; +const ARR2: [usize; ARR[1]] = [42, 99]; +``` \ No newline at end of file From 137c1e8121b0fcaa3a1a1c7e2294e1152a932f46 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 11 Mar 2017 21:07:58 -0500 Subject: [PATCH 028/662] Rust unstable book: basic desc and example for `i128_type`. --- src/doc/unstable-book/src/i128-type.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/doc/unstable-book/src/i128-type.md b/src/doc/unstable-book/src/i128-type.md index ffcf45feb2ad7..a850b7644c3a7 100644 --- a/src/doc/unstable-book/src/i128-type.md +++ b/src/doc/unstable-book/src/i128-type.md @@ -6,5 +6,20 @@ The tracking issue for this feature is: [#35118] ------------------------ +The `i128_type` feature adds support for 128 bit signed and unsigned integer +types. +```rust +#![feature(i128_type)] + +fn main() { + assert_eq!(1u128 + 1u128, 2u128); + assert_eq!(u128::min_value(), 0); + assert_eq!(u128::max_value(), 340282366920938463463374607431768211455); + + assert_eq!(1i128 - 2i128, -1i128); + assert_eq!(i128::min_value(), -170141183460469231731687303715884105728); + assert_eq!(i128::max_value(), 170141183460469231731687303715884105727); +} +``` From e58e3d0bc0495a5103527d4c0317f089684ac0f1 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 01:05:55 -0500 Subject: [PATCH 029/662] Rust unstable book: basic desc and example for `non_ascii_idents`. --- src/doc/unstable-book/src/non-ascii-idents.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/unstable-book/src/non-ascii-idents.md b/src/doc/unstable-book/src/non-ascii-idents.md index f426022ab3a51..d5600c58fd9a6 100644 --- a/src/doc/unstable-book/src/non-ascii-idents.md +++ b/src/doc/unstable-book/src/non-ascii-idents.md @@ -6,5 +6,13 @@ The tracking issue for this feature is: [#28979] ------------------------ +The `non_ascii_idents` feature adds support for non-ASCII identifiers. +## Examples +```rust +#![feature(non_ascii_idents)] + +const ε: f64 = 0.00001f64; +const Π: f64 = 3.14f64; +``` \ No newline at end of file From d3ae2eb58ea2f96aa52b53d9171111b176b611eb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 01:12:29 -0500 Subject: [PATCH 030/662] Rust unstable book: basic desc and example for `concat_idents`. --- src/doc/unstable-book/src/concat-idents.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/doc/unstable-book/src/concat-idents.md b/src/doc/unstable-book/src/concat-idents.md index c9a48293dba68..ecfd34a22e5cc 100644 --- a/src/doc/unstable-book/src/concat-idents.md +++ b/src/doc/unstable-book/src/concat-idents.md @@ -6,5 +6,17 @@ The tracking issue for this feature is: [#29599] ------------------------ +The `concat_idents` feature adds a macro for concatenating multiple identifiers +into one identifier. +## Examples +```rust +#![feature(concat_idents)] + +fn main() { + fn foobar() -> u32 { 23 } + let f = concat_idents!(foo, bar); + assert_eq!(f(), 23); +} +``` \ No newline at end of file From 1545f4e2a323eb869b13f36bd05cc91ff21d5161 Mon Sep 17 00:00:00 2001 From: Sean Gillespie Date: Mon, 13 Mar 2017 18:42:23 -0700 Subject: [PATCH 031/662] std: remove a workaround for privacy limitations that isn't necessary anymore --- src/libstd/rt.rs | 4 ++-- src/libstd/sys_common/thread_info.rs | 7 +------ src/libstd/thread/mod.rs | 7 +------ 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 78d5aa597ba0d..6c791cd336ded 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -34,7 +34,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { use panic; use sys; use sys_common; - use sys_common::thread_info::{self, NewThread}; + use sys_common::thread_info; use thread::Thread; sys::init(); @@ -47,7 +47,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // created. Note that this isn't necessary in general for new threads, // but we just do this to name the main thread and to give it correct // info about the stack bounds. - let thread: Thread = NewThread::new(Some("main".to_owned())); + let thread = Thread::new(Some("main".to_owned())); thread_info::set(main_guard, thread); // Store our args if necessary in a squirreled away location diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 95d8b6cc9516d..5ed48ee455871 100644 --- a/src/libstd/sys_common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs @@ -31,7 +31,7 @@ impl ThreadInfo { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { stack_guard: None, - thread: NewThread::new(None), + thread: Thread::new(None), }) } Some(f(c.borrow_mut().as_mut().unwrap())) @@ -54,8 +54,3 @@ pub fn set(stack_guard: Option, thread: Thread) { thread: thread, })); } - -// a hack to get around privacy restrictions; implemented by `std::thread` -pub trait NewThread { - fn new(name: Option) -> Self; -} diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 2bc066d3fea55..fa4cc276ee5df 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -745,7 +745,7 @@ pub struct Thread { impl Thread { // Used only internally to construct a thread object without spawning - fn new(name: Option) -> Thread { + pub(crate) fn new(name: Option) -> Thread { let cname = name.map(|n| { CString::new(n).expect("thread name may not contain interior null bytes") }); @@ -858,11 +858,6 @@ impl fmt::Debug for Thread { } } -// a hack to get around privacy restrictions -impl thread_info::NewThread for Thread { - fn new(name: Option) -> Thread { Thread::new(name) } -} - //////////////////////////////////////////////////////////////////////////////// // JoinHandle //////////////////////////////////////////////////////////////////////////////// From e7b0f2badf7c3393f1b36339b121054d05353442 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 14:04:52 -0400 Subject: [PATCH 032/662] Remove function invokation parens from documentation links. This was never established as a convention we should follow in the 'More API Documentation Conventions' RFC: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md --- src/doc/book/src/ffi.md | 8 +- src/doc/book/src/guessing-game.md | 2 +- src/liballoc/rc.rs | 4 +- src/libcollections/binary_heap.rs | 4 +- src/libcollections/slice.rs | 22 +++--- src/libcollections/str.rs | 68 ++++++++--------- src/libcollections/string.rs | 94 +++++++++++------------ src/libcollections/vec.rs | 42 +++++------ src/libcore/char.rs | 20 ++--- src/libcore/clone.rs | 4 +- src/libcore/convert.rs | 8 +- src/libcore/hash/mod.rs | 4 +- src/libcore/iter/iterator.rs | 64 ++++++++-------- src/libcore/iter/mod.rs | 120 +++++++++++++++--------------- src/libcore/iter/sources.rs | 22 +++--- src/libcore/iter/traits.rs | 50 ++++++------- src/libcore/macros.rs | 4 +- src/libcore/marker.rs | 4 +- src/libcore/mem.rs | 2 +- src/libcore/num/mod.rs | 10 +-- src/libcore/ops.rs | 14 ++-- src/libcore/str/mod.rs | 70 ++++++++--------- src/libstd/fs.rs | 8 +- src/libstd/io/error.rs | 4 +- src/libstd/io/mod.rs | 92 +++++++++++------------ src/libstd/io/stdio.rs | 4 +- src/libstd/io/util.rs | 6 +- src/libstd/lib.rs | 4 +- src/libstd/net/tcp.rs | 18 ++--- src/libstd/net/udp.rs | 20 ++--- src/libstd/panicking.rs | 8 +- src/libstd/path.rs | 32 ++++---- src/libstd/prelude/mod.rs | 8 +- src/libstd/primitive_docs.rs | 6 +- src/libstd/sync/barrier.rs | 4 +- src/libstd/sync/condvar.rs | 18 ++--- src/libstd/sync/mpsc/mod.rs | 12 +-- src/libstd/sync/mutex.rs | 6 +- src/libstd/sync/rwlock.rs | 12 +-- src/libstd/sys/unix/ext/net.rs | 34 ++++----- src/libstd/thread/mod.rs | 32 ++++---- src/libstd_unicode/char.rs | 14 ++-- 42 files changed, 491 insertions(+), 491 deletions(-) diff --git a/src/doc/book/src/ffi.md b/src/doc/book/src/ffi.md index e9e2dab73eff3..3dd9aa3885bc0 100644 --- a/src/doc/book/src/ffi.md +++ b/src/doc/book/src/ffi.md @@ -687,7 +687,7 @@ attribute turns off Rust's name mangling, so that it is easier to link to. It’s important to be mindful of `panic!`s when working with FFI. A `panic!` across an FFI boundary is undefined behavior. If you’re writing code that may -panic, you should run it in a closure with [`catch_unwind()`]: +panic, you should run it in a closure with [`catch_unwind`]: ```rust use std::panic::catch_unwind; @@ -706,11 +706,11 @@ pub extern fn oh_no() -> i32 { fn main() {} ``` -Please note that [`catch_unwind()`] will only catch unwinding panics, not -those who abort the process. See the documentation of [`catch_unwind()`] +Please note that [`catch_unwind`] will only catch unwinding panics, not +those who abort the process. See the documentation of [`catch_unwind`] for more information. -[`catch_unwind()`]: ../std/panic/fn.catch_unwind.html +[`catch_unwind`]: ../std/panic/fn.catch_unwind.html # Representing opaque structs diff --git a/src/doc/book/src/guessing-game.md b/src/doc/book/src/guessing-game.md index 4d81438b11dea..bbb43b4a9ef4b 100644 --- a/src/doc/book/src/guessing-game.md +++ b/src/doc/book/src/guessing-game.md @@ -217,7 +217,7 @@ The next part will use this handle to get input from the user: .read_line(&mut guess) ``` -Here, we call the [`read_line()`][read_line] method on our handle. +Here, we call the [`read_line`][read_line] method on our handle. [Methods][method] are like associated functions, but are only available on a particular instance of a type, rather than the type itself. We’re also passing one argument to `read_line()`: `&mut guess`. diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 6108a06634bb8..eb449b2660679 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -13,7 +13,7 @@ //! Single-threaded reference-counting pointers. //! //! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, -//! allocated in the heap. Invoking [`clone()`][clone] on [`Rc`] produces a new +//! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new //! pointer to the same value in the heap. When the last [`Rc`] pointer to a //! given value is destroyed, the pointed-to value is also destroyed. //! @@ -30,7 +30,7 @@ //! threads. If you need multi-threaded, atomic reference counting, use //! [`sync::Arc`][arc]. //! -//! The [`downgrade()`][downgrade] method can be used to create a non-owning +//! The [`downgrade`][downgrade] method can be used to create a non-owning //! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d //! to an [`Rc`], but this will return [`None`] if the value has //! already been dropped. diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index a5a2f70492dc9..519117ff9e519 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -218,10 +218,10 @@ pub struct BinaryHeap { data: Vec, } -/// A container object that represents the result of the [`peek_mut()`] method +/// A container object that represents the result of the [`peek_mut`] method /// on `BinaryHeap`. See its documentation for details. /// -/// [`peek_mut()`]: struct.BinaryHeap.html#method.peek_mut +/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap, diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 2ea953df87357..11fc1d553f28e 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -73,10 +73,10 @@ //! the element type of the slice is `i32`, the element type of the iterator is //! `&mut i32`. //! -//! * [`.iter()`] and [`.iter_mut()`] are the explicit methods to return the default +//! * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default //! iterators. -//! * Further methods that return iterators are [`.split()`], [`.splitn()`], -//! [`.chunks()`], [`.windows()`] and more. +//! * Further methods that return iterators are [`.split`], [`.splitn`], +//! [`.chunks`], [`.windows`] and more. //! //! *[See also the slice primitive type](../../std/primitive.slice.html).* //! @@ -85,12 +85,12 @@ //! [`Ord`]: ../../std/cmp/trait.Ord.html //! [`Iter`]: struct.Iter.html //! [`Hash`]: ../../std/hash/trait.Hash.html -//! [`.iter()`]: ../../std/primitive.slice.html#method.iter -//! [`.iter_mut()`]: ../../std/primitive.slice.html#method.iter_mut -//! [`.split()`]: ../../std/primitive.slice.html#method.split -//! [`.splitn()`]: ../../std/primitive.slice.html#method.splitn -//! [`.chunks()`]: ../../std/primitive.slice.html#method.chunks -//! [`.windows()`]: ../../std/primitive.slice.html#method.windows +//! [`.iter`]: ../../std/primitive.slice.html#method.iter +//! [`.iter_mut`]: ../../std/primitive.slice.html#method.iter_mut +//! [`.split`]: ../../std/primitive.slice.html#method.split +//! [`.splitn`]: ../../std/primitive.slice.html#method.splitn +//! [`.chunks`]: ../../std/primitive.slice.html#method.chunks +//! [`.windows`]: ../../std/primitive.slice.html#method.windows #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -368,9 +368,9 @@ impl [T] { } /// Returns a mutable reference to an element or subslice depending on the - /// type of index (see [`get()`]) or `None` if the index is out of bounds. + /// type of index (see [`get`]) or `None` if the index is out of bounds. /// - /// [`get()`]: #method.get + /// [`get`]: #method.get /// /// # Examples /// diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index e27c45773441a..90e54a383d623 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -298,9 +298,9 @@ impl str { /// excluding `end`. /// /// To get a mutable string slice instead, see the - /// [`slice_mut_unchecked()`] method. + /// [`slice_mut_unchecked`] method. /// - /// [`slice_mut_unchecked()`]: #method.slice_mut_unchecked + /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked /// /// # Safety /// @@ -341,9 +341,9 @@ impl str { /// excluding `end`. /// /// To get an immutable string slice instead, see the - /// [`slice_unchecked()`] method. + /// [`slice_unchecked`] method. /// - /// [`slice_unchecked()`]: #method.slice_unchecked + /// [`slice_unchecked`]: #method.slice_unchecked /// /// # Safety /// @@ -367,10 +367,10 @@ impl str { /// The two slices returned go from the start of the string slice to `mid`, /// and from `mid` to the end of the string slice. /// - /// To get mutable string slices instead, see the [`split_at_mut()`] + /// To get mutable string slices instead, see the [`split_at_mut`] /// method. /// - /// [`split_at_mut()`]: #method.split_at_mut + /// [`split_at_mut`]: #method.split_at_mut /// /// # Panics /// @@ -403,9 +403,9 @@ impl str { /// The two slices returned go from the start of the string slice to `mid`, /// and from `mid` to the end of the string slice. /// - /// To get immutable string slices instead, see the [`split_at()`] method. + /// To get immutable string slices instead, see the [`split_at`] method. /// - /// [`split_at()`]: #method.split_at + /// [`split_at`]: #method.split_at /// /// # Panics /// @@ -824,10 +824,10 @@ impl str { /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit()`] method can be used. + /// from a forward search, the [`rsplit`] method can be used. /// /// [`char`]: primitive.char.html - /// [`rsplit()`]: #method.rsplit + /// [`rsplit`]: #method.rsplit /// /// # Examples /// @@ -912,9 +912,9 @@ impl str { /// assert_eq!(d, &["a", "b", "c"]); /// ``` /// - /// Use [`split_whitespace()`] for this behavior. + /// Use [`split_whitespace`] for this behavior. /// - /// [`split_whitespace()`]: #method.split_whitespace + /// [`split_whitespace`]: #method.split_whitespace #[stable(feature = "rust1", since = "1.0.0")] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { core_str::StrExt::split(self, pat) @@ -936,9 +936,9 @@ impl str { /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// - /// For iterating from the front, the [`split()`] method can be used. + /// For iterating from the front, the [`split`] method can be used. /// - /// [`split()`]: #method.split + /// [`split`]: #method.split /// /// # Examples /// @@ -977,10 +977,10 @@ impl str { /// The pattern can be a `&str`, [`char`], or a closure that determines the /// split. /// - /// Equivalent to [`split()`], except that the trailing substring + /// Equivalent to [`split`], except that the trailing substring /// is skipped if empty. /// - /// [`split()`]: #method.split + /// [`split`]: #method.split /// /// This method can be used for string data that is _terminated_, /// rather than _separated_ by a pattern. @@ -995,9 +995,9 @@ impl str { /// [`char`]: primitive.char.html /// /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit_terminator()`] method can be used. + /// from a forward search, the [`rsplit_terminator`] method can be used. /// - /// [`rsplit_terminator()`]: #method.rsplit_terminator + /// [`rsplit_terminator`]: #method.rsplit_terminator /// /// # Examples /// @@ -1025,10 +1025,10 @@ impl str { /// /// [`char`]: primitive.char.html /// - /// Equivalent to [`split()`], except that the trailing substring is + /// Equivalent to [`split`], except that the trailing substring is /// skipped if empty. /// - /// [`split()`]: #method.split + /// [`split`]: #method.split /// /// This method can be used for string data that is _terminated_, /// rather than _separated_ by a pattern. @@ -1039,10 +1039,10 @@ impl str { /// reverse search, and it will be double ended if a forward/reverse /// search yields the same elements. /// - /// For iterating from the front, the [`split_terminator()`] method can be + /// For iterating from the front, the [`split_terminator`] method can be /// used. /// - /// [`split_terminator()`]: #method.split_terminator + /// [`split_terminator`]: #method.split_terminator /// /// # Examples /// @@ -1076,10 +1076,10 @@ impl str { /// The returned iterator will not be double ended, because it is /// not efficient to support. /// - /// If the pattern allows a reverse search, the [`rsplitn()`] method can be + /// If the pattern allows a reverse search, the [`rsplitn`] method can be /// used. /// - /// [`rsplitn()`]: #method.rsplitn + /// [`rsplitn`]: #method.rsplitn /// /// # Examples /// @@ -1127,9 +1127,9 @@ impl str { /// The returned iterator will not be double ended, because it is not /// efficient to support. /// - /// For splitting from the front, the [`splitn()`] method can be used. + /// For splitting from the front, the [`splitn`] method can be used. /// - /// [`splitn()`]: #method.splitn + /// [`splitn`]: #method.splitn /// /// # Examples /// @@ -1177,9 +1177,9 @@ impl str { /// [`char`]: primitive.char.html /// /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatches()`] method can be used. + /// from a forward search, the [`rmatches`] method can be used. /// - /// [`rmatches()`]: #method.rmatches + /// [`rmatches`]: #method.rmatches /// /// # Examples /// @@ -1213,9 +1213,9 @@ impl str { /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// - /// For iterating from the front, the [`matches()`] method can be used. + /// For iterating from the front, the [`matches`] method can be used. /// - /// [`matches()`]: #method.matches + /// [`matches`]: #method.matches /// /// # Examples /// @@ -1255,9 +1255,9 @@ impl str { /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatch_indices()`] method can be used. + /// from a forward search, the [`rmatch_indices`] method can be used. /// - /// [`rmatch_indices()`]: #method.rmatch_indices + /// [`rmatch_indices`]: #method.rmatch_indices /// /// # Examples /// @@ -1297,9 +1297,9 @@ impl str { /// /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html /// - /// For iterating from the front, the [`match_indices()`] method can be used. + /// For iterating from the front, the [`match_indices`] method can be used. /// - /// [`match_indices()`]: #method.match_indices + /// [`match_indices`]: #method.match_indices /// /// # Examples /// diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 43323676ab459..e8e3a25a8f45c 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -89,8 +89,8 @@ use boxed::Box; /// let hello = String::from("Hello, world!"); /// ``` /// -/// You can append a [`char`] to a `String` with the [`push()`] method, and -/// append a [`&str`] with the [`push_str()`] method: +/// You can append a [`char`] to a `String` with the [`push`] method, and +/// append a [`&str`] with the [`push_str`] method: /// /// ``` /// let mut hello = String::from("Hello, "); @@ -100,11 +100,11 @@ use boxed::Box; /// ``` /// /// [`char`]: ../../std/primitive.char.html -/// [`push()`]: #method.push -/// [`push_str()`]: #method.push_str +/// [`push`]: #method.push +/// [`push_str`]: #method.push_str /// /// If you have a vector of UTF-8 bytes, you can create a `String` from it with -/// the [`from_utf8()`] method: +/// the [`from_utf8`] method: /// /// ``` /// // some bytes, in a vector @@ -116,7 +116,7 @@ use boxed::Box; /// assert_eq!("💖", sparkle_heart); /// ``` /// -/// [`from_utf8()`]: #method.from_utf8 +/// [`from_utf8`]: #method.from_utf8 /// /// # UTF-8 /// @@ -136,11 +136,11 @@ use boxed::Box; /// Indexing is intended to be a constant-time operation, but UTF-8 encoding /// does not allow us to do this. Furthermore, it's not clear what sort of /// thing the index should return: a byte, a codepoint, or a grapheme cluster. -/// The [`bytes()`] and [`chars()`] methods return iterators over the first +/// The [`bytes`] and [`chars`] methods return iterators over the first /// two, respectively. /// -/// [`bytes()`]: #method.bytes -/// [`chars()`]: #method.chars +/// [`bytes`]: #method.bytes +/// [`chars`]: #method.chars /// /// # Deref /// @@ -174,7 +174,7 @@ use boxed::Box; /// /// This buffer is always stored on the heap. /// -/// You can look at these with the [`as_ptr()`], [`len()`], and [`capacity()`] +/// You can look at these with the [`as_ptr`], [`len`], and [`capacity`] /// methods: /// /// ``` @@ -200,9 +200,9 @@ use boxed::Box; /// assert_eq!(String::from("Once upon a time..."), s); /// ``` /// -/// [`as_ptr()`]: #method.as_ptr -/// [`len()`]: #method.len -/// [`capacity()`]: #method.capacity +/// [`as_ptr`]: #method.as_ptr +/// [`len`]: #method.len +/// [`capacity`]: #method.capacity /// /// If a `String` has enough capacity, adding elements to it will not /// re-allocate. For example, consider this program: @@ -231,7 +231,7 @@ use boxed::Box; /// /// At first, we have no memory allocated at all, but as we append to the /// string, it increases its capacity appropriately. If we instead use the -/// [`with_capacity()`] method to allocate the correct capacity initially: +/// [`with_capacity`] method to allocate the correct capacity initially: /// /// ``` /// let mut s = String::with_capacity(25); @@ -244,7 +244,7 @@ use boxed::Box; /// } /// ``` /// -/// [`with_capacity()`]: #method.with_capacity +/// [`with_capacity`]: #method.with_capacity /// /// We end up with a different output: /// @@ -266,25 +266,25 @@ pub struct String { /// A possible error value when converting a `String` from a UTF-8 byte vector. /// -/// This type is the error type for the [`from_utf8()`] method on [`String`]. It +/// This type is the error type for the [`from_utf8`] method on [`String`]. It /// is designed in such a way to carefully avoid reallocations: the -/// [`into_bytes()`] method will give back the byte vector that was used in the +/// [`into_bytes`] method will give back the byte vector that was used in the /// conversion attempt. /// -/// [`from_utf8()`]: struct.String.html#method.from_utf8 +/// [`from_utf8`]: struct.String.html#method.from_utf8 /// [`String`]: struct.String.html -/// [`into_bytes()`]: struct.FromUtf8Error.html#method.into_bytes +/// [`into_bytes`]: struct.FromUtf8Error.html#method.into_bytes /// /// The [`Utf8Error`] type provided by [`std::str`] represents an error that may /// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error` -/// through the [`utf8_error()`] method. +/// through the [`utf8_error`] method. /// /// [`Utf8Error`]: ../../std/str/struct.Utf8Error.html /// [`std::str`]: ../../std/str/index.html /// [`u8`]: ../../std/primitive.u8.html /// [`&str`]: ../../std/primitive.str.html -/// [`utf8_error()`]: #method.utf8_error +/// [`utf8_error`]: #method.utf8_error /// /// # Examples /// @@ -308,9 +308,9 @@ pub struct FromUtf8Error { /// A possible error value when converting a `String` from a UTF-16 byte slice. /// -/// This type is the error type for the [`from_utf16()`] method on [`String`]. +/// This type is the error type for the [`from_utf16`] method on [`String`]. /// -/// [`from_utf16()`]: struct.String.html#method.from_utf16 +/// [`from_utf16`]: struct.String.html#method.from_utf16 /// [`String`]: struct.String.html /// /// # Examples @@ -335,10 +335,10 @@ impl String { /// buffer. While that means that this initial operation is very /// inexpensive, but may cause excessive allocation later, when you add /// data. If you have an idea of how much data the `String` will hold, - /// consider the [`with_capacity()`] method to prevent excessive + /// consider the [`with_capacity`] method to prevent excessive /// re-allocation. /// - /// [`with_capacity()`]: #method.with_capacity + /// [`with_capacity`]: #method.with_capacity /// /// # Examples /// @@ -356,18 +356,18 @@ impl String { /// Creates a new empty `String` with a particular capacity. /// /// `String`s have an internal buffer to hold their data. The capacity is - /// the length of that buffer, and can be queried with the [`capacity()`] + /// the length of that buffer, and can be queried with the [`capacity`] /// method. This method creates an empty `String`, but one with an initial /// buffer that can hold `capacity` bytes. This is useful when you may be /// appending a bunch of data to the `String`, reducing the number of /// reallocations it needs to do. /// - /// [`capacity()`]: #method.capacity + /// [`capacity`]: #method.capacity /// /// If the given capacity is `0`, no allocation will occur, and this method - /// is identical to the [`new()`] method. + /// is identical to the [`new`] method. /// - /// [`new()`]: #method.new + /// [`new`]: #method.new /// /// # Examples /// @@ -420,18 +420,18 @@ impl String { /// /// If you are sure that the byte slice is valid UTF-8, and you don't want /// to incur the overhead of the validity check, there is an unsafe version - /// of this function, [`from_utf8_unchecked()`], which has the same behavior + /// of this function, [`from_utf8_unchecked`], which has the same behavior /// but skips the check. /// - /// [`from_utf8_unchecked()`]: struct.String.html#method.from_utf8_unchecked + /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked /// /// This method will take care to not copy the vector, for efficiency's /// sake. /// /// If you need a `&str` instead of a `String`, consider - /// [`str::from_utf8()`]. + /// [`str::from_utf8`]. /// - /// [`str::from_utf8()`]: ../../std/str/fn.from_utf8.html + /// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html /// /// The inverse of this method is [`as_bytes`]. /// @@ -497,10 +497,10 @@ impl String { /// /// If you are sure that the byte slice is valid UTF-8, and you don't want /// to incur the overhead of the conversion, there is an unsafe version - /// of this function, [`from_utf8_unchecked()`], which has the same behavior + /// of this function, [`from_utf8_unchecked`], which has the same behavior /// but skips the checks. /// - /// [`from_utf8_unchecked()`]: struct.String.html#method.from_utf8_unchecked + /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked /// /// This function returns a [`Cow<'a, str>`]. If our byte slice is invalid /// UTF-8, then we need to insert the replacement characters, which will @@ -738,9 +738,9 @@ impl String { /// Converts a vector of bytes to a `String` without checking that the /// string contains valid UTF-8. /// - /// See the safe version, [`from_utf8()`], for more details. + /// See the safe version, [`from_utf8`], for more details. /// - /// [`from_utf8()`]: struct.String.html#method.from_utf8 + /// [`from_utf8`]: struct.String.html#method.from_utf8 /// /// # Safety /// @@ -845,10 +845,10 @@ impl String { /// The capacity may be increased by more than `additional` bytes if it /// chooses, to prevent frequent reallocations. /// - /// If you do not want this "at least" behavior, see the [`reserve_exact()`] + /// If you do not want this "at least" behavior, see the [`reserve_exact`] /// method. /// - /// [`reserve_exact()`]: #method.reserve_exact + /// [`reserve_exact`]: #method.reserve_exact /// /// # Panics /// @@ -892,10 +892,10 @@ impl String { /// Ensures that this `String`'s capacity is `additional` bytes /// larger than its length. /// - /// Consider using the [`reserve()`] method unless you absolutely know + /// Consider using the [`reserve`] method unless you absolutely know /// better than the allocator. /// - /// [`reserve()`]: #method.reserve + /// [`reserve`]: #method.reserve /// /// # Panics /// @@ -1699,9 +1699,9 @@ impl<'a> Add<&'a str> for String { /// Implements the `+=` operator for appending to a `String`. /// -/// This has the same behavior as the [`push_str()`] method. +/// This has the same behavior as the [`push_str`] method. /// -/// [`push_str()`]: struct.String.html#method.push_str +/// [`push_str`]: struct.String.html#method.push_str #[stable(feature = "stringaddassign", since = "1.12.0")] impl<'a> AddAssign<&'a str> for String { #[inline] @@ -1830,14 +1830,14 @@ impl ops::DerefMut for String { /// /// This `enum` is slightly awkward: it will never actually exist. This error is /// part of the type signature of the implementation of [`FromStr`] on -/// [`String`]. The return type of [`from_str()`], requires that an error be +/// [`String`]. The return type of [`from_str`], requires that an error be /// defined, but, given that a [`String`] can always be made into a new /// [`String`] without error, this type will never actually be returned. As /// such, it is only here to satisfy said signature, and is useless otherwise. /// /// [`FromStr`]: ../../std/str/trait.FromStr.html /// [`String`]: struct.String.html -/// [`from_str()`]: ../../std/str/trait.FromStr.html#tymethod.from_str +/// [`from_str`]: ../../std/str/trait.FromStr.html#tymethod.from_str #[stable(feature = "str_parse_error", since = "1.5.0")] #[derive(Copy)] pub enum ParseError {} @@ -2042,10 +2042,10 @@ impl fmt::Write for String { /// A draining iterator for `String`. /// -/// This struct is created by the [`drain()`] method on [`String`]. See its +/// This struct is created by the [`drain`] method on [`String`]. See its /// documentation for more. /// -/// [`drain()`]: struct.String.html#method.drain +/// [`drain`]: struct.String.html#method.drain /// [`String`]: struct.String.html #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a> { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d38c9f6e1cf80..76bc3fc3575d9 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -16,7 +16,7 @@ //! //! # Examples //! -//! You can explicitly create a [`Vec`] with [`new()`]: +//! You can explicitly create a [`Vec`] with [`new`]: //! //! ``` //! let v: Vec = Vec::new(); @@ -58,7 +58,7 @@ //! ``` //! //! [`Vec`]: ../../std/vec/struct.Vec.html -//! [`new()`]: ../../std/vec/struct.Vec.html#method.new +//! [`new`]: ../../std/vec/struct.Vec.html#method.new //! [`push`]: ../../std/vec/struct.Vec.html#method.push //! [`Index`]: ../../std/ops/trait.Index.html //! [`IndexMut`]: ../../std/ops/trait.IndexMut.html @@ -216,19 +216,19 @@ use Bound::{Excluded, Included, Unbounded}; /// The pointer will never be null, so this type is null-pointer-optimized. /// /// However, the pointer may not actually point to allocated memory. In particular, -/// if you construct a `Vec` with capacity 0 via [`Vec::new()`], [`vec![]`][`vec!`], -/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit()`] +/// if you construct a `Vec` with capacity 0 via [`Vec::new`], [`vec![]`][`vec!`], +/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit`] /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized /// types inside a `Vec`, it will not allocate space for them. *Note that in this case -/// the `Vec` may not report a [`capacity()`] of 0*. `Vec` will allocate if and only -/// if [`mem::size_of::()`]` * capacity() > 0`. In general, `Vec`'s allocation +/// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only +/// if [`mem::size_of::`]` * capacity() > 0`. In general, `Vec`'s allocation /// details are subtle enough that it is strongly recommended that you only /// free memory allocated by a `Vec` by creating a new `Vec` and dropping it. /// /// If a `Vec` *has* allocated memory, then the memory it points to is on the heap /// (as defined by the allocator Rust is configured to use by default), and its -/// pointer points to [`len()`] initialized elements in order (what you would see -/// if you coerced it to a slice), followed by [`capacity()`]` - `[`len()`] +/// pointer points to [`len`] initialized elements in order (what you would see +/// if you coerced it to a slice), followed by [`capacity`]` - `[`len`] /// logically uninitialized elements. /// /// `Vec` will never perform a "small optimization" where elements are actually @@ -244,13 +244,13 @@ use Bound::{Excluded, Included, Unbounded}; /// /// `Vec` will never automatically shrink itself, even if completely empty. This /// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec` -/// and then filling it back up to the same [`len()`] should incur no calls to +/// and then filling it back up to the same [`len`] should incur no calls to /// the allocator. If you wish to free up unused memory, use -/// [`shrink_to_fit`][`shrink_to_fit()`]. +/// [`shrink_to_fit`][`shrink_to_fit`]. /// /// [`push`] and [`insert`] will never (re)allocate if the reported capacity is /// sufficient. [`push`] and [`insert`] *will* (re)allocate if -/// [`len()`]` == `[`capacity()`]. That is, the reported capacity is completely +/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely /// accurate, and can be relied on. It can even be used to manually free the memory /// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even /// when not necessary. @@ -262,7 +262,7 @@ use Bound::{Excluded, Included, Unbounded}; /// /// `vec![x; n]`, `vec![a, b, c, d]`, and /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` -/// with exactly the requested capacity. If [`len()`]` == `[`capacity()`], +/// with exactly the requested capacity. If [`len`]` == `[`capacity`], /// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to /// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. /// @@ -283,11 +283,11 @@ use Bound::{Excluded, Included, Unbounded}; /// [`String`]: ../../std/string/struct.String.html /// [`&str`]: ../../std/primitive.str.html /// [`Vec::with_capacity`]: ../../std/vec/struct.Vec.html#method.with_capacity -/// [`Vec::new()`]: ../../std/vec/struct.Vec.html#method.new -/// [`shrink_to_fit()`]: ../../std/vec/struct.Vec.html#method.shrink_to_fit -/// [`capacity()`]: ../../std/vec/struct.Vec.html#method.capacity -/// [`mem::size_of::()`]: ../../std/mem/fn.size_of.html -/// [`len()`]: ../../std/vec/struct.Vec.html#method.len +/// [`Vec::new`]: ../../std/vec/struct.Vec.html#method.new +/// [`shrink_to_fit`]: ../../std/vec/struct.Vec.html#method.shrink_to_fit +/// [`capacity`]: ../../std/vec/struct.Vec.html#method.capacity +/// [`mem::size_of::`]: ../../std/mem/fn.size_of.html +/// [`len`]: ../../std/vec/struct.Vec.html#method.len /// [`push`]: ../../std/vec/struct.Vec.html#method.push /// [`insert`]: ../../std/vec/struct.Vec.html#method.insert /// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve @@ -504,12 +504,12 @@ impl Vec { /// Converts the vector into [`Box<[T]>`][owned slice]. /// /// Note that this will drop any excess capacity. Calling this and - /// converting back to a vector with [`into_vec()`] is equivalent to calling - /// [`shrink_to_fit()`]. + /// converting back to a vector with [`into_vec`] is equivalent to calling + /// [`shrink_to_fit`]. /// /// [owned slice]: ../../std/boxed/struct.Box.html - /// [`into_vec()`]: ../../std/primitive.slice.html#method.into_vec - /// [`shrink_to_fit()`]: #method.shrink_to_fit + /// [`into_vec`]: ../../std/primitive.slice.html#method.into_vec + /// [`shrink_to_fit`]: #method.shrink_to_fit /// /// # Examples /// diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 78764091cf032..a9282b5b02fea 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -97,9 +97,9 @@ pub const MAX: char = '\u{10ffff}'; /// [`as`]: ../../book/casting-between-types.html#as /// /// For an unsafe version of this function which ignores these checks, see -/// [`from_u32_unchecked()`]. +/// [`from_u32_unchecked`]. /// -/// [`from_u32_unchecked()`]: fn.from_u32_unchecked.html +/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html /// /// # Examples /// @@ -152,9 +152,9 @@ pub fn from_u32(i: u32) -> Option { /// /// This function is unsafe, as it may construct invalid `char` values. /// -/// For a safe version of this function, see the [`from_u32()`] function. +/// For a safe version of this function, see the [`from_u32`] function. /// -/// [`from_u32()`]: fn.from_u32.html +/// [`from_u32`]: fn.from_u32.html /// /// # Examples /// @@ -479,10 +479,10 @@ impl CharExt for char { /// Returns an iterator that yields the hexadecimal Unicode escape of a /// character, as `char`s. /// -/// This `struct` is created by the [`escape_unicode()`] method on [`char`]. See +/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See /// its documentation for more. /// -/// [`escape_unicode()`]: ../../std/primitive.char.html#method.escape_unicode +/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode /// [`char`]: ../../std/primitive.char.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -600,10 +600,10 @@ impl fmt::Display for EscapeUnicode { /// An iterator that yields the literal escape code of a `char`. /// -/// This `struct` is created by the [`escape_default()`] method on [`char`]. See +/// This `struct` is created by the [`escape_default`] method on [`char`]. See /// its documentation for more. /// -/// [`escape_default()`]: ../../std/primitive.char.html#method.escape_default +/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default /// [`char`]: ../../std/primitive.char.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -713,10 +713,10 @@ impl fmt::Display for EscapeDefault { /// An iterator that yields the literal escape code of a `char`. /// -/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its +/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its /// documentation for more. /// -/// [`escape_debug()`]: ../../std/primitive.char.html#method.escape_debug +/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug /// [`char`]: ../../std/primitive.char.html #[unstable(feature = "char_escape_debug", issue = "35068")] #[derive(Clone, Debug)] diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 8dbbc5928f45a..97b9525da6715 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -61,7 +61,7 @@ /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of [`clone()`] calls [`clone()`] on each field. +/// implementation of [`clone`] calls [`clone`] on each field. /// /// ## How can I implement `Clone`? /// @@ -75,7 +75,7 @@ /// `Clone` cannot be `derive`d, but can be implemented as: /// /// [`Copy`]: ../../std/marker/trait.Copy.html -/// [`clone()`]: trait.Clone.html#tymethod.clone +/// [`clone`]: trait.Clone.html#tymethod.clone /// /// ``` /// #[derive(Copy)] diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 4e170794c1d6e..70e285f202e52 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -154,14 +154,14 @@ pub trait AsMut { /// # Generic Impls /// /// - [`From`][From]` for U` implies `Into for T` -/// - [`into()`] is reflexive, which means that `Into for T` is implemented +/// - [`into`] is reflexive, which means that `Into for T` is implemented /// /// [`TryInto`]: trait.TryInto.html /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html /// [From]: trait.From.html -/// [`into()`]: trait.Into.html#tymethod.into +/// [`into`]: trait.Into.html#tymethod.into #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. @@ -187,14 +187,14 @@ pub trait Into: Sized { /// # Generic impls /// /// - `From for U` implies [`Into`]` for T` -/// - [`from()`] is reflexive, which means that `From for T` is implemented +/// - [`from`] is reflexive, which means that `From for T` is implemented /// /// [`TryFrom`]: trait.TryFrom.html /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html /// [`Into`]: trait.Into.html -/// [`from()`]: trait.From.html#tymethod.from +/// [`from`]: trait.From.html#tymethod.from #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index f0d8d1a321917..aadeaac83d5c8 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -106,7 +106,7 @@ mod sip; /// /// This trait can be used with `#[derive]` if all fields implement `Hash`. /// When `derive`d, the resulting hash will be the combination of the values -/// from calling [`.hash()`] on each field. +/// from calling [`.hash`] on each field. /// /// ## How can I implement `Hash`? /// @@ -133,7 +133,7 @@ mod sip; /// [`Eq`]: ../../std/cmp/trait.Eq.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html -/// [`.hash()`]: #tymethod.hash +/// [`.hash`]: #tymethod.hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the state given, updating the hasher as necessary. diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 0f47378aebb7c..1301c311c14ca 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -140,11 +140,11 @@ pub trait Iterator { /// Consumes the iterator, counting the number of iterations and returning it. /// - /// This method will evaluate the iterator until its [`next()`] returns + /// This method will evaluate the iterator until its [`next`] returns /// [`None`]. Once [`None`] is encountered, `count()` returns the number of - /// times it called [`next()`]. + /// times it called [`next`]. /// - /// [`next()`]: #tymethod.next + /// [`next`]: #tymethod.next /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Overflow Behavior @@ -323,7 +323,7 @@ pub trait Iterator { /// /// In other words, it zips two iterators together, into a single one. /// - /// When either iterator returns [`None`], all further calls to [`next()`] + /// When either iterator returns [`None`], all further calls to [`next`] /// will return [`None`]. /// /// # Examples @@ -364,7 +364,7 @@ pub trait Iterator { /// /// `zip()` is often used to zip an infinite iterator to a finite one. /// This works because the finite iterator will eventually return [`None`], - /// ending the zipper. Zipping with `(0..)` can look a lot like [`enumerate()`]: + /// ending the zipper. Zipping with `(0..)` can look a lot like [`enumerate`]: /// /// ``` /// let enumerate: Vec<_> = "foo".chars().enumerate().collect(); @@ -381,8 +381,8 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// - /// [`enumerate()`]: trait.Iterator.html#method.enumerate - /// [`next()`]: ../../std/iter/trait.Iterator.html#tymethod.next + /// [`enumerate`]: trait.Iterator.html#method.enumerate + /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../std/option/enum.Option.html#variant.None #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -524,11 +524,11 @@ pub trait Iterator { /// closure returns [`None`], it will try again, and call the closure on the /// next element, seeing if it will return [`Some`]. /// - /// Why `filter_map()` and not just [`filter()`].[`map()`]? The key is in this + /// Why `filter_map()` and not just [`filter()`].[`map`]? The key is in this /// part: /// - /// [`filter()`]: #method.filter - /// [`map()`]: #method.map + /// [`filter`]: #method.filter + /// [`map`]: #method.map /// /// > If the closure returns [`Some(element)`][`Some`], then that element is returned. /// @@ -550,7 +550,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), None); /// ``` /// - /// Here's the same example, but with [`filter()`] and [`map()`]: + /// Here's the same example, but with [`filter`] and [`map`]: /// /// ``` /// let a = ["1", "2", "lol"]; @@ -585,7 +585,7 @@ pub trait Iterator { /// iterator. /// /// `enumerate()` keeps its count as a [`usize`]. If you want to count by a - /// different sized integer, the [`zip()`] function provides similar + /// different sized integer, the [`zip`] function provides similar /// functionality. /// /// # Overflow Behavior @@ -601,7 +601,7 @@ pub trait Iterator { /// /// [`usize::MAX`]: ../../std/usize/constant.MAX.html /// [`usize`]: ../../std/primitive.usize.html - /// [`zip()`]: #method.zip + /// [`zip`]: #method.zip /// /// # Examples /// @@ -624,16 +624,16 @@ pub trait Iterator { /// Creates an iterator which can use `peek` to look at the next element of /// the iterator without consuming it. /// - /// Adds a [`peek()`] method to an iterator. See its documentation for + /// Adds a [`peek`] method to an iterator. See its documentation for /// more information. /// - /// Note that the underlying iterator is still advanced when [`peek()`] is + /// Note that the underlying iterator is still advanced when [`peek`] is /// called for the first time: In order to retrieve the next element, - /// [`next()`] is called on the underlying iterator, hence any side effects of - /// the [`next()`] method will occur. + /// [`next`] is called on the underlying iterator, hence any side effects of + /// the [`next`] method will occur. /// - /// [`peek()`]: struct.Peekable.html#method.peek - /// [`next()`]: ../../std/iter/trait.Iterator.html#tymethod.next + /// [`peek`]: struct.Peekable.html#method.peek + /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next /// /// # Examples /// @@ -666,9 +666,9 @@ pub trait Iterator { Peekable{iter: self, peeked: None} } - /// Creates an iterator that [`skip()`]s elements based on a predicate. + /// Creates an iterator that [`skip`]s elements based on a predicate. /// - /// [`skip()`]: #method.skip + /// [`skip`]: #method.skip /// /// `skip_while()` takes a closure as an argument. It will call this /// closure on each element of the iterator, and ignore elements @@ -863,10 +863,10 @@ pub trait Iterator { Take{iter: self, n: n} } - /// An iterator adaptor similar to [`fold()`] that holds internal state and + /// An iterator adaptor similar to [`fold`] that holds internal state and /// produces a new iterator. /// - /// [`fold()`]: #method.fold + /// [`fold`]: #method.fold /// /// `scan()` takes two arguments: an initial value which seeds the internal /// state, and a closure with two arguments, the first being a mutable @@ -910,16 +910,16 @@ pub trait Iterator { /// Creates an iterator that works like map, but flattens nested structure. /// - /// The [`map()`] adapter is very useful, but only when the closure + /// The [`map`] adapter is very useful, but only when the closure /// argument produces values. If it produces an iterator instead, there's /// an extra layer of indirection. `flat_map()` will remove this extra layer /// on its own. /// - /// Another way of thinking about `flat_map()`: [`map()`]'s closure returns + /// Another way of thinking about `flat_map()`: [`map`]'s closure returns /// one item for each element, and `flat_map()`'s closure returns an /// iterator for each element. /// - /// [`map()`]: #method.map + /// [`map`]: #method.map /// /// # Examples /// @@ -1106,7 +1106,7 @@ pub trait Iterator { /// library, used in a variety of contexts. /// /// The most basic pattern in which `collect()` is used is to turn one - /// collection into another. You take a collection, call [`iter()`] on it, + /// collection into another. You take a collection, call [`iter`] on it, /// do a bunch of transformations, and then `collect()` at the end. /// /// One of the keys to `collect()`'s power is that many things you might @@ -1211,7 +1211,7 @@ pub trait Iterator { /// assert_eq!(Ok(vec![1, 3]), result); /// ``` /// - /// [`iter()`]: ../../std/iter/trait.Iterator.html#tymethod.next + /// [`iter`]: ../../std/iter/trait.Iterator.html#tymethod.next /// [`String`]: ../../std/string/struct.String.html /// [`char`]: ../../std/primitive.char.html /// [`Result`]: ../../std/result/enum.Result.html @@ -1816,9 +1816,9 @@ pub trait Iterator { /// collections: one from the left elements of the pairs, and one /// from the right elements. /// - /// This function is, in some sense, the opposite of [`zip()`]. + /// This function is, in some sense, the opposite of [`zip`]. /// - /// [`zip()`]: #method.zip + /// [`zip`]: #method.zip /// /// # Examples /// @@ -1849,12 +1849,12 @@ pub trait Iterator { (ts, us) } - /// Creates an iterator which [`clone()`]s all of its elements. + /// Creates an iterator which [`clone`]s all of its elements. /// /// This is useful when you have an iterator over `&T`, but you need an /// iterator over `T`. /// - /// [`clone()`]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [`clone`]: ../../std/clone/trait.Clone.html#tymethod.clone /// /// # Examples /// diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index d9b8c5ea589fd..dcb3da4f839a5 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -48,15 +48,15 @@ //! } //! ``` //! -//! An iterator has a method, [`next()`], which when called, returns an -//! [`Option`]``. [`next()`] will return `Some(Item)` as long as there +//! An iterator has a method, [`next`], which when called, returns an +//! [`Option`]``. [`next`] will return `Some(Item)` as long as there //! are elements, and once they've all been exhausted, will return `None` to //! indicate that iteration is finished. Individual iterators may choose to -//! resume iteration, and so calling [`next()`] again may or may not eventually +//! resume iteration, and so calling [`next`] again may or may not eventually //! start returning `Some(Item)` again at some point. //! //! [`Iterator`]'s full definition includes a number of other methods as well, -//! but they are default methods, built on top of [`next()`], and so you get +//! but they are default methods, built on top of [`next`], and so you get //! them for free. //! //! Iterators are also composable, and it's common to chain them together to do @@ -64,7 +64,7 @@ //! below for more details. //! //! [`Iterator`]: trait.Iterator.html -//! [`next()`]: trait.Iterator.html#tymethod.next +//! [`next`]: trait.Iterator.html#tymethod.next //! [`Option`]: ../../std/option/enum.Option.html //! //! # The three forms of iteration @@ -168,13 +168,13 @@ //! produce an iterator. What gives? //! //! There's a trait in the standard library for converting something into an -//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter()`], +//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter`], //! which converts the thing implementing [`IntoIterator`] into an iterator. //! Let's take a look at that `for` loop again, and what the compiler converts //! it into: //! //! [`IntoIterator`]: trait.IntoIterator.html -//! [`into_iter()`]: trait.IntoIterator.html#tymethod.into_iter +//! [`into_iter`]: trait.IntoIterator.html#tymethod.into_iter //! //! ``` //! let values = vec![1, 2, 3, 4, 5]; @@ -202,7 +202,7 @@ //! ``` //! //! First, we call `into_iter()` on the value. Then, we match on the iterator -//! that returns, calling [`next()`] over and over until we see a `None`. At +//! that returns, calling [`next`] over and over until we see a `None`. At //! that point, we `break` out of the loop, and we're done iterating. //! //! There's one more subtle bit here: the standard library contains an @@ -225,19 +225,19 @@ //! often called 'iterator adapters', as they're a form of the 'adapter //! pattern'. //! -//! Common iterator adapters include [`map()`], [`take()`], and [`filter()`]. +//! Common iterator adapters include [`map`], [`take`], and [`filter`]. //! For more, see their documentation. //! -//! [`map()`]: trait.Iterator.html#method.map -//! [`take()`]: trait.Iterator.html#method.take -//! [`filter()`]: trait.Iterator.html#method.filter +//! [`map`]: trait.Iterator.html#method.map +//! [`take`]: trait.Iterator.html#method.take +//! [`filter`]: trait.Iterator.html#method.filter //! //! # Laziness //! //! Iterators (and iterator [adapters](#adapters)) are *lazy*. This means that //! just creating an iterator doesn't _do_ a whole lot. Nothing really happens -//! until you call [`next()`]. This is sometimes a source of confusion when -//! creating an iterator solely for its side effects. For example, the [`map()`] +//! until you call [`next`]. This is sometimes a source of confusion when +//! creating an iterator solely for its side effects. For example, the [`map`] //! method calls a closure on each element it iterates over: //! //! ``` @@ -254,7 +254,7 @@ //! do nothing unless consumed //! ``` //! -//! The idiomatic way to write a [`map()`] for its side effects is to use a +//! The idiomatic way to write a [`map`] for its side effects is to use a //! `for` loop instead: //! //! ``` @@ -265,12 +265,12 @@ //! } //! ``` //! -//! [`map()`]: trait.Iterator.html#method.map +//! [`map`]: trait.Iterator.html#method.map //! //! The two most common ways to evaluate an iterator are to use a `for` loop -//! like this, or using the [`collect()`] method to produce a new collection. +//! like this, or using the [`collect`] method to produce a new collection. //! -//! [`collect()`]: trait.Iterator.html#method.collect +//! [`collect`]: trait.Iterator.html#method.collect //! //! # Infinity //! @@ -281,7 +281,7 @@ //! let numbers = 0..; //! ``` //! -//! It is common to use the [`take()`] iterator adapter to turn an infinite +//! It is common to use the [`take`] iterator adapter to turn an infinite //! iterator into a finite one: //! //! ``` @@ -295,7 +295,7 @@ //! //! This will print the numbers `0` through `4`, each on their own line. //! -//! [`take()`]: trait.Iterator.html#method.take +//! [`take`]: trait.Iterator.html#method.take #![stable(feature = "rust1", since = "1.0.0")] @@ -338,10 +338,10 @@ mod traits; /// An double-ended iterator with the direction inverted. /// -/// This `struct` is created by the [`rev()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`rev()`]: trait.Iterator.html#method.rev +/// [`rev`]: trait.Iterator.html#method.rev /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -389,10 +389,10 @@ unsafe impl TrustedLen for Rev /// An iterator that clones the elements of an underlying iterator. /// -/// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`cloned()`]: trait.Iterator.html#method.cloned +/// [`cloned`]: trait.Iterator.html#method.cloned /// [`Iterator`]: trait.Iterator.html #[stable(feature = "iter_cloned", since = "1.1.0")] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -469,10 +469,10 @@ unsafe impl<'a, I, T: 'a> TrustedLen for Cloned /// An iterator that repeats endlessly. /// -/// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`cycle()`]: trait.Iterator.html#method.cycle +/// [`cycle`]: trait.Iterator.html#method.cycle /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -510,10 +510,10 @@ impl FusedIterator for Cycle where I: Clone + Iterator {} /// An iterator that strings two iterators together. /// -/// This `struct` is created by the [`chain()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`chain()`]: trait.Iterator.html#method.chain +/// [`chain`]: trait.Iterator.html#method.chain /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -703,10 +703,10 @@ unsafe impl TrustedLen for Chain /// An iterator that iterates two other iterators simultaneously. /// -/// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`zip()`]: trait.Iterator.html#method.zip +/// [`zip`]: trait.Iterator.html#method.zip /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -925,16 +925,16 @@ unsafe impl TrustedLen for Zip /// An iterator that maps the values of `iter` with `f`. /// -/// This `struct` is created by the [`map()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`map`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`map()`]: trait.Iterator.html#method.map +/// [`map`]: trait.Iterator.html#method.map /// [`Iterator`]: trait.Iterator.html /// /// # Notes about side effects /// -/// The [`map()`] iterator implements [`DoubleEndedIterator`], meaning that -/// you can also [`map()`] backwards: +/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that +/// you can also [`map`] backwards: /// /// ```rust /// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); @@ -1058,10 +1058,10 @@ unsafe impl TrustedRandomAccess for Map /// An iterator that filters the elements of `iter` with `predicate`. /// -/// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`filter()`]: trait.Iterator.html#method.filter +/// [`filter`]: trait.Iterator.html#method.filter /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1142,10 +1142,10 @@ impl FusedIterator for Filter /// An iterator that uses `f` to both filter and map elements from `iter`. /// -/// This `struct` is created by the [`filter_map()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`filter_map()`]: trait.Iterator.html#method.filter_map +/// [`filter_map`]: trait.Iterator.html#method.filter_map /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1208,10 +1208,10 @@ impl FusedIterator for FilterMap /// An iterator that yields the current count and the element during iteration. /// -/// This `struct` is created by the [`enumerate()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`enumerate()`]: trait.Iterator.html#method.enumerate +/// [`enumerate`]: trait.Iterator.html#method.enumerate /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -1317,10 +1317,10 @@ unsafe impl TrustedLen for Enumerate /// An iterator with a `peek()` that returns an optional reference to the next /// element. /// -/// This `struct` is created by the [`peekable()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`peekable()`]: trait.Iterator.html#method.peekable +/// [`peekable`]: trait.Iterator.html#method.peekable /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -1401,10 +1401,10 @@ impl FusedIterator for Peekable {} impl Peekable { /// Returns a reference to the next() value without advancing the iterator. /// - /// Like [`next()`], if there is a value, it is wrapped in a `Some(T)`. + /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. /// But if the iteration is over, `None` is returned. /// - /// [`next()`]: trait.Iterator.html#tymethod.next + /// [`next`]: trait.Iterator.html#tymethod.next /// /// Because `peek()` returns a reference, and many iterators iterate over /// references, there can be a possibly confusing situation where the @@ -1452,10 +1452,10 @@ impl Peekable { /// An iterator that rejects elements while `predicate` is true. /// -/// This `struct` is created by the [`skip_while()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`skip_while()`]: trait.Iterator.html#method.skip_while +/// [`skip_while`]: trait.Iterator.html#method.skip_while /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1506,10 +1506,10 @@ impl FusedIterator for SkipWhile /// An iterator that only accepts elements while `predicate` is true. /// -/// This `struct` is created by the [`take_while()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`take_while()`]: trait.Iterator.html#method.take_while +/// [`take_while`]: trait.Iterator.html#method.take_while /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1565,10 +1565,10 @@ impl FusedIterator for TakeWhile /// An iterator that skips over `n` elements of `iter`. /// -/// This `struct` is created by the [`skip()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`skip()`]: trait.Iterator.html#method.skip +/// [`skip`]: trait.Iterator.html#method.skip /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -1659,10 +1659,10 @@ impl FusedIterator for Skip where I: FusedIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. /// -/// This `struct` is created by the [`take()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`take`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`take()`]: trait.Iterator.html#method.take +/// [`take`]: trait.Iterator.html#method.take /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -1723,10 +1723,10 @@ impl FusedIterator for Take where I: FusedIterator {} /// An iterator to maintain state while iterating another iterator. /// -/// This `struct` is created by the [`scan()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`scan()`]: trait.Iterator.html#method.scan +/// [`scan`]: trait.Iterator.html#method.scan /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1773,10 +1773,10 @@ impl FusedIterator for Scan /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `struct` is created by the [`flat_map()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`flat_map()`]: trait.Iterator.html#method.flat_map +/// [`flat_map`]: trait.Iterator.html#method.flat_map /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1863,10 +1863,10 @@ impl FusedIterator for FlatMap /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// -/// This `struct` is created by the [`fuse()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`fuse()`]: trait.Iterator.html#method.fuse +/// [`fuse`]: trait.Iterator.html#method.fuse /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -2012,10 +2012,10 @@ impl ExactSizeIterator for Fuse where I: ExactSizeIterator { /// An iterator that calls a function with a reference to each element before /// yielding it. /// -/// This `struct` is created by the [`inspect()`] method on [`Iterator`]. See its +/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its /// documentation for more. /// -/// [`inspect()`]: trait.Iterator.html#method.inspect +/// [`inspect`]: trait.Iterator.html#method.inspect /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b988ce73bdefc..b405f35d5e4db 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -16,9 +16,9 @@ use super::{FusedIterator, TrustedLen}; /// An iterator that repeats an element endlessly. /// -/// This `struct` is created by the [`repeat()`] function. See its documentation for more. +/// This `struct` is created by the [`repeat`] function. See its documentation for more. /// -/// [`repeat()`]: fn.repeat.html +/// [`repeat`]: fn.repeat.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Repeat { @@ -50,9 +50,9 @@ impl FusedIterator for Repeat {} /// over and over and 🔁. /// /// Infinite iterators like `repeat()` are often used with adapters like -/// [`take()`], in order to make them finite. +/// [`take`], in order to make them finite. /// -/// [`take()`]: trait.Iterator.html#method.take +/// [`take`]: trait.Iterator.html#method.take /// /// # Examples /// @@ -74,7 +74,7 @@ impl FusedIterator for Repeat {} /// assert_eq!(Some(4), fours.next()); /// ``` /// -/// Going finite with [`take()`]: +/// Going finite with [`take`]: /// /// ``` /// use std::iter; @@ -98,9 +98,9 @@ pub fn repeat(elt: T) -> Repeat { /// An iterator that yields nothing. /// -/// This `struct` is created by the [`empty()`] function. See its documentation for more. +/// This `struct` is created by the [`empty`] function. See its documentation for more. /// -/// [`empty()`]: fn.empty.html +/// [`empty`]: fn.empty.html #[stable(feature = "iter_empty", since = "1.2.0")] pub struct Empty(marker::PhantomData); @@ -183,9 +183,9 @@ pub fn empty() -> Empty { /// An iterator that yields an element exactly once. /// -/// This `struct` is created by the [`once()`] function. See its documentation for more. +/// This `struct` is created by the [`once`] function. See its documentation for more. /// -/// [`once()`]: fn.once.html +/// [`once`]: fn.once.html #[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] pub struct Once { @@ -227,12 +227,12 @@ impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. /// -/// This is commonly used to adapt a single value into a [`chain()`] of other +/// This is commonly used to adapt a single value into a [`chain`] of other /// kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// [`chain()`]: trait.Iterator.html#method.chain +/// [`chain`]: trait.Iterator.html#method.chain /// /// # Examples /// diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index cb180110d3cc0..3415b0eea9bd0 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -16,13 +16,13 @@ use num::Wrapping; /// created from an iterator. This is common for types which describe a /// collection of some kind. /// -/// `FromIterator`'s [`from_iter()`] is rarely called explicitly, and is instead -/// used through [`Iterator`]'s [`collect()`] method. See [`collect()`]'s +/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead +/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s /// documentation for more examples. /// -/// [`from_iter()`]: #tymethod.from_iter +/// [`from_iter`]: #tymethod.from_iter /// [`Iterator`]: trait.Iterator.html -/// [`collect()`]: trait.Iterator.html#method.collect +/// [`collect`]: trait.Iterator.html#method.collect /// /// See also: [`IntoIterator`]. /// @@ -42,7 +42,7 @@ use num::Wrapping; /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// -/// Using [`collect()`] to implicitly use `FromIterator`: +/// Using [`collect`] to implicitly use `FromIterator`: /// /// ``` /// let five_fives = std::iter::repeat(5).take(5); @@ -487,17 +487,17 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { /// backwards, a good start is to know where the end is. /// /// When implementing an `ExactSizeIterator`, You must also implement -/// [`Iterator`]. When doing so, the implementation of [`size_hint()`] *must* +/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* /// return the exact size of the iterator. /// /// [`Iterator`]: trait.Iterator.html -/// [`size_hint()`]: trait.Iterator.html#method.size_hint +/// [`size_hint`]: trait.Iterator.html#method.size_hint /// -/// The [`len()`] method has a default implementation, so you usually shouldn't +/// The [`len`] method has a default implementation, so you usually shouldn't /// implement it. However, you may be able to provide a more performant /// implementation than the default, so overriding it in this case makes sense. /// -/// [`len()`]: #method.len +/// [`len`]: #method.len /// /// # Examples /// @@ -557,11 +557,11 @@ pub trait ExactSizeIterator: Iterator { /// implementation, you can do so. See the [trait-level] docs for an /// example. /// - /// This function has the same safety guarantees as the [`size_hint()`] + /// This function has the same safety guarantees as the [`size_hint`] /// function. /// /// [trait-level]: trait.ExactSizeIterator.html - /// [`size_hint()`]: trait.Iterator.html#method.size_hint + /// [`size_hint`]: trait.Iterator.html#method.size_hint /// /// # Examples /// @@ -624,14 +624,14 @@ impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I { /// Trait to represent types that can be created by summing up an iterator. /// -/// This trait is used to implement the [`sum()`] method on iterators. Types which -/// implement the trait can be generated by the [`sum()`] method. Like +/// This trait is used to implement the [`sum`] method on iterators. Types which +/// implement the trait can be generated by the [`sum`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::sum()`]. +/// interacted with through [`Iterator::sum`]. /// -/// [`sum()`]: ../../std/iter/trait.Sum.html#tymethod.sum +/// [`sum`]: ../../std/iter/trait.Sum.html#tymethod.sum /// [`FromIterator`]: ../../std/iter/trait.FromIterator.html -/// [`Iterator::sum()`]: ../../std/iter/trait.Iterator.html#method.sum +/// [`Iterator::sum`]: ../../std/iter/trait.Iterator.html#method.sum #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -643,14 +643,14 @@ pub trait Sum: Sized { /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// -/// This trait is used to implement the [`product()`] method on iterators. Types -/// which implement the trait can be generated by the [`product()`] method. Like +/// This trait is used to implement the [`product`] method on iterators. Types +/// which implement the trait can be generated by the [`product`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::product()`]. +/// interacted with through [`Iterator::product`]. /// -/// [`product()`]: ../../std/iter/trait.Product.html#tymethod.product +/// [`product`]: ../../std/iter/trait.Product.html#tymethod.product /// [`FromIterator`]: ../../std/iter/trait.FromIterator.html -/// [`Iterator::product()`]: ../../std/iter/trait.Iterator.html#method.product +/// [`Iterator::product`]: ../../std/iter/trait.Iterator.html#method.product #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -823,12 +823,12 @@ impl Product> for Result /// that behave this way because it allows for some significant optimizations. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`] +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`] /// on the iterator. If the iterator is already fused, the additional [`Fuse`] /// wrapper will be a no-op with no performance penalty. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [`Iterator::fuse()`]: ../../std/iter/trait.Iterator.html#method.fuse +/// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse /// [`Fuse`]: ../../std/iter/struct.Fuse.html #[unstable(feature = "fused", issue = "35602")] pub trait FusedIterator: Iterator {} @@ -848,11 +848,11 @@ impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// # Safety /// /// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect [`.size_hint()`]’s upper bound. +/// Consumers of this trait must inspect [`.size_hint`]’s upper bound. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`usize::MAX`]: ../../std/usize/constant.MAX.html -/// [`.size_hint()`]: ../../std/iter/trait.Iterator.html#method.size_hint +/// [`.size_hint`]: ../../std/iter/trait.Iterator.html#method.size_hint #[unstable(feature = "trusted_len", issue = "37572")] pub unsafe trait TrustedLen : Iterator {} diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index b22f7fa17077b..021079f85f6be 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -90,10 +90,10 @@ macro_rules! assert { /// On panic, this macro will print the values of the expressions with their /// debug representations. /// -/// Like [`assert!()`], this macro has a second version, where a custom +/// Like [`assert!`], this macro has a second version, where a custom /// panic message can be provided. /// -/// [`assert!()`]: macro.assert.html +/// [`assert!`]: macro.assert.html /// /// # Examples /// diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 1e9eaaf5f3223..393c01b0105c5 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -245,7 +245,7 @@ pub trait Unsize { /// [`String`]'s buffer, leading to a double free. /// /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's -/// managing some resource besides its own [`size_of::()`] bytes. +/// managing some resource besides its own [`size_of::`] bytes. /// /// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get /// the error [E0204]. @@ -262,7 +262,7 @@ pub trait Unsize { /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html /// [`Drop`]: ../../std/ops/trait.Drop.html -/// [`size_of::()`]: ../../std/mem/fn.size_of.html +/// [`size_of::`]: ../../std/mem/fn.size_of.html /// [`Clone`]: ../clone/trait.Clone.html /// [`String`]: ../../std/string/struct.String.html /// [`i32`]: ../../std/primitive.i32.html diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f4ce4697d7cf4..ba65e4494a8bb 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -617,7 +617,7 @@ pub fn drop(_x: T) { } /// the contained value. /// /// This function will unsafely assume the pointer `src` is valid for -/// [`size_of::()`][size_of] bytes by transmuting `&T` to `&U` and then reading +/// [`size_of::`][size_of] bytes by transmuting `&T` to `&U` and then reading /// the `&U`. It will also unsafely create a copy of the contained value instead of /// moving out of `src`. /// diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97ea6bb347b54..81c80ba51152d 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2390,11 +2390,11 @@ impl usize { /// A classification of floating point numbers. /// -/// This `enum` is used as the return type for [`f32::classify()`] and [`f64::classify()`]. See +/// This `enum` is used as the return type for [`f32::classify`] and [`f64::classify`]. See /// their documentation for more. /// -/// [`f32::classify()`]: ../../std/primitive.f32.html#method.classify -/// [`f64::classify()`]: ../../std/primitive.f64.html#method.classify +/// [`f32::classify`]: ../../std/primitive.f32.html#method.classify +/// [`f64::classify`]: ../../std/primitive.f64.html#method.classify /// /// # Examples /// @@ -2756,9 +2756,9 @@ fn from_str_radix(src: &str, radix: u32) -> Result> Range { /// A range which is only bounded below: { x | start <= x }. /// Use `start..` for its shorthand. /// -/// See the [`contains()`](#method.contains) method for its characterization. +/// See the [`contains`](#method.contains) method for its characterization. /// /// Note: Currently, no overflow checking is done for the iterator /// implementation; if you use an integer range and the integer overflows, it @@ -2141,7 +2141,7 @@ impl> RangeFrom { /// A range which is only bounded above: { x | x < end }. /// Use `..end` (two dots) for its shorthand. /// -/// See the [`contains()`](#method.contains) method for its characterization. +/// See the [`contains`](#method.contains) method for its characterization. /// /// It cannot serve as an iterator because it doesn't have a starting point. /// @@ -2207,7 +2207,7 @@ impl> RangeTo { /// An inclusive range which is bounded at both ends: { x | start <= x <= end }. /// Use `start...end` (three dots) for its shorthand. /// -/// See the [`contains()`](#method.contains) method for its characterization. +/// See the [`contains`](#method.contains) method for its characterization. /// /// # Examples /// @@ -2293,7 +2293,7 @@ impl> RangeInclusive { /// An inclusive range which is only bounded above: { x | x <= end }. /// Use `...end` (three dots) for its shorthand. /// -/// See the [`contains()`](#method.contains) method for its characterization. +/// See the [`contains`](#method.contains) method for its characterization. /// /// It cannot serve as an iterator because it doesn't have a starting point. /// diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 52e3301631052..395a84460a91d 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -28,12 +28,12 @@ pub mod pattern; /// A trait to abstract the idea of creating a new instance of a type from a /// string. /// -/// `FromStr`'s [`from_str()`] method is often used implicitly, through -/// [`str`]'s [`parse()`] method. See [`parse()`]'s documentation for examples. +/// `FromStr`'s [`from_str`] method is often used implicitly, through +/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples. /// -/// [`from_str()`]: #tymethod.from_str +/// [`from_str`]: #tymethod.from_str /// [`str`]: ../../std/primitive.str.html -/// [`parse()`]: ../../std/primitive.str.html#method.parse +/// [`parse`]: ../../std/primitive.str.html#method.parse #[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. @@ -164,13 +164,13 @@ impl Utf8Error { /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of -/// this function, [`from_utf8_unchecked()`][fromutf8u], which has the same +/// this function, [`from_utf8_unchecked`][fromutf8u], which has the same /// behavior but skips the check. /// /// [fromutf8u]: fn.from_utf8_unchecked.html /// /// If you need a `String` instead of a `&str`, consider -/// [`String::from_utf8()`][string]. +/// [`String::from_utf8`][string]. /// /// [string]: ../../std/string/struct.String.html#method.from_utf8 /// @@ -265,7 +265,7 @@ unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. /// -/// See the safe version, [`from_utf8()`][fromutf8], for more information. +/// See the safe version, [`from_utf8`][fromutf8], for more information. /// /// [fromutf8]: fn.from_utf8.html /// @@ -310,9 +310,9 @@ Section: Iterators /// Iterator for the char (representing *Unicode Scalar Values*) of a string /// -/// Created with the method [`chars()`]. +/// Created with the method [`chars`]. /// -/// [`chars()`]: ../../std/primitive.str.html#method.chars +/// [`chars`]: ../../std/primitive.str.html#method.chars #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { @@ -567,9 +567,9 @@ impl<'a> CharIndices<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. /// -/// Created with the method [`bytes()`]. +/// Created with the method [`bytes`]. /// -/// [`bytes()`]: ../../std/primitive.str.html#method.bytes +/// [`bytes`]: ../../std/primitive.str.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Bytes<'a>(Cloned>); @@ -902,14 +902,14 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`split()`]. + /// Created with the method [`split`]. /// - /// [`split()`]: ../../std/primitive.str.html#method.split + /// [`split`]: ../../std/primitive.str.html#method.split struct Split; reverse: - /// Created with the method [`rsplit()`]. + /// Created with the method [`rsplit`]. /// - /// [`rsplit()`]: ../../std/primitive.str.html#method.rsplit + /// [`rsplit`]: ../../std/primitive.str.html#method.rsplit struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -920,14 +920,14 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - /// Created with the method [`split_terminator()`]. + /// Created with the method [`split_terminator`]. /// - /// [`split_terminator()`]: ../../std/primitive.str.html#method.split_terminator + /// [`split_terminator`]: ../../std/primitive.str.html#method.split_terminator struct SplitTerminator; reverse: - /// Created with the method [`rsplit_terminator()`]. + /// Created with the method [`rsplit_terminator`]. /// - /// [`rsplit_terminator()`]: ../../std/primitive.str.html#method.rsplit_terminator + /// [`rsplit_terminator`]: ../../std/primitive.str.html#method.rsplit_terminator struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -980,14 +980,14 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`splitn()`]. + /// Created with the method [`splitn`]. /// - /// [`splitn()`]: ../../std/primitive.str.html#method.splitn + /// [`splitn`]: ../../std/primitive.str.html#method.splitn struct SplitN; reverse: - /// Created with the method [`rsplitn()`]. + /// Created with the method [`rsplitn`]. /// - /// [`rsplitn()`]: ../../std/primitive.str.html#method.rsplitn + /// [`rsplitn`]: ../../std/primitive.str.html#method.rsplitn struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -1031,14 +1031,14 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`match_indices()`]. + /// Created with the method [`match_indices`]. /// - /// [`match_indices()`]: ../../std/primitive.str.html#method.match_indices + /// [`match_indices`]: ../../std/primitive.str.html#method.match_indices struct MatchIndices; reverse: - /// Created with the method [`rmatch_indices()`]. + /// Created with the method [`rmatch_indices`]. /// - /// [`rmatch_indices()`]: ../../std/primitive.str.html#method.rmatch_indices + /// [`rmatch_indices`]: ../../std/primitive.str.html#method.rmatch_indices struct RMatchIndices; stability: #[stable(feature = "str_match_indices", since = "1.5.0")] @@ -1084,14 +1084,14 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`matches()`]. + /// Created with the method [`matches`]. /// - /// [`matches()`]: ../../std/primitive.str.html#method.matches + /// [`matches`]: ../../std/primitive.str.html#method.matches struct Matches; reverse: - /// Created with the method [`rmatches()`]. + /// Created with the method [`rmatches`]. /// - /// [`rmatches()`]: ../../std/primitive.str.html#method.rmatches + /// [`rmatches`]: ../../std/primitive.str.html#method.rmatches struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] @@ -1100,9 +1100,9 @@ generate_pattern_iterators! { delegate double ended; } -/// Created with the method [`lines()`]. +/// Created with the method [`lines`]. /// -/// [`lines()`]: ../../std/primitive.str.html#method.lines +/// [`lines`]: ../../std/primitive.str.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Lines<'a>(Map, LinesAnyMap>); @@ -1133,9 +1133,9 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[unstable(feature = "fused", issue = "35602")] impl<'a> FusedIterator for Lines<'a> {} -/// Created with the method [`lines_any()`]. +/// Created with the method [`lines_any`]. /// -/// [`lines_any()`]: ../../std/primitive.str.html#method.lines_any +/// [`lines_any`]: ../../std/primitive.str.html#method.lines_any #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] #[derive(Clone, Debug)] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index e5562d05f10ae..b074e8b86b9a3 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -142,14 +142,14 @@ pub struct DirEntry(fs_imp::DirEntry); /// [`File::open`]: struct.File.html#method.open /// [`File::create`]: struct.File.html#method.create /// -/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`], -/// then chain calls to methods to set each option, then call [`open()`], +/// Generally speaking, when using `OpenOptions`, you'll first call [`new`], +/// then chain calls to methods to set each option, then call [`open`], /// passing the path of the file you're trying to open. This will give you a /// [`io::Result`][result] with a [`File`][file] inside that you can further /// operate on. /// -/// [`new()`]: struct.OpenOptions.html#method.new -/// [`open()`]: struct.OpenOptions.html#method.open +/// [`new`]: struct.OpenOptions.html#method.new +/// [`open`]: struct.OpenOptions.html#method.open /// [result]: ../io/type.Result.html /// [file]: struct.File.html /// diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 6d4da2e6a88cf..fb67eaf3c63a9 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -140,13 +140,13 @@ pub enum ErrorKind { #[stable(feature = "rust1", since = "1.0.0")] TimedOut, /// An error returned when an operation could not be completed because a - /// call to [`write()`] returned [`Ok(0)`]. + /// call to [`write`] returned [`Ok(0)`]. /// /// This typically means that an operation could only succeed if it wrote a /// particular number of bytes but only a smaller number of bytes could be /// written. /// - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Ok(0)`]: ../../std/io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] WriteZero, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 58788cdcd4c7c..850885a8c0f3a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,7 @@ //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For -//! example, [`Read`] adds a [`read()`] method, which we can use on `File`s: +//! example, [`Read`] adds a [`read`] method, which we can use on `File`s: //! //! ``` //! use std::io; @@ -106,7 +106,7 @@ //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write()`]: +//! to [`write`]: //! //! ``` //! use std::io; @@ -157,7 +157,7 @@ //! # } //! ``` //! -//! Of course, using [`io::stdout()`] directly is less common than something like +//! Of course, using [`io::stdout`] directly is less common than something like //! [`println!`]. //! //! ## Iterator types @@ -245,13 +245,13 @@ //! [`Vec`]: ../vec/struct.Vec.html //! [`BufReader`]: struct.BufReader.html //! [`BufWriter`]: struct.BufWriter.html -//! [`write()`]: trait.Write.html#tymethod.write -//! [`io::stdout()`]: fn.stdout.html +//! [`write`]: trait.Write.html#tymethod.write +//! [`io::stdout`]: fn.stdout.html //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`?` operator]: ../../book/syntax-index.html -//! [`read()`]: trait.Read.html#tymethod.read +//! [`read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] @@ -530,7 +530,7 @@ pub trait Read { /// If the data in this stream is *not* valid UTF-8 then an error is /// returned and `buf` is unchanged. /// - /// See [`read_to_end()`][readtoend] for other error semantics. + /// See [`read_to_end`][readtoend] for other error semantics. /// /// [readtoend]: #method.read_to_end /// @@ -815,12 +815,12 @@ pub trait Read { /// /// Implementors of the `Write` trait are sometimes called 'writers'. /// -/// Writers are defined by two required methods, [`write()`] and [`flush()`]: +/// Writers are defined by two required methods, [`write`] and [`flush`]: /// -/// * The [`write()`] method will attempt to write some data into the object, +/// * The [`write`] method will attempt to write some data into the object, /// returning how many bytes were successfully written. /// -/// * The [`flush()`] method is useful for adaptors and explicit buffers +/// * The [`flush`] method is useful for adaptors and explicit buffers /// themselves for ensuring that all buffered data has been pushed out to the /// 'true sink'. /// @@ -828,8 +828,8 @@ pub trait Read { /// throughout [`std::io`] take and provide types which implement the `Write` /// trait. /// -/// [`write()`]: #tymethod.write -/// [`flush()`]: #tymethod.flush +/// [`write`]: #tymethod.write +/// [`flush`]: #tymethod.flush /// [`std::io`]: index.html /// /// # Examples @@ -1159,7 +1159,7 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// /// For example, reading line-by-line is inefficient without using a buffer, so /// if you want to read by line, you'll need `BufRead`, which includes a -/// [`read_line()`] method as well as a [`lines()`] iterator. +/// [`read_line`] method as well as a [`lines`] iterator. /// /// # Examples /// @@ -1183,8 +1183,8 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// /// [`BufReader`]: struct.BufReader.html /// [`File`]: ../fs/struct.File.html -/// [`read_line()`]: #method.read_line -/// [`lines()`]: #method.lines +/// [`read_line`]: #method.read_line +/// [`lines`]: #method.lines /// [`Read`]: trait.Read.html /// /// ``` @@ -1209,13 +1209,13 @@ pub trait BufRead: Read { /// Fills the internal buffer of this object, returning the buffer contents. /// /// This function is a lower-level call. It needs to be paired with the - /// [`consume()`] method to function properly. When calling this + /// [`consume`] method to function properly. When calling this /// method, none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. As such, [`consume()`] must + /// calling `read` may return the same contents. As such, [`consume`] must /// be called with the number of bytes that are consumed from this buffer to /// ensure that the bytes are never returned twice. /// - /// [`consume()`]: #tymethod.consume + /// [`consume`]: #tymethod.consume /// /// An empty buffer returned indicates that the stream has reached EOF. /// @@ -1256,21 +1256,21 @@ pub trait BufRead: Read { /// so they should no longer be returned in calls to `read`. /// /// This function is a lower-level call. It needs to be paired with the - /// [`fill_buf()`] method to function properly. This function does + /// [`fill_buf`] method to function properly. This function does /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from [`fill_buf()`], has been consumed and should + /// its buffer, returned from [`fill_buf`], has been consumed and should /// no longer be returned. As such, this function may do odd things if - /// [`fill_buf()`] isn't called before calling it. + /// [`fill_buf`] isn't called before calling it. /// /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// [`fill_buf()`]. + /// [`fill_buf`]. /// /// # Examples /// - /// Since `consume()` is meant to be used with [`fill_buf()`], + /// Since `consume()` is meant to be used with [`fill_buf`], /// that method's example includes an example of `consume()`. /// - /// [`fill_buf()`]: #tymethod.fill_buf + /// [`fill_buf`]: #tymethod.fill_buf #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); @@ -1285,7 +1285,7 @@ pub trait BufRead: Read { /// # Errors /// /// This function will ignore all instances of [`ErrorKind::Interrupted`] and - /// will otherwise return any errors returned by [`fill_buf()`]. + /// will otherwise return any errors returned by [`fill_buf`]. /// /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. @@ -1295,7 +1295,7 @@ pub trait BufRead: Read { /// A locked standard input implements `BufRead`. In this example, we'll /// read from standard input until we see an `a` byte. /// - /// [`fill_buf()`]: #tymethod.fill_buf + /// [`fill_buf`]: #tymethod.fill_buf /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted /// /// ``` @@ -1330,7 +1330,7 @@ pub trait BufRead: Read { /// /// # Errors /// - /// This function has the same error semantics as [`read_until()`] and will + /// This function has the same error semantics as [`read_until`] and will /// also return an error if the read bytes are not valid UTF-8. If an I/O /// error is encountered then `buf` may contain some bytes already read in /// the event that all data read so far was valid UTF-8. @@ -1339,11 +1339,11 @@ pub trait BufRead: Read { /// /// A locked standard input implements `BufRead`. In this example, we'll /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines()`] method would be easier, of + /// an actual project, the [`lines`] method would be easier, of /// course. /// - /// [`lines()`]: #method.lines - /// [`read_until()`]: #method.read_until + /// [`lines`]: #method.lines + /// [`read_until`]: #method.read_until /// /// ``` /// use std::io; @@ -1375,7 +1375,7 @@ pub trait BufRead: Read { /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have /// the delimiter byte at the end. /// - /// This function will yield errors whenever [`read_until()`] would have + /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// /// # Examples @@ -1385,7 +1385,7 @@ pub trait BufRead: Read { /// /// [`io::Result`]: type.Result.html /// [`Vec`]: ../vec/struct.Vec.html - /// [`read_until()`]: #method.read_until + /// [`read_until`]: #method.read_until /// /// ``` /// use std::io; @@ -1428,9 +1428,9 @@ pub trait BufRead: Read { /// /// # Errors /// - /// Each line of the iterator has the same error semantics as [`BufRead::read_line()`]. + /// Each line of the iterator has the same error semantics as [`BufRead::read_line`]. /// - /// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line + /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line #[stable(feature = "rust1", since = "1.0.0")] fn lines(self) -> Lines where Self: Sized { Lines { buf: self } @@ -1439,10 +1439,10 @@ pub trait BufRead: Read { /// Adaptor to chain together two readers. /// -/// This struct is generally created by calling [`chain()`] on a reader. -/// Please see the documentation of [`chain()`] for more details. +/// This struct is generally created by calling [`chain`] on a reader. +/// Please see the documentation of [`chain`] for more details. /// -/// [`chain()`]: trait.Read.html#method.chain +/// [`chain`]: trait.Read.html#method.chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain { first: T, @@ -1496,10 +1496,10 @@ impl BufRead for Chain { /// Reader adaptor which limits the bytes read from an underlying reader. /// -/// This struct is generally created by calling [`take()`] on a reader. -/// Please see the documentation of [`take()`] for more details. +/// This struct is generally created by calling [`take`] on a reader. +/// Please see the documentation of [`take`] for more details. /// -/// [`take()`]: trait.Read.html#method.take +/// [`take`]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Take { @@ -1614,10 +1614,10 @@ fn read_one_byte(reader: &mut Read) -> Option> { /// An iterator over `u8` values of a reader. /// -/// This struct is generally created by calling [`bytes()`] on a reader. -/// Please see the documentation of [`bytes()`] for more details. +/// This struct is generally created by calling [`bytes`] on a reader. +/// Please see the documentation of [`bytes`] for more details. /// -/// [`bytes()`]: trait.Read.html#method.bytes +/// [`bytes`]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Bytes { @@ -1635,7 +1635,7 @@ impl Iterator for Bytes { /// An iterator over the `char`s of a reader. /// -/// This struct is generally created by calling [`chars()`][chars] on a reader. +/// This struct is generally created by calling [`chars`][chars] on a reader. /// Please see the documentation of `chars()` for more details. /// /// [chars]: trait.Read.html#method.chars @@ -1726,7 +1726,7 @@ impl fmt::Display for CharsError { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// This struct is generally created by calling [`split()`][split] on a +/// This struct is generally created by calling [`split`][split] on a /// `BufRead`. Please see the documentation of `split()` for more details. /// /// [split]: trait.BufRead.html#method.split @@ -1758,7 +1758,7 @@ impl Iterator for Split { /// An iterator over the lines of an instance of `BufRead`. /// -/// This struct is generally created by calling [`lines()`][lines] on a +/// This struct is generally created by calling [`lines`][lines] on a /// `BufRead`. Please see the documentation of `lines()` for more details. /// /// [lines]: trait.BufRead.html#method.lines diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index e16e8019b5f73..38ad23e14b3eb 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -332,11 +332,11 @@ impl<'a> fmt::Debug for StdinLock<'a> { /// /// Each handle shares a global buffer of data to be written to the standard /// output stream. Access is also synchronized via a lock and explicit control -/// over locking is available via the [`lock()`] method. +/// over locking is available via the [`lock`] method. /// /// Created by the [`io::stdout`] method. /// -/// [`lock()`]: #method.lock +/// [`lock`]: #method.lock /// [`io::stdout`]: fn.stdout.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdout { diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 4163187488e65..078f1ad3f6cfe 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -63,7 +63,7 @@ pub fn copy(reader: &mut R, writer: &mut W) -> io::Result< /// A reader which is always at EOF. /// -/// This struct is generally created by calling [`empty()`][empty]. Please see +/// This struct is generally created by calling [`empty`][empty]. Please see /// the documentation of `empty()` for more details. /// /// [empty]: fn.empty.html @@ -107,7 +107,7 @@ impl fmt::Debug for Empty { /// A reader which yields one byte over and over and over and over and over and... /// -/// This struct is generally created by calling [`repeat()`][repeat]. Please +/// This struct is generally created by calling [`repeat`][repeat]. Please /// see the documentation of `repeat()` for more details. /// /// [repeat]: fn.repeat.html @@ -150,7 +150,7 @@ impl fmt::Debug for Repeat { /// A writer which will move data into the void. /// -/// This struct is generally created by calling [`sink()`][sink]. Please +/// This struct is generally created by calling [`sink`][sink]. Please /// see the documentation of `sink()` for more details. /// /// [sink]: fn.sink.html diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 070690773b6c4..a6ea890c3ee8d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -21,7 +21,7 @@ //! contained an `extern crate std;` import at the [crate root]. Therefore the //! standard library can be accessed in [`use`] statements through the path //! `std`, as in [`use std::env`], or in expressions through the absolute path -//! `::std`, as in [`::std::env::args()`]. +//! `::std`, as in [`::std::env::args`]. //! //! # How to read this documentation //! @@ -156,7 +156,7 @@ //! [TCP]: net/struct.TcpStream.html //! [The Rust Prelude]: prelude/index.html //! [UDP]: net/struct.UdpSocket.html -//! [`::std::env::args()`]: env/fn.args.html +//! [`::std::env::args`]: env/fn.args.html //! [`Arc`]: sync/struct.Arc.html //! [owned slice]: boxed/index.html //! [`Cell`]: cell/struct.Cell.html diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 9bead22ef7f5e..a07972468e68a 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -183,7 +183,7 @@ impl TcpStream { /// Sets the read timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`read()`] calls will block + /// If the value specified is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. /// @@ -194,7 +194,7 @@ impl TcpStream { /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut /// @@ -214,7 +214,7 @@ impl TcpStream { /// Sets the write timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`write()`] calls will block + /// If the value specified is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// @@ -225,7 +225,7 @@ impl TcpStream { /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut @@ -246,14 +246,14 @@ impl TcpStream { /// Returns the read timeout of this socket. /// - /// If the timeout is [`None`], then [`read()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`read`] calls will block indefinitely. /// /// # Note /// /// Some platforms do not provide access to the current timeout. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// /// # Examples /// @@ -272,14 +272,14 @@ impl TcpStream { /// Returns the write timeout of this socket. /// - /// If the timeout is [`None`], then [`write()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`write`] calls will block indefinitely. /// /// # Note /// /// Some platforms do not provide access to the current timeout. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// /// # Examples /// @@ -618,7 +618,7 @@ impl TcpListener { /// Gets the value of the `IP_TTL` option for this socket. /// - /// For more information about this option, see [`set_ttl()`][link]. + /// For more information about this option, see [`set_ttl`][link]. /// /// [link]: #method.set_ttl /// diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index f452c75d38966..1ebce93934840 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -175,7 +175,7 @@ impl UdpSocket { /// Sets the read timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`read()`] calls will block + /// If the value specified is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// @@ -186,7 +186,7 @@ impl UdpSocket { /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut @@ -206,7 +206,7 @@ impl UdpSocket { /// Sets the write timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`write()`] calls will block + /// If the value specified is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// @@ -217,7 +217,7 @@ impl UdpSocket { /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut @@ -237,10 +237,10 @@ impl UdpSocket { /// Returns the read timeout of this socket. /// - /// If the timeout is [`None`], then [`read()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`read`] calls will block indefinitely. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// /// # Examples /// @@ -258,10 +258,10 @@ impl UdpSocket { /// Returns the write timeout of this socket. /// - /// If the timeout is [`None`], then [`write()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`write`] calls will block indefinitely. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// /// # Examples /// @@ -560,10 +560,10 @@ impl UdpSocket { /// Sends data on the socket to the remote address to which it is connected. /// - /// The [`connect()`] method will connect this socket to a remote address. This + /// The [`connect`] method will connect this socket to a remote address. This /// method will fail if the socket is not connected. /// - /// [`connect()`]: #method.connect + /// [`connect`]: #method.connect /// /// # Examples /// diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3b5a1cffc7a22..6f46a73698f35 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -160,10 +160,10 @@ pub fn take_hook() -> Box { /// A struct providing information about a panic. /// -/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook()`] +/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] /// function. /// -/// [`set_hook()`]: ../../std/panic/fn.set_hook.html +/// [`set_hook`]: ../../std/panic/fn.set_hook.html /// /// # Examples /// @@ -237,9 +237,9 @@ impl<'a> PanicInfo<'a> { /// A struct containing information about the location of a panic. /// -/// This structure is created by the [`location()`] method of [`PanicInfo`]. +/// This structure is created by the [`location`] method of [`PanicInfo`]. /// -/// [`location()`]: ../../std/panic/struct.PanicInfo.html#method.location +/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location /// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html /// /// # Examples diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 245a6d945b5a3..b5d2fe82dea80 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1065,13 +1065,13 @@ impl PathBuf { self.inner.push(path); } - /// Truncate `self` to [`self.parent()`]. + /// 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`. /// - /// [`self.parent()`]: struct.PathBuf.html#method.parent - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// [`self.parent`]: struct.PathBuf.html#method.parent + /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// /// # Examples /// @@ -1096,12 +1096,12 @@ impl PathBuf { } } - /// Updates [`self.file_name()`] to `file_name`. + /// Updates [`self.file_name`] to `file_name`. /// - /// If [`self.file_name()`] was [`None`], this is equivalent to pushing + /// If [`self.file_name`] was [`None`], this is equivalent to pushing /// `file_name`. /// - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples @@ -1130,15 +1130,15 @@ impl PathBuf { self.push(file_name); } - /// Updates [`self.extension()`] to `extension`. + /// Updates [`self.extension`] to `extension`. /// - /// If [`self.file_name()`] is `None`, does nothing and returns `false`. + /// If [`self.file_name`] is `None`, does nothing and returns `false`. /// - /// Otherwise, returns `true`; if [`self.extension()`] is [`None`], the + /// Otherwise, returns `true`; 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 + /// [`self.file_name`]: struct.PathBuf.html#method.file_name + /// [`self.extension`]: struct.PathBuf.html#method.extension /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples @@ -1733,9 +1733,9 @@ impl Path { iter_after(self.components().rev(), child.components().rev()).is_some() } - /// Extracts the stem (non-extension) portion of [`self.file_name()`]. + /// Extracts the stem (non-extension) portion of [`self.file_name`]. /// - /// [`self.file_name()`]: struct.Path.html#method.file_name + /// [`self.file_name`]: struct.Path.html#method.file_name /// /// The stem is: /// @@ -1760,7 +1760,7 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) } - /// Extracts the extension of [`self.file_name()`], if possible. + /// Extracts the extension of [`self.file_name`], if possible. /// /// The extension is: /// @@ -1769,7 +1769,7 @@ impl Path { /// * [`None`], if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` /// - /// [`self.file_name()`]: struct.Path.html#method.file_name + /// [`self.file_name`]: struct.Path.html#method.file_name /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index f4cd319f06454..c71e0b2a7035a 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -60,9 +60,9 @@ //! value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines -//! [`to_owned()`], the generic method for creating an owned type from a +//! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`], +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`], //! the method for producing a copy of a value. //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The //! comparison traits, which implement the comparison operators and are often @@ -117,7 +117,7 @@ //! [`ToOwned`]: ../borrow/trait.ToOwned.html //! [`ToString`]: ../string/trait.ToString.html //! [`Vec`]: ../vec/struct.Vec.html -//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone +//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone //! [`drop`]: ../mem/fn.drop.html //! [`std::borrow`]: ../borrow/index.html //! [`std::boxed`]: ../boxed/index.html @@ -135,7 +135,7 @@ //! [`std::slice`]: ../slice/index.html //! [`std::string`]: ../string/index.html //! [`std::vec`]: ../vec/index.html -//! [`to_owned()`]: ../borrow/trait.ToOwned.html#tymethod.to_owned +//! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned //! [book-closures]: ../../book/closures.html //! [book-dtor]: ../../book/drop.html //! [book-enums]: ../../book/enums.html diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 11197db98a396..7d6d16f474845 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -420,7 +420,7 @@ mod prim_slice { } /// # Representation /// /// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`.as_ptr()`] and [`len()`] methods: +/// length. You can look at these with the [`.as_ptr`] and [`len`] methods: /// /// ``` /// use std::slice; @@ -447,8 +447,8 @@ mod prim_slice { } /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`.as_ptr()`]: #method.as_ptr -/// [`len()`]: #method.len +/// [`.as_ptr`]: #method.as_ptr +/// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be /// used to get a string slice under normal circumstances. Use `.as_slice()` diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index f15e7ff891684..295a49d6a8e89 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -52,10 +52,10 @@ struct BarrierState { /// A result returned from wait. /// -/// Currently this opaque structure only has one method, [`.is_leader()`]. Only +/// Currently this opaque structure only has one method, [`.is_leader`]. Only /// one thread will receive a result that will return `true` from this function. /// -/// [`.is_leader()`]: #method.is_leader +/// [`.is_leader`]: #method.is_leader /// /// # Examples /// diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 68c7e88f67fc5..7ad9d9ee37ce6 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -150,7 +150,7 @@ impl Condvar { /// /// This function will atomically unlock the mutex specified (represented by /// `guard`) and block the current thread. This means that any calls - /// to [`notify_one()`] or [`notify_all()`] which happen logically after the + /// to [`notify_one`] or [`notify_all`] which happen logically after the /// mutex is unlocked are candidates to wake this thread up. When this /// function call returns, the lock specified will have been re-acquired. /// @@ -167,16 +167,16 @@ impl Condvar { /// /// # Panics /// - /// This function will [`panic!()`] if it is used with more than one mutex + /// This function will [`panic!`] if it is used with more than one mutex /// over time. Each condition variable is dynamically bound to exactly one /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. /// - /// [`notify_one()`]: #method.notify_one - /// [`notify_all()`]: #method.notify_all + /// [`notify_one`]: #method.notify_one + /// [`notify_all`]: #method.notify_all /// [poisoning]: ../sync/struct.Mutex.html#poisoning /// [`Mutex`]: ../sync/struct.Mutex.html - /// [`panic!()`]: ../../std/macro.panic.html + /// [`panic!`]: ../../std/macro.panic.html /// /// # Examples /// @@ -359,11 +359,11 @@ impl Condvar { /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to /// `notify_one` are not buffered in any way. /// - /// To wake up all threads, see [`notify_all()`]. + /// To wake up all threads, see [`notify_all`]. /// /// [`wait`]: #method.wait /// [`wait_timeout`]: #method.wait_timeout - /// [`notify_all()`]: #method.notify_all + /// [`notify_all`]: #method.notify_all /// /// # Examples /// @@ -401,9 +401,9 @@ impl Condvar { /// variable are awoken. Calls to `notify_all()` are not buffered in any /// way. /// - /// To wake up only one thread, see [`notify_one()`]. + /// To wake up only one thread, see [`notify_one`]. /// - /// [`notify_one()`]: #method.notify_one + /// [`notify_one`]: #method.notify_one /// /// # Examples /// diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index aeeab170deafe..71dd94161c03d 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -460,10 +460,10 @@ impl UnsafeFlavor for Receiver { /// All data sent on the sender will become available on the receiver, and no /// send will block the calling thread (this channel has an "infinite buffer"). /// -/// If the [`Receiver`] is disconnected while trying to [`send()`] with the -/// [`Sender`], the [`send()`] method will return an error. +/// If the [`Receiver`] is disconnected while trying to [`send`] with the +/// [`Sender`], the [`send`] method will return an error. /// -/// [`send()`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html /// @@ -504,13 +504,13 @@ pub fn channel() -> (Sender, Receiver) { /// `bound` specifies the buffer size. When the internal buffer becomes full, /// future sends will *block* waiting for the buffer to open up. Note that a /// buffer size of 0 is valid, in which case this becomes "rendezvous channel" -/// where each [`send()`] will not return until a recv is paired with it. +/// where each [`send`] will not return until a recv is paired with it. /// /// Like asynchronous channels, if the [`Receiver`] is disconnected while -/// trying to [`send()`] with the [`SyncSender`], the [`send()`] method will +/// trying to [`send`] with the [`SyncSender`], the [`send`] method will /// return an error. /// -/// [`send()`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send /// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html /// diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 97b84d59218ac..48d8d34dbe090 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -135,13 +135,13 @@ unsafe impl Sync for Mutex { } /// The data protected by the mutex can be access through this guard via its /// [`Deref`] and [`DerefMut`] implementations. /// -/// This structure is created by the [`lock()`] and [`try_lock()`] methods on +/// This structure is created by the [`lock`] and [`try_lock`] methods on /// [`Mutex`]. /// /// [`Deref`]: ../../std/ops/trait.Deref.html /// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`lock()`]: struct.Mutex.html#method.lock -/// [`try_lock()`]: struct.Mutex.html#method.try_lock +/// [`lock`]: struct.Mutex.html#method.lock +/// [`try_lock`]: struct.Mutex.html#method.try_lock /// [`Mutex`]: struct.Mutex.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index a3db0adeda00d..d26f2f7bb7e3c 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -78,11 +78,11 @@ unsafe impl Sync for RwLock {} /// RAII structure used to release the shared read access of a lock when /// dropped. /// -/// This structure is created by the [`read()`] and [`try_read()`] methods on +/// This structure is created by the [`read`] and [`try_read`] methods on /// [`RwLock`]. /// -/// [`read()`]: struct.RwLock.html#method.read -/// [`try_read()`]: struct.RwLock.html#method.try_read +/// [`read`]: struct.RwLock.html#method.read +/// [`try_read`]: struct.RwLock.html#method.try_read /// [`RwLock`]: struct.RwLock.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -96,11 +96,11 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped. /// -/// This structure is created by the [`write()`] and [`try_write()`] methods +/// This structure is created by the [`write`] and [`try_write`] methods /// on [`RwLock`]. /// -/// [`write()`]: struct.RwLock.html#method.write -/// [`try_write()`]: struct.RwLock.html#method.try_write +/// [`write`]: struct.RwLock.html#method.write +/// [`try_write`]: struct.RwLock.html#method.try_write /// [`RwLock`]: struct.RwLock.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 1ba4a104e515c..d5933d316c4bd 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -375,12 +375,12 @@ impl UnixStream { /// Sets the read timeout for the socket. /// - /// If the provided value is [`None`], then [`read()`] calls will block + /// If the provided value is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -399,12 +399,12 @@ impl UnixStream { /// Sets the write timeout for the socket. /// - /// If the provided value is [`None`], then [`write()`] calls will block + /// If the provided value is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -974,12 +974,12 @@ impl UnixDatagram { /// Connects the socket to the specified address. /// - /// The [`send()`] method may be used to send data to the specified address. - /// [`recv()`] and [`recv_from()`] will only receive data from that address. + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. /// - /// [`send()`]: #method.send - /// [`recv()`]: #method.recv - /// [`recv_from()`]: #method.recv_from + /// [`send`]: #method.send + /// [`recv`]: #method.recv + /// [`recv_from`]: #method.recv_from /// /// # Examples /// @@ -1047,9 +1047,9 @@ impl UnixDatagram { /// Returns the address of this socket's peer. /// - /// The [`connect()`] method will connect the socket to a peer. + /// The [`connect`] method will connect the socket to a peer. /// - /// [`connect()`]: #method.connect + /// [`connect`]: #method.connect /// /// # Examples /// @@ -1178,13 +1178,13 @@ impl UnixDatagram { /// Sets the read timeout for the socket. /// - /// If the provided value is [`None`], then [`recv()`] and [`recv_from()`] calls will + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will /// block indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`recv()`]: #method.recv - /// [`recv_from()`]: #method.recv_from + /// [`recv`]: #method.recv + /// [`recv_from`]: #method.recv_from /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -1203,13 +1203,13 @@ impl UnixDatagram { /// Sets the write timeout for the socket. /// - /// If the provided value is [`None`], then [`send()`] and [`send_to()`] calls will + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will /// block indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`send()`]: #method.send - /// [`send_to()`]: #method.send_to + /// [`send`]: #method.send + /// [`send_to`]: #method.send_to /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 2bc066d3fea55..64c2be25222a0 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -90,29 +90,29 @@ //! two ways: //! //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread()`] on the [`JoinHandle`]. -//! * By requesting the current thread, using the [`thread::current()`] function. +//! function, and calling [`thread`] on the [`JoinHandle`]. +//! * By requesting the current thread, using the [`thread::current`] function. //! -//! The [`thread::current()`] function is available even for threads not spawned +//! The [`thread::current`] function is available even for threads not spawned //! by the APIs of this module. //! //! ## Blocking support: park and unpark //! //! Every thread is equipped with some basic low-level blocking support, via the -//! [`thread::park()`][`park()`] function and [`thread::Thread::unpark()`][`unpark()`] -//! method. [`park()`] blocks the current thread, which can then be resumed from -//! another thread by calling the [`unpark()`] method on the blocked thread's handle. +//! [`thread::park`][`park`] function and [`thread::Thread::unpark()`][`unpark`] +//! method. [`park`] blocks the current thread, which can then be resumed from +//! another thread by calling the [`unpark`] method on the blocked thread's handle. //! //! Conceptually, each [`Thread`] handle has an associated token, which is //! initially not present: //! -//! * The [`thread::park()`][`park()`] function blocks the current thread unless or until +//! * The [`thread::park`][`park`] function blocks the current thread unless or until //! the token is available for its thread handle, at which point it atomically //! consumes the token. It may also return *spuriously*, without consuming the -//! token. [`thread::park_timeout()`] does the same, but allows specifying a +//! token. [`thread::park_timeout`] does the same, but allows specifying a //! maximum time to block the thread for. //! -//! * The [`unpark()`] method on a [`Thread`] atomically makes the token available +//! * The [`unpark`] method on a [`Thread`] atomically makes the token available //! if it wasn't already. //! //! In other words, each [`Thread`] acts a bit like a semaphore with initial count @@ -122,7 +122,7 @@ //! The API is typically used by acquiring a handle to the current thread, //! placing that handle in a shared data structure so that other threads can //! find it, and then `park`ing. When some desired condition is met, another -//! thread calls [`unpark()`] on the handle. +//! thread calls [`unpark`] on the handle. //! //! The motivation for this design is twofold: //! @@ -151,18 +151,18 @@ //! [`Arc`]: ../../std/sync/struct.Arc.html //! [`spawn`]: ../../std/thread/fn.spawn.html //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`thread()`]: ../../std/thread/struct.JoinHandle.html#method.thread +//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join //! [`Result`]: ../../std/result/enum.Result.html //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok //! [`Err`]: ../../std/result/enum.Result.html#variant.Err //! [`panic!`]: ../../std/macro.panic.html //! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`thread::current()`]: ../../std/thread/fn.spawn.html +//! [`thread::current`]: ../../std/thread/fn.spawn.html //! [`Thread`]: ../../std/thread/struct.Thread.html -//! [`park()`]: ../../std/thread/fn.park.html -//! [`unpark()`]: ../../std/thread/struct.Thread.html#method.unpark -//! [`thread::park_timeout()`]: ../../std/thread/fn.park_timeout.html +//! [`park`]: ../../std/thread/fn.park.html +//! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark +//! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html //! [`Cell`]: ../cell/struct.Cell.html //! [`RefCell`]: ../cell/struct.RefCell.html //! [`thread_local!`]: ../macro.thread_local.html @@ -547,7 +547,7 @@ pub fn sleep(dur: Duration) { /// Blocks unless or until the current thread's token is made available. /// /// Every thread is equipped with some basic low-level blocking support, via -/// the `park()` function and the [`unpark()`][unpark] method. These can be +/// the `park()` function and the [`unpark`][unpark] method. These can be /// used as a more CPU-efficient implementation of a spinlock. /// /// [unpark]: struct.Thread.html#method.unpark diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 4269ce8534bd0..682eec490bc65 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -49,10 +49,10 @@ pub use tables::UNICODE_VERSION; /// Returns an iterator that yields the lowercase equivalent of a `char`. /// -/// This `struct` is created by the [`to_lowercase()`] method on [`char`]. See +/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See /// its documentation for more. /// -/// [`to_lowercase()`]: ../../std/primitive.char.html#method.to_lowercase +/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase /// [`char`]: ../../std/primitive.char.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ToLowercase(CaseMappingIter); @@ -70,10 +70,10 @@ impl FusedIterator for ToLowercase {} /// Returns an iterator that yields the uppercase equivalent of a `char`. /// -/// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See +/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See /// its documentation for more. /// -/// [`to_uppercase()`]: ../../std/primitive.char.html#method.to_uppercase +/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase /// [`char`]: ../../std/primitive.char.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ToUppercase(CaseMappingIter); @@ -183,7 +183,7 @@ impl char { /// * `a-z` /// * `A-Z` /// - /// For a more comprehensive understanding of 'digit', see [`is_numeric()`][is_numeric]. + /// For a more comprehensive understanding of 'digit', see [`is_numeric`][is_numeric]. /// /// [is_numeric]: #method.is_numeric /// @@ -465,10 +465,10 @@ impl char { /// Returns the number of 16-bit code units this `char` would need if /// encoded in UTF-16. /// - /// See the documentation for [`len_utf8()`] for more explanation of this + /// See the documentation for [`len_utf8`] for more explanation of this /// concept. This function is a mirror, but for UTF-16 instead of UTF-8. /// - /// [`len_utf8()`]: #method.len_utf8 + /// [`len_utf8`]: #method.len_utf8 /// /// # Examples /// From 9ac628d5e84bd3664e41d53bafa3d66b303b19c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 12 Mar 2017 21:28:49 -0700 Subject: [PATCH 033/662] Add label to primary span for mutable access of immutable struct error --- src/librustc_borrowck/borrowck/mod.rs | 11 ++++++++--- src/test/ui/did_you_mean/issue-39544.stderr | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 073ebe24de924..1b44ba1ec617e 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -747,9 +747,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some((span, msg)) = immutable_field { db.span_label(span, &msg); } - if let Some(span) = local_def { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - db.span_label(span, &format!("consider changing this to `mut {}`", snippet)); + if let Some(let_span) = local_def { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet)); } } db @@ -1120,6 +1120,11 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ } else { db.span_label(*error_span, &format!("cannot borrow mutably")); } + } else if let Categorization::Interior(ref cmt, _) = err.cmt.cat { + if let mc::MutabilityCategory::McImmutable = cmt.mutbl { + db.span_label(*error_span, + &"cannot mutably borrow immutable field"); + } } } } diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index 3eb3e9a4c3b0a..7f124e6d34d35 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -4,7 +4,7 @@ error: cannot borrow immutable field `z.x` as mutable 20 | let z = Z { x: X::Y }; | - consider changing this to `mut z` 21 | let _ = &mut z.x; - | ^^^ + | ^^^ cannot mutably borrow immutable field error: aborting due to previous error From 6a2ef9a25f70afaaf32711063e93cf1b4d7f3713 Mon Sep 17 00:00:00 2001 From: Joshua Horwitz Date: Mon, 13 Mar 2017 23:12:54 -0400 Subject: [PATCH 034/662] clean up visuals on error index #40425 --- src/librustc_const_eval/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 9937cbbf8e10c..60eef8dd3bc5f 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -16,7 +16,7 @@ register_long_diagnostics! { E0001: r##" -## Note: this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. 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 @@ -43,7 +43,7 @@ arms. "##, E0002: r##" -## Note: this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. This error indicates that an empty match expression is invalid because the type it is matching on is non-empty (there exist values of this type). In safe code @@ -75,7 +75,7 @@ fn foo(x: Option) { "##, E0003: r##" -## Note: this error code is no longer emitted by the compiler. +#### Note: this error code is no longer emitted by the compiler. Not-a-Number (NaN) values cannot be compared for equality and hence can never match the input to a match expression. So, the following will not compile: From 460bf55f8a649a7f19680df2ac67dbeb936f8700 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 6 Mar 2017 06:45:28 +0000 Subject: [PATCH 035/662] Cleanup. --- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index b9cb3d82d4f7c..6385d206a0cb9 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -488,7 +488,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { - return token::NtTT(panictry!(p.parse_token_tree())); + return token::NtTT(p.parse_token_tree()); } _ => {} } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6446d38e5ef70..9872afd27b7bc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -891,7 +891,7 @@ impl<'a> Parser<'a> { self.parse_seq_to_before_tokens(kets, SeqSep::none(), - |p| p.parse_token_tree(), + |p| Ok(p.parse_token_tree()), |mut e| handler.cancel(&mut e)); } @@ -1267,7 +1267,7 @@ impl<'a> Parser<'a> { break; } token::OpenDelim(token::Brace) => { - self.parse_token_tree()?; + self.parse_token_tree(); break; } _ => self.bump(), @@ -2101,10 +2101,10 @@ impl<'a> Parser<'a> { fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, ThinTokenStream)> { match self.token { - token::OpenDelim(delim) => self.parse_token_tree().map(|tree| match tree { - TokenTree::Delimited(_, delimited) => (delim, delimited.stream().into()), + token::OpenDelim(delim) => match self.parse_token_tree() { + TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())), _ => unreachable!(), - }), + }, _ => Err(self.fatal("expected open delimiter")), } } @@ -2643,24 +2643,23 @@ impl<'a> Parser<'a> { } /// parse a single token tree from the input. - pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> { + pub fn parse_token_tree(&mut self) -> TokenTree { match self.token { token::OpenDelim(..) => { let frame = mem::replace(&mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap()); self.span = frame.span; self.bump(); - return Ok(TokenTree::Delimited(frame.span, Delimited { + TokenTree::Delimited(frame.span, Delimited { delim: frame.delim, tts: frame.tree_cursor.original_stream().into(), - })); + }) }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { let token = mem::replace(&mut self.token, token::Underscore); - let res = Ok(TokenTree::Token(self.span, token)); self.bump(); - res + TokenTree::Token(self.prev_span, token) } } } @@ -2670,7 +2669,7 @@ impl<'a> Parser<'a> { pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { let mut tts = Vec::new(); while self.token != token::Eof { - tts.push(self.parse_token_tree()?); + tts.push(self.parse_token_tree()); } Ok(tts) } From 68c1cc68b44bb987ec57251bc457a55292515d1d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 3 Mar 2017 09:23:59 +0000 Subject: [PATCH 036/662] Refactor `Attribute` to use `Path` and `TokenStream` instead of `MetaItem`. --- src/librustc/hir/check_attr.rs | 11 +- src/librustc/hir/lowering.rs | 2 +- src/librustc/lint/context.rs | 4 +- src/librustc/middle/stability.rs | 4 +- src/librustc/traits/error_reporting.rs | 2 +- .../calculate_svh/svh_visitor.rs | 55 +--- .../persist/dirty_clean.rs | 8 +- src/librustc_lint/builtin.rs | 8 +- src/librustc_lint/lib.rs | 1 + src/librustc_lint/unused.rs | 5 +- src/librustc_metadata/creader.rs | 8 +- src/librustc_metadata/cstore.rs | 9 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/lib.rs | 5 +- src/librustc_resolve/macros.rs | 43 ++- src/librustc_save_analysis/external_data.rs | 4 +- src/librustc_save_analysis/lib.rs | 5 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustdoc/clean/mod.rs | 21 +- src/librustdoc/html/render.rs | 4 +- src/librustdoc/test.rs | 14 +- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ast.rs | 9 +- src/libsyntax/attr.rs | 306 +++++++++++++++--- src/libsyntax/config.rs | 8 +- src/libsyntax/ext/derive.rs | 4 +- src/libsyntax/ext/expand.rs | 42 +-- src/libsyntax/ext/quote.rs | 14 +- src/libsyntax/feature_gate.rs | 28 +- src/libsyntax/fold.rs | 7 +- src/libsyntax/lib.rs | 10 + src/libsyntax/parse/attr.rs | 16 +- src/libsyntax/parse/mod.rs | 131 +++++--- src/libsyntax/parse/parser.rs | 44 +-- src/libsyntax/parse/token.rs | 4 +- src/libsyntax/print/pprust.rs | 100 +++--- src/libsyntax/std_inject.rs | 8 +- src/libsyntax/tokenstream.rs | 2 +- src/libsyntax_ext/deriving/custom.rs | 8 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/libsyntax_ext/proc_macro_registrar.rs | 12 +- 41 files changed, 614 insertions(+), 362 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 6f5f548aa7802..54ae947214091 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -120,11 +120,12 @@ impl<'a> CheckAttrVisitor<'a> { } fn check_attribute(&self, attr: &ast::Attribute, target: Target) { - let name: &str = &attr.name().as_str(); - match name { - "inline" => self.check_inline(attr, target), - "repr" => self.check_repr(attr, target), - _ => (), + if let Some(name) = attr.name() { + match &*name.as_str() { + "inline" => self.check_inline(attr, target), + "repr" => self.check_repr(attr, target), + _ => (), + } } } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index aa6614b0af4f7..a5c8213067550 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1277,7 +1277,7 @@ impl<'a> LoweringContext<'a> { let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); if let ItemKind::MacroDef(ref tts) = i.node { - if i.attrs.iter().any(|attr| attr.name() == "macro_export") { + if i.attrs.iter().any(|attr| attr.path == "macro_export") { self.exported_macros.push(hir::MacroDef { name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), }); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9279f24a57ab3..65e2fec0b8b09 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -402,14 +402,14 @@ pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec Vec> { let mut out = vec![]; - let level = match Level::from_str(&attr.name().as_str()) { + let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) { None => return out, Some(lvl) => lvl, }; + let meta = unwrap_or!(attr.meta(), return out); attr::mark_used(attr); - let meta = &attr.value; let metas = if let Some(metas) = meta.meta_item_list() { metas } else { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index baa22d7061435..1fb5371402574 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } else { // Emit errors for non-staged-api crates. for attr in attrs { - let tag = attr.name(); + let tag = unwrap_or!(attr.name(), continue); if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" { attr::mark_used(attr); self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \ @@ -402,7 +402,7 @@ impl<'a, 'tcx> Index<'tcx> { let mut is_staged_api = false; for attr in &krate.attrs { - if attr.name() == "stable" || attr.name() == "unstable" { + if attr.path == "stable" || attr.path == "unstable" { is_staged_api = true; break } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0e5c786cd8dcf..27525d550ff20 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .filter(|a| a.check_name("rustc_on_unimplemented")) .next() { - let err_sp = item.meta().span.substitute_dummy(span); + let err_sp = item.span.substitute_dummy(span); let trait_str = self.tcx.item_path_str(trait_ref.def_id); if let Some(istring) = item.value_str() { let istring = &*istring.as_str(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index d0eedcac0c06a..fac49b29598aa 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -18,16 +18,15 @@ use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::InternedString; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use syntax::tokenstream; use rustc::hir; use rustc::hir::*; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit as visit; +use rustc::hir::intravisit::{self as visit, Visitor}; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv; use std::hash::{Hash, Hasher}; use super::def_path_hash::DefPathHashes; @@ -559,7 +558,7 @@ macro_rules! hash_span { }); } -impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { +impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> { if self.hash_bodies { visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir) @@ -960,50 +959,24 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } } - fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) { - debug!("hash_meta_item: st={:?}", self.st); - - // ignoring span information, it doesn't matter here - self.hash_discriminant(&meta_item.node); - meta_item.name.as_str().len().hash(self.st); - meta_item.name.as_str().hash(self.st); - - match meta_item.node { - ast::MetaItemKind::Word => {} - ast::MetaItemKind::NameValue(ref lit) => saw_lit(lit).hash(self.st), - ast::MetaItemKind::List(ref items) => { - // Sort subitems so the hash does not depend on their order - let indices = self.indices_sorted_by(&items, |p| { - (p.name().map(Symbol::as_str), fnv::hash(&p.literal().map(saw_lit))) - }); - items.len().hash(self.st); - for (index, &item_index) in indices.iter().enumerate() { - index.hash(self.st); - let nested_meta_item: &ast::NestedMetaItemKind = &items[item_index].node; - self.hash_discriminant(nested_meta_item); - match *nested_meta_item { - ast::NestedMetaItemKind::MetaItem(ref meta_item) => { - self.hash_meta_item(meta_item); - } - ast::NestedMetaItemKind::Literal(ref lit) => { - saw_lit(lit).hash(self.st); - } - } - } - } - } - } - pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { debug!("hash_attributes: st={:?}", self.st); let indices = self.indices_sorted_by(attributes, |attr| attr.name()); for i in indices { let attr = &attributes[i]; - if !attr.is_sugared_doc && - !IGNORED_ATTRIBUTES.contains(&&*attr.value.name().as_str()) { + match attr.name() { + Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue, + _ => {} + }; + if !attr.is_sugared_doc { SawAttribute(attr.style).hash(self.st); - self.hash_meta_item(&attr.value); + for segment in &attr.path.segments { + SawIdent(segment.identifier.name.as_str()).hash(self.st); + } + for tt in attr.tokens.trees() { + self.hash_token_tree(&tt); + } } } } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 156f8b9e7c489..929249df0b173 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -104,9 +104,9 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> { impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode { - for item in attr.meta_item_list().unwrap_or(&[]) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(LABEL) { - let value = expect_associated_value(self.tcx, item); + let value = expect_associated_value(self.tcx, &item); match DepNode::from_label_string(&value.as_str(), def_id) { Ok(def_id) => return def_id, Err(()) => { @@ -331,9 +331,9 @@ fn check_config(tcx: TyCtxt, attr: &Attribute) -> bool { debug!("check_config(attr={:?})", attr); let config = &tcx.sess.parse_sess.config; debug!("check_config: config={:?}", config); - for item in attr.meta_item_list().unwrap_or(&[]) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(CFG) { - let value = expect_associated_value(tcx, item); + let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); return config.contains(&(value, None)); } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 58336f939d122..f0276f90f274d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -312,7 +312,7 @@ impl MissingDoc { } } - let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); + let has_doc = attrs.iter().any(|a| a.is_value_str() && a.check_name("doc")); if !has_doc { cx.span_lint(MISSING_DOCS, sp, @@ -635,7 +635,7 @@ impl LintPass for DeprecatedAttr { impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) { - let name = attr.name(); + let name = unwrap_or!(attr.name(), return); for &&(n, _, ref g) in &self.depr_attrs { if name == n { if let &AttributeGate::Gated(Stability::Deprecated(link), @@ -1121,8 +1121,8 @@ impl LintPass for UnstableFeatures { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { - if attr.meta().check_name("feature") { - if let Some(items) = attr.meta().meta_item_list() { + if attr.check_name("feature") { + if let Some(items) = attr.meta_item_list() { for item in items { ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 443a219928f1c..05dbbc0987025 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -38,6 +38,7 @@ #![feature(slice_patterns)] #![feature(staged_api)] +#[macro_use] extern crate syntax; #[macro_use] extern crate rustc; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f9b7c68587678..abba8afd9da86 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -269,6 +269,7 @@ impl LintPass for UnusedAttributes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { debug!("checking attribute: {:?}", attr); + let name = unwrap_or!(attr.name(), return); // Note that check_name() marks the attribute as used if it matches. for &(ref name, ty, _) in BUILTIN_ATTRIBUTES { @@ -294,13 +295,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? let known_crate = BUILTIN_ATTRIBUTES.iter() - .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel) + .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel) .is_some(); // Has a plugin registered this attribute as one which must be used at // the crate level? let plugin_crate = plugin_attributes.iter() - .find(|&&(ref x, t)| attr.name() == &**x && AttributeType::CrateLevel == t) + .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t) .is_some(); if known_crate || plugin_crate { let msg = match attr.style { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 49dcffb4830a1..9f5ce00f40812 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -973,9 +973,11 @@ impl<'a> CrateLoader<'a> { impl<'a> CrateLoader<'a> { pub fn preprocess(&mut self, krate: &ast::Crate) { - for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") { - if let Some(linkarg) = attr.value_str() { - self.cstore.add_used_link_args(&linkarg.as_str()); + for attr in &krate.attrs { + if attr.path == "link_args" { + if let Some(linkarg) = attr.value_str() { + self.cstore.add_used_link_args(&linkarg.as_str()); + } } } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index bb30245df5f56..17a6a706e0aaa 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -269,9 +269,12 @@ impl CrateMetadata { } pub fn is_staged_api(&self) -> bool { - self.get_item_attrs(CRATE_DEF_INDEX) - .iter() - .any(|attr| attr.name() == "stable" || attr.name() == "unstable") + for attr in self.get_item_attrs(CRATE_DEF_INDEX) { + if attr.path == "stable" || attr.path == "unstable" { + return true; + } + } + false } pub fn is_allocator(&self) -> bool { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 0933fdfd357cd..8c45a66694533 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -241,12 +241,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); - if let Some(attr) = - item.attrs.iter().find(|attr| attr.name() == "warn_directory_ownership") { + if item.attrs.iter().any(|attr| attr.check_name("warn_directory_ownership")) { let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP; let msg = "cannot declare a new module at this location"; self.session.add_lint(lint, item.id, item.span, msg.to_string()); - attr::mark_used(attr); } } ItemKind::Union(ref vdata, _) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0958748ed092f..c3e471650a3e1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3360,8 +3360,9 @@ impl<'a> Resolver<'a> { if self.proc_macro_enabled { return; } for attr in attrs { - let maybe_binding = self.builtin_macros.get(&attr.name()).cloned().or_else(|| { - let ident = Ident::with_empty_ctxt(attr.name()); + let name = unwrap_or!(attr.name(), continue); + let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| { + let ident = Ident::with_empty_ctxt(name); self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok() }); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7ad122d1c31d8..9e1dcd1bc35c4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -30,6 +30,7 @@ use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; +use syntax::tokenstream::TokenStream; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; @@ -176,12 +177,14 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { + let name = unwrap_or!(attrs[i].name(), continue); + if self.session.plugin_attributes.borrow().iter() - .any(|&(ref attr_nm, _)| attrs[i].name() == &**attr_nm) { + .any(|&(ref attr_nm, _)| name == &**attr_nm) { attr::mark_known(&attrs[i]); } - match self.builtin_macros.get(&attrs[i].name()).cloned() { + match self.builtin_macros.get(&name).cloned() { Some(binding) => match *binding.get_macro(self) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -194,9 +197,11 @@ impl<'a> base::Resolver for Resolver<'a> { // Check for legacy derives for i in 0..attrs.len() { - if attrs[i].name() == "derive" { + let name = unwrap_or!(attrs[i].name(), continue); + + if name == "derive" { let mut traits = match attrs[i].meta_item_list() { - Some(traits) if !traits.is_empty() => traits.to_owned(), + Some(traits) => traits, _ => continue, }; @@ -213,18 +218,11 @@ impl<'a> base::Resolver for Resolver<'a> { if traits.is_empty() { attrs.remove(i); } else { - attrs[i].value = ast::MetaItem { - name: attrs[i].name(), - span: attrs[i].span, - node: ast::MetaItemKind::List(traits), - }; + attrs[i].tokens = ast::MetaItemKind::List(traits).tokens(attrs[i].span); } return Some(ast::Attribute { - value: ast::MetaItem { - name: legacy_name, - span: span, - node: ast::MetaItemKind::Word, - }, + path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)), + tokens: TokenStream::empty(), id: attr::mk_attr_id(), style: ast::AttrStyle::Outer, is_sugared_doc: false, @@ -270,19 +268,20 @@ impl<'a> Resolver<'a> { } }; - let (attr_name, path) = { - let attr = attr.as_ref().unwrap(); - (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) - }; - let mut determined = true; + let path = attr.as_ref().unwrap().path.clone(); + let mut determinacy = Determinacy::Determined; match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { Ok(def) => return Ok(def), - Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), Err(Determinacy::Determined) => {} } + let attr_name = match path.segments.len() { + 1 => path.segments[0].identifier.name, + _ => return Err(determinacy), + }; for &(name, span) in traits { let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); match self.resolve_macro(scope, &path, MacroKind::Derive, force) { @@ -304,12 +303,12 @@ impl<'a> Resolver<'a> { } return Err(Determinacy::Undetermined); }, - Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, Err(Determinacy::Determined) => {} } } - Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) + Err(determinacy) } fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 41658dc5b1b48..f038c2dc298ad 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -14,7 +14,6 @@ use rustc::ty::TyCtxt; use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; use syntax::print::pprust; -use syntax::symbol::Symbol; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -77,10 +76,9 @@ impl Lower for Vec { type Target = Vec; fn lower(self, tcx: TyCtxt) -> Vec { - let doc = Symbol::intern("doc"); self.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.name() != doc) + .filter(|attr| attr.path != "doc") .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 111c8370be2b1..90ee19198c939 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -54,7 +54,7 @@ use std::path::{Path, PathBuf}; use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::parse::token; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; use syntax::codemap::MacroAttribute; @@ -829,11 +829,10 @@ impl<'a> Visitor<'a> for PathCollector { } fn docs_for_attrs(attrs: &[Attribute]) -> String { - let doc = Symbol::intern("doc"); let mut result = String::new(); for attr in attrs { - if attr.name() == doc { + if attr.check_name("doc") { if let Some(val) = attr.value_str() { if attr.is_sugared_doc { result.push_str(&strip_doc_comment_decoration(&val.as_str())); diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 7a41f8341099b..8528482c7856c 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { } fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name { - for item in attr.meta_item_list().unwrap_or(&[]) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(name) { if let Some(value) = item.value_str() { return value; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1294296840ebd..660fa647882aa 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,12 +39,11 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc::hir; +use std::{mem, slice, vec}; use std::path::PathBuf; use std::rc::Rc; -use std::slice; use std::sync::Arc; use std::u32; -use std::mem; use core::DocContext; use doctree; @@ -472,12 +471,12 @@ impl Clean for doctree::Module { pub struct ListAttributesIter<'a> { attrs: slice::Iter<'a, ast::Attribute>, - current_list: slice::Iter<'a, ast::NestedMetaItem>, + current_list: vec::IntoIter, name: &'a str } impl<'a> Iterator for ListAttributesIter<'a> { - type Item = &'a ast::NestedMetaItem; + type Item = ast::NestedMetaItem; fn next(&mut self) -> Option { if let Some(nested) = self.current_list.next() { @@ -485,9 +484,9 @@ impl<'a> Iterator for ListAttributesIter<'a> { } for attr in &mut self.attrs { - if let Some(ref list) = attr.meta_item_list() { + if let Some(list) = attr.meta_item_list() { if attr.check_name(self.name) { - self.current_list = list.iter(); + self.current_list = list.into_iter(); if let Some(nested) = self.current_list.next() { return Some(nested); } @@ -508,7 +507,7 @@ impl AttributesExt for [ast::Attribute] { fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { ListAttributesIter { attrs: self.iter(), - current_list: [].iter(), + current_list: Vec::new().into_iter(), name: name } } @@ -519,7 +518,7 @@ pub trait NestedAttributesExt { fn has_word(self, &str) -> bool; } -impl<'a, I: IntoIterator> NestedAttributesExt for I { +impl> NestedAttributesExt for I { fn has_word(self, word: &str) -> bool { self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) } @@ -2596,9 +2595,9 @@ impl Clean> for doctree::Import { // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let denied = self.vis != hir::Public || self.attrs.iter().any(|a| { - a.name() == "doc" && match a.meta_item_list() { - Some(l) => attr::list_contains_name(l, "no_inline") || - attr::list_contains_name(l, "hidden"), + a.name().unwrap() == "doc" && match a.meta_item_list() { + Some(l) => attr::list_contains_name(&l, "no_inline") || + attr::list_contains_name(&l, "hidden"), None => false, } }); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 44f71d8952985..130a4526bf705 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2620,11 +2620,11 @@ fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { let mut attrs = String::new(); for attr in &it.attrs.other_attrs { - let name = attr.name(); + let name = attr.name().unwrap(); if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) { continue; } - if let Some(s) = render_attribute(attr.meta()) { + if let Some(s) = render_attribute(&attr.meta().unwrap()) { attrs.push_str(&format!("#[{}]\n", s)); } } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index c1ecc241b7b63..f6b7a07bdae01 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -137,13 +137,13 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { attrs: Vec::new(), }; - let attrs = krate.attrs.iter() - .filter(|a| a.check_name("doc")) - .filter_map(|a| a.meta_item_list()) - .flat_map(|l| l) - .filter(|a| a.check_name("test")) - .filter_map(|a| a.meta_item_list()) - .flat_map(|l| l); + let test_attrs: Vec<_> = krate.attrs.iter() + .filter(|a| a.check_name("doc")) + .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new)) + .filter(|a| a.check_name("test")) + .collect(); + let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[])); + for attr in attrs { if attr.check_name("no_crate_inject") { opts.no_crate_inject = true; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b80de3cc50546..4a909f8e2a972 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -376,7 +376,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if item.vis == hir::Public && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(list) if item.check_name("doc") => { + Some(ref list) if item.check_name("doc") => { list.iter().any(|i| i.check_name("inline")) } _ => false, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 981667337d59a..5deb91ef53aeb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -116,6 +116,12 @@ pub struct Path { pub segments: Vec, } +impl<'a> PartialEq<&'a str> for Path { + fn eq(&self, string: &&'a str) -> bool { + self.segments.len() == 1 && self.segments[0].identifier.name == *string + } +} + impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "path({})", pprust::path_to_string(self)) @@ -1679,7 +1685,8 @@ pub struct AttrId(pub usize); pub struct Attribute { pub id: AttrId, pub style: AttrStyle, - pub value: MetaItem, + pub path: Path, + pub tokens: TokenStream, pub is_sugared_doc: bool, pub span: Span, } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 096657a6e7ac8..68f1f690a62f0 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -15,20 +15,24 @@ pub use self::ReprAttr::*; pub use self::IntType::*; use ast; -use ast::{AttrId, Attribute, Name}; +use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use ast::{Lit, Expr, Item, Local, Stmt, StmtKind}; +use ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind}; use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use parse::ParseSess; +use parse::parser::Parser; +use parse::{self, ParseSess, PResult}; +use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; +use tokenstream::{TokenStream, TokenTree, Delimited}; use util::ThinVec; use std::cell::{RefCell, Cell}; +use std::iter; thread_local! { static USED_ATTRS: RefCell> = RefCell::new(Vec::new()); @@ -185,26 +189,38 @@ impl NestedMetaItem { impl Attribute { pub fn check_name(&self, name: &str) -> bool { - let matches = self.name() == name; + let matches = self.path == name; if matches { mark_used(self); } matches } - pub fn name(&self) -> Name { self.meta().name() } + pub fn name(&self) -> Option { + match self.path.segments.len() { + 1 => Some(self.path.segments[0].identifier.name), + _ => None, + } + } pub fn value_str(&self) -> Option { - self.meta().value_str() + self.meta().and_then(|meta| meta.value_str()) } - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - self.meta().meta_item_list() + pub fn meta_item_list(&self) -> Option> { + match self.meta() { + Some(MetaItem { node: MetaItemKind::List(list), .. }) => Some(list), + _ => None + } } - pub fn is_word(&self) -> bool { self.meta().is_word() } + pub fn is_word(&self) -> bool { + self.path.segments.len() == 1 && self.tokens.is_empty() + } - pub fn span(&self) -> Span { self.meta().span } + pub fn span(&self) -> Span { + self.span + } pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() @@ -225,7 +241,7 @@ impl MetaItem { match self.node { MetaItemKind::NameValue(ref v) => { match v.node { - ast::LitKind::Str(ref s, _) => Some((*s).clone()), + LitKind::Str(ref s, _) => Some((*s).clone()), _ => None, } }, @@ -264,8 +280,35 @@ impl MetaItem { impl Attribute { /// Extract the MetaItem from inside this Attribute. - pub fn meta(&self) -> &MetaItem { - &self.value + pub fn meta(&self) -> Option { + let mut tokens = self.tokens.trees().peekable(); + Some(MetaItem { + name: match self.path.segments.len() { + 1 => self.path.segments[0].identifier.name, + _ => return None, + }, + node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { + if tokens.peek().is_some() { + return None; + } + node + } else { + return None; + }, + span: self.span, + }) + } + + pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { + if self.path.segments.len() > 1 { + sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); + } + + Ok(MetaItem { + name: self.path.segments.last().unwrap().identifier.name, + node: Parser::new(sess, self.tokens.clone(), None, false).parse_meta_item_kind()?, + span: self.span, + }) } /// Convert self to a normal #[doc="foo"] comment, if it is a @@ -293,7 +336,7 @@ impl Attribute { /* Constructors */ pub fn mk_name_value_item_str(name: Name, value: Symbol) -> MetaItem { - let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked)); + let value_lit = dummy_spanned(LitKind::Str(value, ast::StrStyle::Cooked)); mk_spanned_name_value_item(DUMMY_SP, name, value_lit) } @@ -348,7 +391,8 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id: id, style: ast::AttrStyle::Inner, - value: item, + path: ast::Path::from_ident(item.span, ast::Ident::with_empty_ctxt(item.name)), + tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, } @@ -365,7 +409,8 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id: id, style: ast::AttrStyle::Outer, - value: item, + path: ast::Path::from_ident(item.span, ast::Ident::with_empty_ctxt(item.name)), + tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, } @@ -374,32 +419,25 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos) -> Attribute { let style = doc_comment_style(&text.as_str()); - let lit = spanned(lo, hi, ast::LitKind::Str(text, ast::StrStyle::Cooked)); + let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked)); Attribute { id: id, style: style, - value: MetaItem { - span: mk_sp(lo, hi), - name: Symbol::intern("doc"), - node: MetaItemKind::NameValue(lit), - }, + path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")), + tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)), is_sugared_doc: true, span: mk_sp(lo, hi), } } pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { - debug!("attr::list_contains_name (name={})", name); items.iter().any(|item| { - debug!(" testing: {:?}", item.name()); item.check_name(name) }) } pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { - debug!("attr::contains_name (name={})", name); attrs.iter().any(|item| { - debug!(" testing: {}", item.name()); item.check_name(name) }) } @@ -452,8 +490,14 @@ pub enum InlineAttr { /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr { attrs.iter().fold(InlineAttr::None, |ia, attr| { - match attr.value.node { - _ if attr.value.name != "inline" => ia, + if attr.path != "inline" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { MetaItemKind::Word => { mark_used(attr); InlineAttr::Hint @@ -574,14 +618,15 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut rustc_depr: Option = None; 'outer: for attr in attrs_iter { - let tag = attr.name(); - if tag != "rustc_deprecated" && tag != "unstable" && tag != "stable" { + if attr.path != "rustc_deprecated" && attr.path != "unstable" && attr.path != "stable" { continue // not a stability level } mark_used(attr); - if let Some(metas) = attr.meta_item_list() { + let meta = attr.meta(); + if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { + let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); @@ -596,7 +641,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } }; - match &*tag.as_str() { + match &*meta.name.as_str() { "rustc_deprecated" => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, @@ -772,7 +817,7 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut depr: Option = None; 'outer: for attr in attrs_iter { - if attr.name() != "deprecated" { + if attr.path != "deprecated" { continue } @@ -847,8 +892,8 @@ pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], /// structure layout, and `packed` to remove padding. pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec { let mut acc = Vec::new(); - match attr.value.node { - ast::MetaItemKind::List(ref items) if attr.value.name == "repr" => { + if attr.path == "repr" { + if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { if !item.is_meta_item() { @@ -883,8 +928,6 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec } } } - // Not a "repr" hint: ignore. - _ => { } } acc } @@ -931,6 +974,195 @@ impl IntType { } } +impl MetaItem { + fn tokens(&self) -> TokenStream { + let ident = TokenTree::Token(self.span, Token::Ident(Ident::with_empty_ctxt(self.name))); + TokenStream::concat(vec![ident.into(), self.node.tokens(self.span)]) + } + + fn from_tokens(tokens: &mut iter::Peekable) -> Option + where I: Iterator, + { + let (mut span, name) = match tokens.next() { + Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), + _ => return None, + }; + let node = match MetaItemKind::from_tokens(tokens) { + Some(node) => node, + _ => return None, + }; + if let Some(last_span) = node.last_span() { + span.hi = last_span.hi; + } + Some(MetaItem { name: name, span: span, node: node }) + } +} + +impl MetaItemKind { + fn last_span(&self) -> Option { + match *self { + MetaItemKind::Word => None, + MetaItemKind::List(ref list) => list.last().map(NestedMetaItem::span), + MetaItemKind::NameValue(ref lit) => Some(lit.span), + } + } + + pub fn tokens(&self, span: Span) -> TokenStream { + match *self { + MetaItemKind::Word => TokenStream::empty(), + MetaItemKind::NameValue(ref lit) => { + TokenStream::concat(vec![TokenTree::Token(span, Token::Eq).into(), lit.tokens()]) + } + MetaItemKind::List(ref list) => { + let mut tokens = Vec::new(); + for (i, item) in list.iter().enumerate() { + if i > 0 { + tokens.push(TokenTree::Token(span, Token::Comma).into()); + } + tokens.push(item.node.tokens()); + } + TokenTree::Delimited(span, Delimited { + delim: token::Paren, + tts: TokenStream::concat(tokens).into(), + }).into() + } + } + } + + fn from_tokens(tokens: &mut iter::Peekable) -> Option + where I: Iterator, + { + let delimited = match tokens.peek().cloned() { + Some(TokenTree::Token(_, token::Eq)) => { + tokens.next(); + return if let Some(TokenTree::Token(span, token)) = tokens.next() { + LitKind::from_token(token) + .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span })) + } else { + None + }; + } + Some(TokenTree::Delimited(_, ref delimited)) if delimited.delim == token::Paren => { + tokens.next(); + delimited.stream() + } + _ => return Some(MetaItemKind::Word), + }; + + let mut tokens = delimited.into_trees().peekable(); + let mut result = Vec::new(); + while let Some(..) = tokens.peek() { + match NestedMetaItemKind::from_tokens(&mut tokens) { + Some(item) => result.push(Spanned { span: item.span(), node: item }), + None => return None, + } + match tokens.next() { + None | Some(TokenTree::Token(_, Token::Comma)) => {} + _ => return None, + } + } + Some(MetaItemKind::List(result)) + } +} + +impl NestedMetaItemKind { + fn span(&self) -> Span { + match *self { + NestedMetaItemKind::MetaItem(ref item) => item.span, + NestedMetaItemKind::Literal(ref lit) => lit.span, + } + } + + fn tokens(&self) -> TokenStream { + match *self { + NestedMetaItemKind::MetaItem(ref item) => item.tokens(), + NestedMetaItemKind::Literal(ref lit) => lit.tokens(), + } + } + + fn from_tokens(tokens: &mut iter::Peekable) -> Option + where I: Iterator, + { + if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() { + if let Some(node) = LitKind::from_token(token) { + tokens.next(); + return Some(NestedMetaItemKind::Literal(Spanned { node: node, span: span })); + } + } + + MetaItem::from_tokens(tokens).map(NestedMetaItemKind::MetaItem) + } +} + +impl Lit { + fn tokens(&self) -> TokenStream { + TokenTree::Token(self.span, self.node.token()).into() + } +} + +impl LitKind { + fn token(&self) -> Token { + use std::ascii; + + match *self { + LitKind::Str(string, ast::StrStyle::Cooked) => { + let mut escaped = String::new(); + for ch in string.as_str().chars() { + escaped.extend(ch.escape_unicode()); + } + Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None) + } + LitKind::Str(string, ast::StrStyle::Raw(n)) => { + Token::Literal(token::Lit::StrRaw(string, n), None) + } + LitKind::ByteStr(ref bytes) => { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::::into).collect::(); + Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None) + } + LitKind::Byte(byte) => { + let string: String = ascii::escape_default(byte).map(Into::::into).collect(); + Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None) + } + LitKind::Char(ch) => { + let string: String = ch.escape_default().map(Into::::into).collect(); + Token::Literal(token::Lit::Char(Symbol::intern(&string)), None) + } + LitKind::Int(n, ty) => { + let suffix = match ty { + ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Unsuffixed => None, + }; + Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix) + } + LitKind::Float(symbol, ty) => { + Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string()))) + } + LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None), + LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(match value { + true => "true", + false => "false", + }))), + } + } + + fn from_token(token: Token) -> Option { + match token { + Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)), + Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)), + Token::Literal(lit, suf) => { + let (suffix_illegal, result) = parse::lit_token(lit, suf, None); + if suffix_illegal && suf.is_some() { + return None; + } + result + } + _ => None, + } + } +} + pub trait HasAttrs: Sized { fn attrs(&self) -> &[ast::Attribute]; fn map_attrs) -> Vec>(self, f: F) -> Self; diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ea12a31770fc0..2591a5766693f 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -109,7 +109,8 @@ impl<'a> StripUnconfigured<'a> { self.process_cfg_attr(ast::Attribute { id: attr::mk_attr_id(), style: attr.style, - value: mi.clone(), + path: ast::Path::from_ident(mi.span, ast::Ident::with_empty_ctxt(mi.name)), + tokens: mi.node.tokens(mi.span), is_sugared_doc: false, span: mi.span, }) @@ -132,8 +133,9 @@ impl<'a> StripUnconfigured<'a> { return false; } - let mis = match attr.value.node { - ast::MetaItemKind::List(ref mis) if is_cfg(&attr) => mis, + let mis = attr.meta_item_list(); + let mis = match mis { + Some(ref mis) if is_cfg(&attr) => mis, _ => return true }; diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 77cc7bab0315a..5b253635f257e 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -18,7 +18,7 @@ use syntax_pos::Span; pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec<(Symbol, Span)> { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.name() != "derive" { + if attr.path != "derive" { return true; } @@ -27,7 +27,7 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec return false; } - let traits = attr.meta_item_list().unwrap_or(&[]).to_owned(); + let traits = attr.meta_item_list().unwrap_or_else(Vec::new); if traits.is_empty() { cx.span_warn(attr.span, "empty trait list in `derive`"); return false; diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 10168f010a077..c1095d3445682 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -272,7 +272,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.collect_invocations(expansion, &[]) } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { let item = item - .map_attrs(|mut attrs| { attrs.retain(|a| a.name() != "derive"); attrs }); + .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = add_derived_markers(&mut self.cx, &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); @@ -380,7 +380,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - let name = attr.name(); + let name = attr.path.segments[0].identifier.name; self.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { @@ -392,25 +392,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> { match *ext { MultiModifier(ref mac) => { - let item = mac.expand(self.cx, attr.span, &attr.value, item); + let meta = panictry!(attr.parse_meta(&self.cx.parse_sess)); + let item = mac.expand(self.cx, attr.span, &meta, item); kind.expect_from_annotatables(item) } MultiDecorator(ref mac) => { let mut items = Vec::new(); - mac.expand(self.cx, attr.span, &attr.value, &item, - &mut |item| items.push(item)); + let meta = panictry!(attr.parse_meta(&self.cx.parse_sess)); + mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); items.push(item); kind.expect_from_annotatables(items) } SyntaxExtension::AttrProcMacro(ref mac) => { - let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess); let item_toks = stream_for_item(&item, &self.cx.parse_sess); let span = Span { expn_id: self.cx.codemap().record_expansion(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - format: MacroAttribute(name), + format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), span: None, allow_internal_unstable: false, }, @@ -418,7 +418,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ..attr.span }; - let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); + let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); self.parse_expansion(tok_result, kind, name, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { @@ -784,32 +784,6 @@ fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream { string_to_stream(text, parse_sess) } -fn stream_for_attr_args(attr: &ast::Attribute, parse_sess: &ParseSess) -> TokenStream { - use ast::MetaItemKind::*; - use print::pp::Breaks; - use print::pprust::PrintState; - - let token_string = match attr.value.node { - // For `#[foo]`, an empty token - Word => return TokenStream::empty(), - // For `#[foo(bar, baz)]`, returns `(bar, baz)` - List(ref items) => pprust::to_string(|s| { - s.popen()?; - s.commasep(Breaks::Consistent, - &items[..], - |s, i| s.print_meta_list_item(&i))?; - s.pclose() - }), - // For `#[foo = "bar"]`, returns `= "bar"` - NameValue(ref lit) => pprust::to_string(|s| { - s.word_space("=")?; - s.print_literal(lit) - }), - }; - - string_to_stream(token_string, parse_sess) -} - fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream { let filename = String::from(""); filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, None, text)) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 69ff726e719a9..10b7249743b8c 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -220,16 +220,24 @@ pub mod rt { } impl ToTokens for ast::Attribute { - fn to_tokens(&self, cx: &ExtCtxt) -> Vec { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { let mut r = vec![]; // FIXME: The spans could be better r.push(TokenTree::Token(self.span, token::Pound)); if self.style == ast::AttrStyle::Inner { r.push(TokenTree::Token(self.span, token::Not)); } + let mut inner = Vec::new(); + for (i, segment) in self.path.segments.iter().enumerate() { + if i > 0 { + inner.push(TokenTree::Token(self.span, token::Colon).into()); + } + inner.push(TokenTree::Token(self.span, token::Ident(segment.identifier)).into()); + } + inner.push(self.tokens.clone()); + r.push(TokenTree::Delimited(self.span, tokenstream::Delimited { - delim: token::Bracket, - tts: self.value.to_tokens(cx).into_iter().collect::().into(), + delim: token::Bracket, tts: TokenStream::concat(inner).into() })); r } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7bf16eae9ee6..2c3ad98a6be63 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -859,35 +859,34 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = &*attr.name().as_str(); + let name = unwrap_or!(attr.name(), return); + for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { - if n == name { + if name == n { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { gate_feature_fn!(self, has_feature, attr.span, name, desc); } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage); + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); return; } } for &(ref n, ref ty) in self.plugin_attributes { - if n == name { + if attr.path == &**n { // Plugins can't gate attributes, so we don't check for it // unlike the code above; we only use this loop to // short-circuit to avoid the checks below - debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty); + debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); return; } } - if name.starts_with("rustc_") { + if name.as_str().starts_with("rustc_") { gate_feature!(self, rustc_attrs, attr.span, "unless otherwise specified, attributes \ with the prefix `rustc_` \ are reserved for internal compiler diagnostics"); - } else if name.starts_with("derive_") { + } else if name.as_str().starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); - } else if attr::is_known(attr) { - debug!("check_attribute: {:?} is known", name); - } else { + } else if !attr::is_known(attr) { // Only run the custom attribute lint during regular // feature gate checking. Macro gating runs // before the plugin attributes are registered @@ -898,7 +897,7 @@ impl<'a> Context<'a> { unknown to the compiler and \ may have meaning \ added to it in the future", - name)); + attr.path)); } } } @@ -1097,7 +1096,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { self.context.check_attribute(attr, false); } - if contains_novel_literal(&attr.value) { + let meta = panictry!(attr.parse_meta(&self.context.parse_sess)); + if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, "non-string literals in attributes, or string \ literals in top-level positions, are experimental"); @@ -1160,8 +1160,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { `#[repr(simd)]` instead"); } for attr in &i.attrs { - if attr.name() == "repr" { - for item in attr.meta_item_list().unwrap_or(&[]) { + if attr.path == "repr" { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name("simd") { gate_feature_post!(&self, repr_simd, i.span, "SIMD types are experimental \ diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb4eb19be2b15..903dac1f379ca 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -488,7 +488,8 @@ pub fn noop_fold_attribute(attr: Attribute, fld: &mut T) -> Option(nt: token::Nonterminal, fld: &mut T) token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(id) => token::NtIdent(Spanned::{node: fld.fold_ident(id.node), ..id}), - token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), + token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)), token::NtPath(path) => token::NtPath(fld.fold_path(path)), token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)), token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)), @@ -1369,7 +1370,7 @@ mod tests { matches_codepattern, "matches_codepattern", pprust::to_string(|s| fake_print_crate(s, &folded_crate)), - "#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); + "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); } // even inside macro defs.... diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 39a9aff48bf27..4c9a5d512af02 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -65,6 +65,16 @@ macro_rules! panictry { }) } +#[macro_export] +macro_rules! unwrap_or { + ($opt:expr, $default:expr) => { + match $opt { + Some(x) => x, + None => $default, + } + } +} + #[macro_use] pub mod diagnostics { #[macro_use] diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index ded676da3c676..272cff7ad34b2 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -143,7 +143,8 @@ impl<'a> Parser<'a> { Ok(ast::Attribute { id: attr::mk_attr_id(), style: style, - value: value, + path: ast::Path::from_ident(value.span, ast::Ident::with_empty_ctxt(value.name)), + tokens: value.node.tokens(value.span), is_sugared_doc: false, span: span, }) @@ -221,15 +222,20 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let ident = self.parse_ident()?; - let node = if self.eat(&token::Eq) { + let node = self.parse_meta_item_kind()?; + let hi = self.prev_span.hi; + Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + } + + pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { + Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) } else if self.token == token::OpenDelim(token::Paren) { ast::MetaItemKind::List(self.parse_meta_seq()?) } else { + self.eat(&token::OpenDelim(token::Paren)); ast::MetaItemKind::Word - }; - let hi = self.prev_span.hi; - Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + }) } /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b42..2bdd3938d6bd5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -374,38 +374,80 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s[1..].chars().all(|c| '0' <= c && c <= '9') } -fn filtered_float_lit(data: Symbol, suffix: Option, sd: &Handler, sp: Span) - -> ast::LitKind { +macro_rules! err { + ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { + match $opt_diag { + Some(($span, $diag)) => { $($body)* } + None => return None, + } + } +} + +pub fn lit_token(lit: token::Lit, suf: Option, diag: Option<(Span, &Handler)>) + -> (bool /* suffix illegal? */, Option) { + use ast::LitKind; + + match lit { + token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), + token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str()).0))), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), + token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), + + token::Str_(s) => { + let s = Symbol::intern(&str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Cooked))) + } + token::StrRaw(s, n) => { + let s = Symbol::intern(&raw_str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Raw(n)))) + } + token::ByteStr(i) => { + (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) + } + token::ByteStrRaw(i, _) => { + (true, Some(LitKind::ByteStr(Rc::new(i.to_string().into_bytes())))) + } + } +} + +fn filtered_float_lit(data: Symbol, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { debug!("filtered_float_lit: {}, {:?}", data, suffix); let suffix = match suffix { Some(suffix) => suffix, - None => return ast::LitKind::FloatUnsuffixed(data), + None => return Some(ast::LitKind::FloatUnsuffixed(data)), }; - match &*suffix.as_str() { + Some(match &*suffix.as_str() { "f32" => ast::LitKind::Float(data, ast::FloatTy::F32), "f64" => ast::LitKind::Float(data, ast::FloatTy::F64), suf => { - if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { - // if it looks like a width, lets try to be helpful. - sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) - .help("valid widths are 32 and 64") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } + err!(diag, |span, diag| { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + diag.struct_span_err(span, &msg) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + }); ast::LitKind::FloatUnsuffixed(data) } - } + }) } -pub fn float_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn float_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { debug!("float_lit: {:?}, {:?}", s, suffix); // FIXME #2252: bounds checking float literals is deferred until trans let s = s.chars().filter(|&c| c != '_').collect::(); - filtered_float_lit(Symbol::intern(&s), suffix, sd, sp) + filtered_float_lit(Symbol::intern(&s), suffix, diag) } /// Parse a string representing a byte literal into its final form. Similar to `char_lit` @@ -500,7 +542,8 @@ pub fn byte_str_lit(lit: &str) -> Rc> { Rc::new(res) } -pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { // s can only be ascii, byte indexing is fine let s2 = s.chars().filter(|&c| c != '_').collect::(); @@ -524,13 +567,16 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a // 1f64 and 2f32 etc. are valid float literals. if let Some(suf) = suffix { if looks_like_width_suffix(&['f'], &suf.as_str()) { - match base { - 16 => sd.span_err(sp, "hexadecimal float literal is not supported"), - 8 => sd.span_err(sp, "octal float literal is not supported"), - 2 => sd.span_err(sp, "binary float literal is not supported"), - _ => () + let err = match base { + 16 => Some("hexadecimal float literal is not supported"), + 8 => Some("octal float literal is not supported"), + 2 => Some("binary float literal is not supported"), + _ => None, + }; + if let Some(err) = err { + err!(diag, |span, diag| diag.span_err(span, err)); } - return filtered_float_lit(Symbol::intern(&s), Some(suf), sd, sp) + return filtered_float_lit(Symbol::intern(&s), Some(suf), diag) } } @@ -539,7 +585,9 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a } if let Some(suf) = suffix { - if suf.as_str().is_empty() { sd.span_bug(sp, "found empty literal suffix in Some")} + if suf.as_str().is_empty() { + err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); + } ty = match &*suf.as_str() { "isize" => ast::LitIntType::Signed(ast::IntTy::Is), "i8" => ast::LitIntType::Signed(ast::IntTy::I8), @@ -556,17 +604,20 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a suf => { // i and u look like widths, so lets // give an error message along those lines - if looks_like_width_suffix(&['i', 'u'], suf) { - sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", - &suf[1..])) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) - .help("the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") - .emit(); - } + err!(diag, |span, diag| { + if looks_like_width_suffix(&['i', 'u'], suf) { + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for numeric literal", suf); + diag.struct_span_err(span, &msg) + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") + .emit(); + } + }); ty } @@ -576,7 +627,7 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - match u128::from_str_radix(s, base) { + Some(match u128::from_str_radix(s, base) { Ok(r) => ast::LitKind::Int(r, ty), Err(_) => { // small bases are lexed as if they were base 10, e.g, the string @@ -588,11 +639,11 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); if !already_errored { - sd.span_err(sp, "int literal is too large"); + err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); } ast::LitKind::Int(0, ty) } - } + }) } #[cfg(test)] @@ -957,7 +1008,7 @@ mod tests { let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name.clone(), source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.name() == "doc") + let docs = item.attrs.iter().filter(|a| a.path == "doc") .map(|a| a.value_str().unwrap().to_string()).collect::>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9872afd27b7bc..ed512b899877d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -60,7 +60,6 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; use std::path::{Path, PathBuf}; -use std::rc::Rc; bitflags! { flags Restrictions: u8 { @@ -1643,44 +1642,15 @@ impl<'a> Parser<'a> { _ => { return self.unexpected_last(&self.token); } }, token::Literal(lit, suf) => { - let (suffix_illegal, out) = match lit { - token::Byte(i) => (true, LitKind::Byte(parse::byte_lit(&i.as_str()).0)), - token::Char(i) => (true, LitKind::Char(parse::char_lit(&i.as_str()).0)), - - // there are some valid suffixes for integer and - // float literals, so all the handling is done - // internally. - token::Integer(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::integer_lit(&s.as_str(), suf, diag, self.span)) - } - token::Float(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::float_lit(&s.as_str(), suf, diag, self.span)) - } - - token::Str_(s) => { - let s = Symbol::intern(&parse::str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Cooked)) - } - token::StrRaw(s, n) => { - let s = Symbol::intern(&parse::raw_str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Raw(n))) - } - token::ByteStr(i) => { - (true, LitKind::ByteStr(parse::byte_str_lit(&i.as_str()))) - } - token::ByteStrRaw(i, _) => { - (true, LitKind::ByteStr(Rc::new(i.to_string().into_bytes()))) - } - }; + let diag = Some((self.span, &self.sess.span_diagnostic)); + let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); if suffix_illegal { let sp = self.span; self.expect_no_suffix(sp, &format!("{} literal", lit.short_name()), suf) } - out + result.unwrap() } _ => { return self.unexpected_last(&self.token); } }; @@ -5135,11 +5105,9 @@ impl<'a> Parser<'a> { let attr = ast::Attribute { id: attr::mk_attr_id(), style: ast::AttrStyle::Outer, - value: ast::MetaItem { - name: Symbol::intern("warn_directory_ownership"), - node: ast::MetaItemKind::Word, - span: syntax_pos::DUMMY_SP, - }, + path: ast::Path::from_ident(syntax_pos::DUMMY_SP, + Ident::from_str("warn_directory_ownership")), + tokens: TokenStream::empty(), is_sugared_doc: false, span: syntax_pos::DUMMY_SP, }; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b81c..3837700457290 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -17,7 +17,7 @@ pub use self::Token::*; use ast::{self}; use ptr::P; use symbol::keywords; -use tokenstream; +use tokenstream::TokenTree; use std::fmt; use std::rc::Rc; @@ -348,7 +348,7 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), - NtTT(tokenstream::TokenTree), + NtTT(TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), NtImplItem(ast::ImplItem), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3efadbd00d1e0..d8af95d8d3062 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -28,7 +28,7 @@ use ptr::P; use std_inject; use symbol::{Symbol, keywords}; use syntax_pos::DUMMY_SP; -use tokenstream::{self, TokenTree}; +use tokenstream::{self, TokenStream, TokenTree}; use std::ascii; use std::io::{self, Write, Read}; @@ -329,6 +329,10 @@ pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String { to_string(|s| s.print_tts(tts.iter().cloned().collect())) } +pub fn tokens_to_string(tokens: TokenStream) -> String { + to_string(|s| s.print_tts(tokens)) +} + pub fn stmt_to_string(stmt: &ast::Stmt) -> String { to_string(|s| s.print_stmt(stmt)) } @@ -750,7 +754,21 @@ pub trait PrintState<'a> { ast::AttrStyle::Inner => word(self.writer(), "#![")?, ast::AttrStyle::Outer => word(self.writer(), "#[")?, } - self.print_meta_item(&attr.meta())?; + if let Some(mi) = attr.meta() { + self.print_meta_item(&mi)? + } else { + for (i, segment) in attr.path.segments.iter().enumerate() { + if i > 0 { + word(self.writer(), "::")? + } + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { + word(self.writer(), &segment.identifier.name.as_str())?; + } + } + space(self.writer())?; + self.print_tts(attr.tokens.clone())?; + } word(self.writer(), "]") } } @@ -789,6 +807,45 @@ pub trait PrintState<'a> { self.end() } + /// This doesn't deserve to be called "pretty" printing, but it should be + /// meaning-preserving. A quick hack that might help would be to look at the + /// spans embedded in the TTs to decide where to put spaces and newlines. + /// But it'd be better to parse these according to the grammar of the + /// appropriate macro, transcribe back into the grammar we just parsed from, + /// and then pretty-print the resulting AST nodes (so, e.g., we print + /// expression arguments as expressions). It can be done! I think. + fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { + match tt { + TokenTree::Token(_, ref tk) => { + word(self.writer(), &token_to_string(tk))?; + match *tk { + parse::token::DocComment(..) => { + hardbreak(self.writer()) + } + _ => Ok(()) + } + } + TokenTree::Delimited(_, ref delimed) => { + word(self.writer(), &token_to_string(&delimed.open_token()))?; + space(self.writer())?; + self.print_tts(delimed.stream())?; + space(self.writer())?; + word(self.writer(), &token_to_string(&delimed.close_token())) + }, + } + } + + fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> { + self.ibox(0)?; + for (i, tt) in tts.into_trees().enumerate() { + if i != 0 { + space(self.writer())?; + } + self.print_tt(tt)?; + } + self.end() + } + fn space_if_not_bol(&mut self) -> io::Result<()> { if !self.is_bol() { space(self.writer())?; } Ok(()) @@ -1458,45 +1515,6 @@ impl<'a> State<'a> { } } - /// This doesn't deserve to be called "pretty" printing, but it should be - /// meaning-preserving. A quick hack that might help would be to look at the - /// spans embedded in the TTs to decide where to put spaces and newlines. - /// But it'd be better to parse these according to the grammar of the - /// appropriate macro, transcribe back into the grammar we just parsed from, - /// and then pretty-print the resulting AST nodes (so, e.g., we print - /// expression arguments as expressions). It can be done! I think. - pub fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { - match tt { - TokenTree::Token(_, ref tk) => { - word(&mut self.s, &token_to_string(tk))?; - match *tk { - parse::token::DocComment(..) => { - hardbreak(&mut self.s) - } - _ => Ok(()) - } - } - TokenTree::Delimited(_, ref delimed) => { - word(&mut self.s, &token_to_string(&delimed.open_token()))?; - space(&mut self.s)?; - self.print_tts(delimed.stream())?; - space(&mut self.s)?; - word(&mut self.s, &token_to_string(&delimed.close_token())) - }, - } - } - - pub fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> { - self.ibox(0)?; - for (i, tt) in tts.into_trees().enumerate() { - if i != 0 { - space(&mut self.s)?; - } - self.print_tt(tt)?; - } - self.end() - } - pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> { self.head("")?; let generics = ast::Generics::default(); diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4a2dfaf61247c..94954e2c42980 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -15,6 +15,7 @@ use syntax_pos::{DUMMY_SP, Span}; use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; use parse::ParseSess; use ptr::P; +use tokenstream::TokenStream; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. @@ -70,11 +71,8 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, - value: ast::MetaItem { - name: Symbol::intern("prelude_import"), - node: ast::MetaItemKind::Word, - span: span, - }, + path: ast::Path::from_ident(span, ast::Ident::from_str("prelude_import")), + tokens: TokenStream::empty(), id: attr::mk_attr_id(), is_sugared_doc: false, span: span, diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 2da442a1a53da..35e4d9eb68aea 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -360,7 +360,7 @@ impl PartialEq for ThinTokenStream { impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&pprust::tts_to_string(&self.trees().collect::>())) + f.write_str(&pprust::tokens_to_string(self.clone())) } } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index a7e2d82bb978f..b01ef65e5fe5e 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -23,9 +23,11 @@ struct MarkAttrs<'a>(&'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - if self.0.contains(&attr.name()) { - mark_used(attr); - mark_known(attr); + if let Some(name) = attr.name() { + if self.0.contains(&name) { + mark_used(attr); + mark_known(attr); + } } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index fe492bd7fc849..48e7ff0d24370 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -439,7 +439,7 @@ impl<'a> TraitDef<'a> { attrs.extend(item.attrs .iter() .filter(|a| { - match &*a.name().as_str() { + a.name().is_some() && match &*a.name().unwrap().as_str() { "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, _ => false, } diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 5adaf470f2374..2d815b3f1bb7d 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -248,7 +248,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.node { if self.is_proc_macro_crate && - item.attrs.iter().any(|attr| attr.name() == "macro_export") { + item.attrs.iter().any(|attr| attr.path == "macro_export") { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; self.handler.span_err(item.span, msg); @@ -270,12 +270,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { - let msg = if attr.name() == prev_attr.name() { + let msg = if attr.path == prev_attr.path { format!("Only one `#[{}]` attribute is allowed on any given function", - attr.name()) + attr.path) } else { format!("`#[{}]` and `#[{}]` attributes cannot both be applied \ - to the same function", attr.name(), prev_attr.name()) + to the same function", attr.path, prev_attr.path) }; self.handler.struct_span_err(attr.span(), &msg) @@ -299,7 +299,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !is_fn { let msg = format!("the `#[{}]` attribute may only be used on bare functions", - attr.name()); + attr.path); self.handler.span_err(attr.span(), &msg); return; @@ -311,7 +311,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { let msg = format!("the `#[{}]` attribute is only usable with crates of the \ - `proc-macro` crate type", attr.name()); + `proc-macro` crate type", attr.path); self.handler.span_err(attr.span(), &msg); return; From 839c2860ccb7cd3d381abf2838dfba566f52618e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 8 Mar 2017 23:13:35 +0000 Subject: [PATCH 037/662] Liberalize attributes. --- src/librustc_resolve/lib.rs | 2 + src/librustc_resolve/macros.rs | 54 +++++++---- src/libsyntax/attr.rs | 46 ++++++++- src/libsyntax/config.rs | 72 +++++++------- src/libsyntax/ext/derive.rs | 45 ++++----- src/libsyntax/ext/expand.rs | 94 ++++++++++--------- src/libsyntax/ext/tt/macro_rules.rs | 3 +- src/libsyntax/feature_gate.rs | 4 + src/libsyntax/parse/attr.rs | 32 +++++-- src/libsyntax/parse/parser.rs | 11 +++ .../macro-attribute.rs | 2 - .../compile-fail/malformed-derive-entry.rs | 4 +- .../compile-fail/suffixed-literal-meta.rs | 25 +++++ src/test/parse-fail/attr-bad-meta.rs | 6 +- src/test/parse-fail/suffixed-literal-meta.rs | 25 ----- src/test/ui/span/E0536.stderr | 2 +- src/test/ui/span/E0537.stderr | 2 +- 17 files changed, 257 insertions(+), 172 deletions(-) rename src/test/{parse-fail => compile-fail}/macro-attribute.rs (94%) create mode 100644 src/test/compile-fail/suffixed-literal-meta.rs delete mode 100644 src/test/parse-fail/suffixed-literal-meta.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c3e471650a3e1..bf7115abd4edd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1165,6 +1165,7 @@ pub struct Resolver<'a> { privacy_errors: Vec>, ambiguity_errors: Vec>, + gated_errors: FxHashSet, disallowed_shadowing: Vec<&'a LegacyBinding<'a>>, arenas: &'a ResolverArenas<'a>, @@ -1355,6 +1356,7 @@ impl<'a> Resolver<'a> { privacy_errors: Vec::new(), ambiguity_errors: Vec::new(), + gated_errors: FxHashSet(), disallowed_shadowing: Vec::new(), arenas: arenas, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 9e1dcd1bc35c4..67ce24efb3b1f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -28,9 +28,11 @@ use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; +use syntax::parse::parser::PathStyle; +use syntax::parse::token::{self, Token}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; -use syntax::tokenstream::TokenStream; +use syntax::tokenstream::{TokenStream, TokenTree, Delimited}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; @@ -200,16 +202,22 @@ impl<'a> base::Resolver for Resolver<'a> { let name = unwrap_or!(attrs[i].name(), continue); if name == "derive" { - let mut traits = match attrs[i].meta_item_list() { - Some(traits) => traits, - _ => continue, + let result = attrs[i].parse_list(&self.session.parse_sess, + |parser| parser.parse_path(PathStyle::Mod)); + let mut traits = match result { + Ok(traits) => traits, + Err(mut e) => { + e.cancel(); + continue + } }; for j in 0..traits.len() { - let legacy_name = Symbol::intern(&match traits[j].word() { - Some(..) => format!("derive_{}", traits[j].name().unwrap()), - None => continue, - }); + if traits[j].segments.len() > 1 { + continue + } + let trait_name = traits[j].segments[0].identifier.name; + let legacy_name = Symbol::intern(&format!("derive_{}", trait_name)); if !self.builtin_macros.contains_key(&legacy_name) { continue } @@ -218,7 +226,23 @@ impl<'a> base::Resolver for Resolver<'a> { if traits.is_empty() { attrs.remove(i); } else { - attrs[i].tokens = ast::MetaItemKind::List(traits).tokens(attrs[i].span); + let mut tokens = Vec::new(); + for (i, path) in traits.iter().enumerate() { + if i > 0 { + tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into()); + } + for (j, segment) in path.segments.iter().enumerate() { + if j > 0 { + tokens.push(TokenTree::Token(path.span, Token::ModSep).into()); + } + let tok = Token::Ident(segment.identifier); + tokens.push(TokenTree::Token(path.span, tok).into()); + } + } + attrs[i].tokens = TokenTree::Delimited(attrs[i].span, Delimited { + delim: token::Paren, + tts: TokenStream::concat(tokens).into(), + }).into(); } return Some(ast::Attribute { path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)), @@ -262,9 +286,8 @@ impl<'a> Resolver<'a> { InvocationKind::Bang { ref mac, .. } => { return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force); } - InvocationKind::Derive { name, span, .. } => { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force); + InvocationKind::Derive { ref path, .. } => { + return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force); } }; @@ -282,9 +305,8 @@ impl<'a> Resolver<'a> { 1 => path.segments[0].identifier.name, _ => return Err(determinacy), }; - for &(name, span) in traits { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - match self.resolve_macro(scope, &path, MacroKind::Derive, force) { + for path in traits { + match self.resolve_macro(scope, path, MacroKind::Derive, force) { Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { if inert_attrs.contains(&attr_name) { // FIXME(jseyfried) Avoid `mem::replace` here. @@ -327,7 +349,7 @@ impl<'a> Resolver<'a> { self.current_module = invocation.module.get(); if path.len() > 1 { - if !self.use_extern_macros { + if !self.use_extern_macros && self.gated_errors.insert(span) { let msg = "non-ident macro paths are experimental"; let feature = "use_extern_macros"; emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 68f1f690a62f0..2f1efd6ad00ee 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -17,7 +17,7 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind}; +use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; @@ -299,6 +299,37 @@ impl Attribute { }) } + pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + let mut parser = Parser::new(sess, self.tokens.clone(), None, false); + let result = f(&mut parser)?; + if parser.token != token::Eof { + parser.unexpected()?; + } + Ok(result) + } + + pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + if self.tokens.is_empty() { + return Ok(Vec::new()); + } + self.parse(sess, |parser| { + parser.expect(&token::OpenDelim(token::Paren))?; + let mut list = Vec::new(); + while !parser.eat(&token::CloseDelim(token::Paren)) { + list.push(f(parser)?); + if !parser.eat(&token::Comma) { + parser.expect(&token::CloseDelim(token::Paren))?; + break + } + } + Ok(list) + }) + } + pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { if self.path.segments.len() > 1 { sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); @@ -306,7 +337,7 @@ impl Attribute { Ok(MetaItem { name: self.path.segments.last().unwrap().identifier.name, - node: Parser::new(sess, self.tokens.clone(), None, false).parse_meta_item_kind()?, + node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, span: self.span, }) } @@ -985,6 +1016,10 @@ impl MetaItem { { let (mut span, name) = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), + Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt { + token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + _ => None, + }, _ => return None, }; let node = match MetaItemKind::from_tokens(tokens) { @@ -1151,6 +1186,13 @@ impl LitKind { match token { Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)), Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)), + Token::Interpolated(ref nt) => match **nt { + token::NtExpr(ref v) => match v.node { + ExprKind::Lit(ref lit) => Some(lit.node.clone()), + _ => None, + }, + _ => None, + }, Token::Literal(lit, suf) => { let (suffix_illegal, result) = parse::lit_token(lit, suf, None); if suffix_illegal && suf.is_some() { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2591a5766693f..ede8a33df6546 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -13,9 +13,10 @@ use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features use {fold, attr}; use ast; use codemap::Spanned; -use parse::ParseSess; -use ptr::P; +use parse::{token, ParseSess}; +use syntax_pos::Span; +use ptr::P; use util::small_vector::SmallVector; /// A folder that strips out items that do not belong in the current configuration. @@ -84,44 +85,33 @@ impl<'a> StripUnconfigured<'a> { return Some(attr); } - let attr_list = match attr.meta_item_list() { - Some(attr_list) => attr_list, - None => { - let msg = "expected `#[cfg_attr(, )]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); - return None; - } - }; - - let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { - (2, Some(cfg), Some(mi)) => (cfg, mi), - _ => { - let msg = "expected `#[cfg_attr(, )]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); + let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| { + parser.expect(&token::OpenDelim(token::Paren))?; + let cfg = parser.parse_meta_item()?; + parser.expect(&token::Comma)?; + let lo = parser.span.lo; + let (path, tokens) = parser.parse_path_and_tokens()?; + parser.expect(&token::CloseDelim(token::Paren))?; + Ok((cfg, path, tokens, Span { lo: lo, ..parser.prev_span })) + }) { + Ok(result) => result, + Err(mut e) => { + e.emit(); return None; } }; - use attr::cfg_matches; - match (cfg.meta_item(), mi.meta_item()) { - (Some(cfg), Some(mi)) => - if cfg_matches(&cfg, self.sess, self.features) { - self.process_cfg_attr(ast::Attribute { - id: attr::mk_attr_id(), - style: attr.style, - path: ast::Path::from_ident(mi.span, ast::Ident::with_empty_ctxt(mi.name)), - tokens: mi.node.tokens(mi.span), - is_sugared_doc: false, - span: mi.span, - }) - } else { - None - }, - _ => { - let msg = "unexpected literal(s) in `#[cfg_attr(, )]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); - None - } + if attr::cfg_matches(&cfg, self.sess, self.features) { + self.process_cfg_attr(ast::Attribute { + id: attr::mk_attr_id(), + style: attr.style, + path: path, + tokens: tokens, + is_sugared_doc: false, + span: span, + }) + } else { + None } } @@ -133,10 +123,12 @@ impl<'a> StripUnconfigured<'a> { return false; } - let mis = attr.meta_item_list(); - let mis = match mis { - Some(ref mis) if is_cfg(&attr) => mis, - _ => return true + let mis = if !is_cfg(&attr) { + return true; + } else if let Some(mis) = attr.meta_item_list() { + mis + } else { + return true; }; if mis.len() != 1 { diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 5b253635f257e..1569d9f540b8e 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -12,36 +12,31 @@ use attr::HasAttrs; use {ast, codemap}; use ext::base::ExtCtxt; use ext::build::AstBuilder; +use parse::parser::PathStyle; use symbol::Symbol; use syntax_pos::Span; -pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec<(Symbol, Span)> { +pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { if attr.path != "derive" { return true; } - if attr.value_str().is_some() { - cx.span_err(attr.span, "unexpected value in `derive`"); - return false; - } - - let traits = attr.meta_item_list().unwrap_or_else(Vec::new); - if traits.is_empty() { - cx.span_warn(attr.span, "empty trait list in `derive`"); - return false; - } - - for titem in traits { - if titem.word().is_none() { - cx.span_err(titem.span, "malformed `derive` entry"); - return false; + match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { + Ok(ref traits) if traits.is_empty() => { + cx.span_warn(attr.span, "empty trait list in `derive`"); + false + } + Ok(traits) => { + result.extend(traits); + true + } + Err(mut e) => { + e.emit(); + false } - result.push((titem.name().unwrap(), titem.span)); } - - true }); result } @@ -60,21 +55,21 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { } } -pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[(Symbol, Span)], item: T) -> T { +pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T { let span = match traits.get(0) { - Some(&(_, span)) => span, + Some(path) => path.span, None => return item, }; item.map_attrs(|mut attrs| { - if traits.iter().any(|&(name, _)| name == "PartialEq") && - traits.iter().any(|&(name, _)| name == "Eq") { + if traits.iter().any(|path| *path == "PartialEq") && + traits.iter().any(|path| *path == "Eq") { let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); let meta = cx.meta_word(span, Symbol::intern("structural_match")); attrs.push(cx.attribute(span, meta)); } - if traits.iter().any(|&(name, _)| name == "Copy") && - traits.iter().any(|&(name, _)| name == "Clone") { + if traits.iter().any(|path| *path == "Copy") && + traits.iter().any(|path| *path == "Clone") { let span = allow_unstable(cx, span, "derive(Copy, Clone)"); let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); attrs.push(cx.attribute(span, meta)); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c1095d3445682..c1816582bc6ca 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Block, Ident, PatKind}; -use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; +use ast::{self, Block, Ident, PatKind, Path}; +use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use config::{is_test_or_bench, StripUnconfigured}; @@ -27,7 +27,7 @@ use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; -use syntax_pos::{self, Span, ExpnId}; +use syntax_pos::{Span, ExpnId, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -165,12 +165,11 @@ pub enum InvocationKind { }, Attr { attr: Option, - traits: Vec<(Symbol, Span)>, + traits: Vec, item: Annotatable, }, Derive { - name: Symbol, - span: Span, + path: Path, item: Annotatable, }, } @@ -180,8 +179,8 @@ impl Invocation { match self.kind { InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span, - InvocationKind::Attr { attr: None, .. } => syntax_pos::DUMMY_SP, - InvocationKind::Derive { span, .. } => span, + InvocationKind::Attr { attr: None, .. } => DUMMY_SP, + InvocationKind::Derive { ref path, .. } => path.span, } } } @@ -277,12 +276,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { add_derived_markers(&mut self.cx, &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); - for &(name, span) in &traits { + for path in &traits { let mark = Mark::fresh(); derives.push(mark); - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); let item = match self.cx.resolver.resolve_macro( - Mark::root(), &path, MacroKind::Derive, false) { + Mark::root(), path, MacroKind::Derive, false) { Ok(ext) => match *ext { SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(), _ => item.clone(), @@ -290,7 +288,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.clone(), }; invocations.push(Invocation { - kind: InvocationKind::Derive { name: name, span: span, item: item }, + kind: InvocationKind::Derive { path: path.clone(), item: item }, expansion_kind: invoc.expansion_kind, expansion_data: ExpansionData { mark: mark, @@ -380,11 +378,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - let name = attr.path.segments[0].identifier.name; self.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - format: MacroAttribute(name), + format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), span: Some(attr.span), allow_internal_unstable: false, } @@ -419,14 +416,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); - self.parse_expansion(tok_result, kind, name, span) + self.parse_expansion(tok_result, kind, &attr.path, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); + self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); kind.dummy(attr.span) } _ => { - let msg = &format!("macro `{}` may not be used in attributes", name); + let msg = &format!("macro `{}` may not be used in attributes", attr.path); self.cx.span_err(attr.span, &msg); kind.dummy(attr.span) } @@ -442,7 +439,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let path = &mac.node.path; - let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); @@ -450,7 +446,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { let msg = - format!("macro {}! expects no ident argument, given '{}'", extname, ident); + format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); return kind.dummy(span); } @@ -458,7 +454,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), span: exp_span, allow_internal_unstable: allow_internal_unstable, }, @@ -470,14 +466,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { IdentTT(ref expander, tt_span, allow_internal_unstable) => { if ident.name == keywords::Invalid.name() { self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", extname)); + &format!("macro {}! expects an ident argument", path)); return kind.dummy(span); }; self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), span: tt_span, allow_internal_unstable: allow_internal_unstable, } @@ -489,19 +485,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => { self.cx.span_err(path.span, - &format!("`{}` can only be used in attributes", extname)); + &format!("`{}` can only be used in attributes", path)); return kind.dummy(span); } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname)); + self.cx.span_err(path.span, &format!("`{}` is a derive mode", path)); return kind.dummy(span); } SyntaxExtension::ProcMacro(ref expandfun) => { if ident.name != keywords::Invalid.name() { let msg = - format!("macro {}! expects no ident argument, given '{}'", extname, ident); + format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); return kind.dummy(span); } @@ -509,7 +505,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), // FIXME procedural macros do not have proper span info // yet, when they do, we should use it here. span: None, @@ -519,7 +515,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); let tok_result = expandfun.expand(self.cx, span, marked_tts); - Some(self.parse_expansion(tok_result, kind, extname, span)) + Some(self.parse_expansion(tok_result, kind, path, span)) } }; @@ -541,19 +537,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> { /// Expand a derive invocation. Returns the result of expansion. fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { let Invocation { expansion_kind: kind, .. } = invoc; - let (name, span, item) = match invoc.kind { - InvocationKind::Derive { name, span, item } => (name, span, item), + let (path, item) = match invoc.kind { + InvocationKind::Derive { path, item } => (path, item), _ => unreachable!(), }; - let mitem = ast::MetaItem { name: name, span: span, node: ast::MetaItemKind::Word }; - let pretty_name = Symbol::intern(&format!("derive({})", name)); + let pretty_name = Symbol::intern(&format!("derive({})", path)); + let span = path.span; + let attr = ast::Attribute { + path: path, tokens: TokenStream::empty(), span: span, + // irrelevant: + id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, + }; self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroAttribute(pretty_name), - span: Some(span), + span: None, allow_internal_unstable: false, } }); @@ -571,7 +572,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }), ..span }; - return kind.expect_from_annotatables(ext.expand(self.cx, span, &mitem, item)); + let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this + name: keywords::Invalid.name(), + span: DUMMY_SP, + node: ast::MetaItemKind::Word, + }; + return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)); } SyntaxExtension::BuiltinDerive(func) => { let span = Span { @@ -586,20 +592,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ..span }; let mut items = Vec::new(); - func(self.cx, span, &mitem, &item, &mut |a| { - items.push(a) - }); + func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); return kind.expect_from_annotatables(items); } _ => { - let msg = &format!("macro `{}` may not be used for derive attributes", name); + let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); self.cx.span_err(span, &msg); kind.dummy(span) } } } - fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span) + fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, path: &Path, span: Span) -> Expansion { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::>()); let expansion = match parser.parse_expansion(kind, false) { @@ -609,7 +613,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } }; - parser.ensure_complete_parse(name, kind.name(), span); + parser.ensure_complete_parse(path, kind.name(), span); // FIXME better span info expansion.fold_with(&mut ChangeSpan { span: span }) } @@ -658,14 +662,14 @@ impl<'a> Parser<'a> { }) } - pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) { + pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) { if self.token != token::Eof { let msg = format!("macro expansion ignores token `{}` and any following", self.this_token_to_string()); let mut err = self.diagnostic().struct_span_err(self.span, &msg); let msg = format!("caused by the macro expansion here; the usage \ of `{}!` is likely invalid in {} context", - macro_name, kind_name); + macro_path, kind_name); err.span_note(span, &msg).emit(); } } @@ -708,20 +712,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr(&mut self, attr: Option, - traits: Vec<(Symbol, Span)>, + traits: Vec, item: Annotatable, kind: ExpansionKind) -> Expansion { if !traits.is_empty() && (kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) { - self.cx.span_err(traits[0].1, "`derive` can be only be applied to items"); + self.cx.span_err(traits[0].span, "`derive` can be only be applied to items"); return kind.expect_from_annotatables(::std::iter::once(item)); } self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item }) } // If `item` is an attr invocation, remove and return the macro attribute. - fn classify_item(&mut self, mut item: T) -> (Option, Vec<(Symbol, Span)>, T) + fn classify_item(&mut self, mut item: T) -> (Option, Vec, T) where T: HasAttrs, { let (mut attr, mut traits) = (None, Vec::new()); @@ -900,7 +904,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). // Thus, if `inner` is the dummy span, we know the module is inline. - let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; + let inline_module = item.span.contains(inner) || inner == DUMMY_SP; if inline_module { if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 7aa1230f9aeea..021c5398a4200 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -51,7 +51,8 @@ impl<'a> ParserAnyMacro<'a> { } // Make sure we don't have any tokens left to parse so we don't silently drop anything. - parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span); + let path = ast::Path::from_ident(site_span, macro_ident); + parser.ensure_complete_parse(&path, kind.name(), site_span); expansion } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2c3ad98a6be63..05e7b0f9aa4da 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1096,6 +1096,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { self.context.check_attribute(attr, false); } + if self.context.features.proc_macro && attr::is_known(attr) { + return + } + let meta = panictry!(attr.parse_meta(&self.context.parse_sess)); if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 272cff7ad34b2..53106214fa310 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -14,8 +14,9 @@ use syntax_pos::{mk_sp, Span}; use codemap::spanned; use parse::common::SeqSep; use parse::PResult; -use parse::token; -use parse::parser::{Parser, TokenType}; +use parse::token::{self, Nonterminal}; +use parse::parser::{Parser, TokenType, PathStyle}; +use tokenstream::TokenStream; #[derive(PartialEq, Eq, Debug)] enum InnerAttributeParsePolicy<'a> { @@ -91,7 +92,7 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, value, mut style) = match self.token { + let (span, path, tokens, mut style) = match self.token { token::Pound => { let lo = self.span.lo; self.bump(); @@ -119,11 +120,11 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let meta_item = self.parse_meta_item()?; + let (path, tokens) = self.parse_path_and_tokens()?; self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span.hi; - (mk_sp(lo, hi), meta_item, style) + (mk_sp(lo, hi), path, tokens, style) } _ => { let token_str = self.this_token_to_string(); @@ -143,13 +144,30 @@ impl<'a> Parser<'a> { Ok(ast::Attribute { id: attr::mk_attr_id(), style: style, - path: ast::Path::from_ident(value.span, ast::Ident::with_empty_ctxt(value.name)), - tokens: value.node.tokens(value.span), + path: path, + tokens: tokens, is_sugared_doc: false, span: span, }) } + pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { + let meta = match self.token { + token::Interpolated(ref nt) => match **nt { + Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + _ => None, + }, + _ => None, + }; + Ok(if let Some(meta) = meta { + self.bump(); + (ast::Path::from_ident(meta.span, ast::Ident::with_empty_ctxt(meta.name)), + meta.node.tokens(meta.span)) + } else { + (self.parse_path(PathStyle::Mod)?, self.parse_tokens()) + }) + } + /// Parse attributes that appear after the opening of an item. These should /// be preceded by an exclamation mark, but we accept and warn about one /// terminated by a semicolon. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ed512b899877d..308876fed56dc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2644,6 +2644,17 @@ impl<'a> Parser<'a> { Ok(tts) } + pub fn parse_tokens(&mut self) -> TokenStream { + let mut result = Vec::new(); + loop { + match self.token { + token::Eof | token::CloseDelim(..) => break, + _ => result.push(self.parse_token_tree().into()), + } + } + TokenStream::concat(result) + } + /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self, already_parsed_attrs: Option>) diff --git a/src/test/parse-fail/macro-attribute.rs b/src/test/compile-fail/macro-attribute.rs similarity index 94% rename from src/test/parse-fail/macro-attribute.rs rename to src/test/compile-fail/macro-attribute.rs index 18add7d011cba..52f867fe913b8 100644 --- a/src/test/parse-fail/macro-attribute.rs +++ b/src/test/compile-fail/macro-attribute.rs @@ -8,7 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - #[doc = $not_there] //~ error: unexpected token: `$` fn main() { } diff --git a/src/test/compile-fail/malformed-derive-entry.rs b/src/test/compile-fail/malformed-derive-entry.rs index 62dbc21495a54..ac000628f2b04 100644 --- a/src/test/compile-fail/malformed-derive-entry.rs +++ b/src/test/compile-fail/malformed-derive-entry.rs @@ -9,11 +9,11 @@ // except according to those terms. #[derive(Copy(Bad))] -//~^ ERROR malformed `derive` entry +//~^ ERROR expected one of `)`, `,`, or `::`, found `(` struct Test1; #[derive(Copy="bad")] -//~^ ERROR malformed `derive` entry +//~^ ERROR expected one of `)`, `,`, or `::`, found `=` struct Test2; #[derive()] diff --git a/src/test/compile-fail/suffixed-literal-meta.rs b/src/test/compile-fail/suffixed-literal-meta.rs new file mode 100644 index 0000000000000..bf55b7bdcb1de --- /dev/null +++ b/src/test/compile-fail/suffixed-literal-meta.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(attr_literals)] + +#[path = 1usize] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u8] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u16] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u32] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u64] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1isize] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i8] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i16] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i32] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i64] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes +fn main() { } diff --git a/src/test/parse-fail/attr-bad-meta.rs b/src/test/parse-fail/attr-bad-meta.rs index 092adbf29e340..d57a813311b5a 100644 --- a/src/test/parse-fail/attr-bad-meta.rs +++ b/src/test/parse-fail/attr-bad-meta.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -// error-pattern:expected one of `=` or `]` - // asterisk is bogus -#[attr*] +#[path*] //~ ERROR expected one of `(` or `=` mod m {} diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs deleted file mode 100644 index 0e2840c69d364..0000000000000 --- a/src/test/parse-fail/suffixed-literal-meta.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z parse-only - -#[foo = 1usize] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1u8] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1u16] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1u32] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1u64] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1isize] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1i8] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1i16] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1i32] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1i64] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes -#[foo = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes -fn main() { } diff --git a/src/test/ui/span/E0536.stderr b/src/test/ui/span/E0536.stderr index c33b89953e274..b2da0c6a296d8 100644 --- a/src/test/ui/span/E0536.stderr +++ b/src/test/ui/span/E0536.stderr @@ -2,7 +2,7 @@ error[E0536]: expected 1 cfg-pattern --> $DIR/E0536.rs:11:7 | 11 | #[cfg(not())] //~ ERROR E0536 - | ^^^^^ + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/span/E0537.stderr b/src/test/ui/span/E0537.stderr index 9d66ddbaae317..29873943f444d 100644 --- a/src/test/ui/span/E0537.stderr +++ b/src/test/ui/span/E0537.stderr @@ -2,7 +2,7 @@ error[E0537]: invalid predicate `unknown` --> $DIR/E0537.rs:11:7 | 11 | #[cfg(unknown())] //~ ERROR E0537 - | ^^^^^^^^^ + | ^^^^^^^ error: aborting due to previous error From 85e02bdbfcfd0e38def7656a8295a5260640fd4a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 8 Mar 2017 23:13:43 +0000 Subject: [PATCH 038/662] Add tests. --- .../proc-macro/proc-macro-attributes.rs | 1 + src/test/compile-fail/macro-with-seps-err-msg.rs | 1 + src/test/run-pass-fulldeps/proc-macro/attr-args.rs | 6 +++--- .../run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs | 5 +++++ .../run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs | 2 +- src/test/run-pass-fulldeps/proc-macro/derive-b.rs | 7 ++++--- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs index 4ad1cf79d61c6..df881bedec1bb 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs @@ -20,6 +20,7 @@ extern crate derive_b; #[C] //~ ERROR: The attribute `C` is currently unknown to the compiler #[B(D)] #[B(E = "foo")] +#[B arbitrary tokens] //~ expected one of `(` or `=`, found `arbitrary` struct B; fn main() {} diff --git a/src/test/compile-fail/macro-with-seps-err-msg.rs b/src/test/compile-fail/macro-with-seps-err-msg.rs index 6cc682bde997f..c28e22d58f9db 100644 --- a/src/test/compile-fail/macro-with-seps-err-msg.rs +++ b/src/test/compile-fail/macro-with-seps-err-msg.rs @@ -14,4 +14,5 @@ fn main() { globnar::brotz!(); //~ ERROR non-ident macro paths are experimental ::foo!(); //~ ERROR non-ident macro paths are experimental foo::!(); //~ ERROR type parameters are not allowed on macros + #[derive(foo::Bar)] struct T; //~ ERROR non-ident macro paths are experimental } diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-args.rs b/src/test/run-pass-fulldeps/proc-macro/attr-args.rs index d28d75d81a2fb..8a9fdd7536770 100644 --- a/src/test/run-pass-fulldeps/proc-macro/attr-args.rs +++ b/src/test/run-pass-fulldeps/proc-macro/attr-args.rs @@ -19,6 +19,6 @@ use attr_args::attr_with_args; #[attr_with_args(text = "Hello, world!")] fn foo() {} -fn main() { - assert_eq!(foo(), "Hello, world!"); -} +#[::attr_args::identity + fn main() { assert_eq!(foo(), "Hello, world!"); }] +struct Dummy; diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs index 6e1eb395a0a19..989c77f1089cf 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs @@ -30,3 +30,8 @@ pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream { fn foo() -> &'static str { "Hello, world!" } "#.parse().unwrap() } + +#[proc_macro_attribute] +pub fn identity(attr_args: TokenStream, _: TokenStream) -> TokenStream { + attr_args +} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs index bf793534d50c9..7b521f2b9138a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs @@ -19,7 +19,7 @@ use proc_macro::TokenStream; #[proc_macro_derive(B, attributes(B, C))] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert!(input.contains("#[B]")); + assert!(input.contains("#[B arbitrary tokens]")); assert!(input.contains("struct B {")); assert!(input.contains("#[C]")); "".parse().unwrap() diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs index f1e1626ddf8ca..995dc65729a50 100644 --- a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs +++ b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs @@ -11,11 +11,12 @@ // aux-build:derive-b.rs // ignore-stage1 -#[macro_use] +#![feature(proc_macro)] + extern crate derive_b; -#[derive(Debug, PartialEq, B, Eq, Copy, Clone)] -#[B] +#[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)] +#[cfg_attr(all(), B arbitrary tokens)] struct B { #[C] a: u64 From 5cc056a744d1fbdacbdeed65ee62c76362bd68cf Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 14 Mar 2017 00:42:44 -0400 Subject: [PATCH 039/662] A few improvements to the `core::hash` top-level docs. Primarily opened to address the concerns brought up in https://github.com/rust-lang/rust/issues/40498. * run rustfmt on code blocks * use `DefaultHasher` instead of deprecated `SipHasher` * rename `hash` to `calculate_hash` to prevent confusion with the `hash` method --- src/libcore/hash/mod.rs | 44 +++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index f0d8d1a321917..8c7d83232de4f 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -16,7 +16,8 @@ //! # Examples //! //! ```rust -//! use std::hash::{Hash, SipHasher, Hasher}; +//! use std::collections::hash_map::DefaultHasher; +//! use std::hash::{Hash, Hasher}; //! //! #[derive(Hash)] //! struct Person { @@ -25,13 +26,21 @@ //! phone: u64, //! } //! -//! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; -//! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; +//! let person1 = Person { +//! id: 5, +//! name: "Janet".to_string(), +//! phone: 555_666_7777, +//! }; +//! let person2 = Person { +//! id: 5, +//! name: "Bob".to_string(), +//! phone: 555_666_7777, +//! }; //! -//! assert!(hash(&person1) != hash(&person2)); +//! assert!(calculate_hash(&person1) != calculate_hash(&person2)); //! -//! fn hash(t: &T) -> u64 { -//! let mut s = SipHasher::new(); +//! fn calculate_hash(t: &T) -> u64 { +//! let mut s = DefaultHasher::new(); //! t.hash(&mut s); //! s.finish() //! } @@ -43,11 +52,12 @@ //! [`Hash`]: trait.Hash.html //! //! ```rust -//! use std::hash::{Hash, Hasher, SipHasher}; +//! use std::collections::hash_map::DefaultHasher; +//! use std::hash::{Hash, Hasher}; //! //! struct Person { //! id: u32, -//! # #[allow(dead_code)] +//! # #[allow(dead_code)] //! name: String, //! phone: u64, //! } @@ -59,13 +69,21 @@ //! } //! } //! -//! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; -//! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; +//! let person1 = Person { +//! id: 5, +//! name: "Janet".to_string(), +//! phone: 555_666_7777, +//! }; +//! let person2 = Person { +//! id: 5, +//! name: "Bob".to_string(), +//! phone: 555_666_7777, +//! }; //! -//! assert_eq!(hash(&person1), hash(&person2)); +//! assert_eq!(calculate_hash(&person1), calculate_hash(&person2)); //! -//! fn hash(t: &T) -> u64 { -//! let mut s = SipHasher::new(); +//! fn calculate_hash(t: &T) -> u64 { +//! let mut s = DefaultHasher::new(); //! t.hash(&mut s); //! s.finish() //! } From 5fab9bf4f67235f7f5599f0e29bc7b2dd746d084 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Mar 2017 22:13:37 -0700 Subject: [PATCH 040/662] travis: Ensure cargo links libcurl statically We don't want a dynamic dependency in the library that we ship, so link it statically by configuring curl-sys's build script to not pick up the system version via pkg-config. --- src/ci/docker/dist-x86-linux/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 3f6f71c41b520..282739ceebee9 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -86,4 +86,10 @@ ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --enable-sanitizers ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS + +# This is the only builder which will create source tarballs ENV DIST_SRC 1 + +# When we build cargo in this container, we don't want it to use the system +# libcurl, instead it should compile its own. +ENV LIBCURL_NO_PKG_CONFIG 1 From 182044248ca2aa569844a25e73f90e5bc2fd05d3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 2 Mar 2017 17:27:57 +0100 Subject: [PATCH 041/662] Add Utf8Error::resume_from, to help incremental and/or lossy decoding. Without this, code outside of the standard library needs to reimplement most of the logic `from_utf8` to interpret the bytes after `valid_up_to()`. --- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/str.rs | 30 ++++++++++++++ src/libcore/str/mod.rs | 78 +++++++++++++++++++++++++---------- 3 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index d97d9b8ab83f6..a7018daf09847 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -28,6 +28,7 @@ #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] +#![feature(utf8_error_resume_from)] extern crate collections; extern crate test; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 8071c7e8c20d5..5de74d68b9eca 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -540,6 +540,36 @@ fn from_utf8_mostly_ascii() { } } +#[test] +fn from_utf8_error() { + macro_rules! test { + ($input: expr, $expected_valid_up_to: expr, $expected_resume_from: expr) => { + let error = from_utf8($input).unwrap_err(); + assert_eq!(error.valid_up_to(), $expected_valid_up_to); + assert_eq!(error.resume_from(), $expected_resume_from); + } + } + test!(b"A\xC3\xA9 \xFF ", 4, Some(5)); + test!(b"A\xC3\xA9 \x80 ", 4, Some(5)); + test!(b"A\xC3\xA9 \xC1 ", 4, Some(5)); + test!(b"A\xC3\xA9 \xC1", 4, Some(5)); + test!(b"A\xC3\xA9 \xC2", 4, None); + test!(b"A\xC3\xA9 \xC2 ", 4, Some(5)); + test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(5)); + test!(b"A\xC3\xA9 \xE0", 4, None); + test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(5)); + test!(b"A\xC3\xA9 \xE0\xA0", 4, None); + test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(6)); + test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(6)); + test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(5)); + test!(b"A\xC3\xA9 \xF1", 4, None); + test!(b"A\xC3\xA9 \xF1\x80", 4, None); + test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None); + test!(b"A\xC3\xA9 \xF1 ", 4, Some(5)); + test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(6)); + test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(7)); +} + #[test] fn test_as_bytes() { // no null diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 52e3301631052..eb13d28e82d23 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -125,13 +125,14 @@ Section: Creating a string #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { valid_up_to: usize, + invalid_length: Option, } impl Utf8Error { /// Returns the index in the given string up to which valid UTF-8 was /// verified. /// - /// It is the maximum index such that `from_utf8(input[..index])` + /// It is the maximum index such that `from_utf8(&input[..index])` /// would return `Ok(_)`. /// /// # Examples @@ -152,6 +153,21 @@ impl Utf8Error { /// ``` #[stable(feature = "utf8_error", since = "1.5.0")] pub fn valid_up_to(&self) -> usize { self.valid_up_to } + + /// Provide more information about the failure: + /// + /// * `None`: the end of the input was reached unexpectedly. + /// `self.valid_up_to()` is 1 to 3 bytes from the end of the input. + /// If a byte stream (such as a file or a network socket) is being decoded incrementally, + /// this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks. + /// + /// * `Some(index)`: an unexpected byte was encountered. + /// The index provided is where decoding should resume + /// (after inserting a U+FFFD REPLACEMENT CHARACTER) in case of lossy decoding. + #[unstable(feature = "utf8_error_resume_from", reason ="new", issue = "0")] + pub fn resume_from(&self) -> Option { + self.invalid_length.map(|l| self.valid_up_to + l as usize) + } } /// Converts a slice of bytes to a string slice. @@ -300,7 +316,12 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "invalid utf-8: invalid byte near index {}", self.valid_up_to) + if let Some(invalid_length) = self.invalid_length { + write!(f, "invalid utf-8 sequence of {} bytes from index {}", + invalid_length, self.valid_up_to) + } else { + write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to) + } } } @@ -1241,17 +1262,20 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { while index < len { let old_offset = index; - macro_rules! err { () => {{ - return Err(Utf8Error { - valid_up_to: old_offset - }) - }}} + macro_rules! err { + ($invalid_length: expr) => { + return Err(Utf8Error { + valid_up_to: old_offset, + invalid_length: $invalid_length, + }) + } + } macro_rules! next { () => {{ index += 1; // we needed data, but there was none: error! if index >= len { - err!() + err!(None) } v[index] }}} @@ -1259,7 +1283,6 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let first = v[index]; if first >= 128 { let w = UTF8_CHAR_WIDTH[first as usize]; - let second = next!(); // 2-byte encoding is for codepoints \u{0080} to \u{07ff} // first C2 80 last DF BF // 3-byte encoding is for codepoints \u{0800} to \u{ffff} @@ -1279,25 +1302,36 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / // %xF4 %x80-8F 2( UTF8-tail ) match w { - 2 => if second & !CONT_MASK != TAG_CONT_U8 {err!()}, + 2 => if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(1)) + }, 3 => { - match (first, second, next!() & !CONT_MASK) { - (0xE0 , 0xA0 ... 0xBF, TAG_CONT_U8) | - (0xE1 ... 0xEC, 0x80 ... 0xBF, TAG_CONT_U8) | - (0xED , 0x80 ... 0x9F, TAG_CONT_U8) | - (0xEE ... 0xEF, 0x80 ... 0xBF, TAG_CONT_U8) => {} - _ => err!() + match (first, next!()) { + (0xE0 , 0xA0 ... 0xBF) | + (0xE1 ... 0xEC, 0x80 ... 0xBF) | + (0xED , 0x80 ... 0x9F) | + (0xEE ... 0xEF, 0x80 ... 0xBF) => {} + _ => err!(Some(1)) + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(2)) } } 4 => { - match (first, second, next!() & !CONT_MASK, next!() & !CONT_MASK) { - (0xF0 , 0x90 ... 0xBF, TAG_CONT_U8, TAG_CONT_U8) | - (0xF1 ... 0xF3, 0x80 ... 0xBF, TAG_CONT_U8, TAG_CONT_U8) | - (0xF4 , 0x80 ... 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {} - _ => err!() + match (first, next!()) { + (0xF0 , 0x90 ... 0xBF) | + (0xF1 ... 0xF3, 0x80 ... 0xBF) | + (0xF4 , 0x80 ... 0x8F) => {} + _ => err!(Some(1)) + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(2)) + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(3)) } } - _ => err!() + _ => err!(Some(1)) } index += 1; } else { From b5f16a10e9406fc1c19294fee1c33e507a17458e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 6 Mar 2017 22:06:30 +0100 Subject: [PATCH 042/662] Replace Utf8Error::resume_from with Utf8Error::error_len Their relationship is: * `resume_from = error_len.map(|l| l + valid_up_to)` * error_len is always one of None, Some(1), Some(2), or Some(3). When I started using resume_from I almost always ended up subtracting valid_up_to to obtain error_len. Therefore the latter is what should be provided in the first place. --- src/libcollectionstest/lib.rs | 2 +- src/libcollectionstest/str.rs | 30 +++++++++++++++--------------- src/libcore/str/mod.rs | 22 ++++++++++++---------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index a7018daf09847..98d0b1c8e1565 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -28,7 +28,7 @@ #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(utf8_error_resume_from)] +#![feature(utf8_error_error_len)] extern crate collections; extern crate test; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 5de74d68b9eca..c9b7104fec4f0 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -543,31 +543,31 @@ fn from_utf8_mostly_ascii() { #[test] fn from_utf8_error() { macro_rules! test { - ($input: expr, $expected_valid_up_to: expr, $expected_resume_from: expr) => { + ($input: expr, $expected_valid_up_to: expr, $expected_error_len: expr) => { let error = from_utf8($input).unwrap_err(); assert_eq!(error.valid_up_to(), $expected_valid_up_to); - assert_eq!(error.resume_from(), $expected_resume_from); + assert_eq!(error.error_len(), $expected_error_len); } } - test!(b"A\xC3\xA9 \xFF ", 4, Some(5)); - test!(b"A\xC3\xA9 \x80 ", 4, Some(5)); - test!(b"A\xC3\xA9 \xC1 ", 4, Some(5)); - test!(b"A\xC3\xA9 \xC1", 4, Some(5)); + test!(b"A\xC3\xA9 \xFF ", 4, Some(1)); + test!(b"A\xC3\xA9 \x80 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xC1 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xC1", 4, Some(1)); test!(b"A\xC3\xA9 \xC2", 4, None); - test!(b"A\xC3\xA9 \xC2 ", 4, Some(5)); - test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(5)); + test!(b"A\xC3\xA9 \xC2 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1)); test!(b"A\xC3\xA9 \xE0", 4, None); - test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(5)); + test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1)); test!(b"A\xC3\xA9 \xE0\xA0", 4, None); - test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(6)); - test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(6)); - test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(5)); + test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2)); + test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2)); + test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1)); test!(b"A\xC3\xA9 \xF1", 4, None); test!(b"A\xC3\xA9 \xF1\x80", 4, None); test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None); - test!(b"A\xC3\xA9 \xF1 ", 4, Some(5)); - test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(6)); - test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(7)); + test!(b"A\xC3\xA9 \xF1 ", 4, Some(1)); + test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2)); + test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3)); } #[test] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index eb13d28e82d23..63b12932c3d62 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -125,7 +125,7 @@ Section: Creating a string #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { valid_up_to: usize, - invalid_length: Option, + error_len: Option, } impl Utf8Error { @@ -161,12 +161,14 @@ impl Utf8Error { /// If a byte stream (such as a file or a network socket) is being decoded incrementally, /// this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks. /// - /// * `Some(index)`: an unexpected byte was encountered. - /// The index provided is where decoding should resume + /// * `Some(len)`: an unexpected byte was encountered. + /// The length provided is that of the invalid byte sequence + /// that starts at the index given by `valid_up_to()`. + /// Decoding should resume after that sequence /// (after inserting a U+FFFD REPLACEMENT CHARACTER) in case of lossy decoding. - #[unstable(feature = "utf8_error_resume_from", reason ="new", issue = "0")] - pub fn resume_from(&self) -> Option { - self.invalid_length.map(|l| self.valid_up_to + l as usize) + #[unstable(feature = "utf8_error_error_len", reason ="new", issue = "0")] + pub fn error_len(&self) -> Option { + self.error_len.map(|len| len as usize) } } @@ -316,9 +318,9 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(invalid_length) = self.invalid_length { + if let Some(error_len) = self.error_len { write!(f, "invalid utf-8 sequence of {} bytes from index {}", - invalid_length, self.valid_up_to) + error_len, self.valid_up_to) } else { write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to) } @@ -1263,10 +1265,10 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { while index < len { let old_offset = index; macro_rules! err { - ($invalid_length: expr) => { + ($error_len: expr) => { return Err(Utf8Error { valid_up_to: old_offset, - invalid_length: $invalid_length, + error_len: $error_len, }) } } From 73370c543ea130a3d6d9097aa56b786c72dc6c94 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 13 Mar 2017 23:54:06 +0100 Subject: [PATCH 043/662] Add tracking issue number for Utf8Error::error_len --- src/libcore/str/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 63b12932c3d62..2919adc1cbc63 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -166,7 +166,7 @@ impl Utf8Error { /// that starts at the index given by `valid_up_to()`. /// Decoding should resume after that sequence /// (after inserting a U+FFFD REPLACEMENT CHARACTER) in case of lossy decoding. - #[unstable(feature = "utf8_error_error_len", reason ="new", issue = "0")] + #[unstable(feature = "utf8_error_error_len", reason ="new", issue = "40494")] pub fn error_len(&self) -> Option { self.error_len.map(|len| len as usize) } From 0671cc10f03c1c487b33abe89ae2c1db2271f520 Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Tue, 14 Mar 2017 20:52:01 +0800 Subject: [PATCH 044/662] .gitmodules: use official URLs w/o redirect --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 9bc2a6a70eb45..a7063bbddc5f0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,10 +20,10 @@ url = https://github.com/rust-lang/libc.git [submodule "src/doc/nomicon"] path = src/doc/nomicon - url = https://github.com/rust-lang-nursery/nomicon + url = https://github.com/rust-lang-nursery/nomicon.git [submodule "src/tools/cargo"] path = cargo - url = https://github.com/rust-lang/cargo + url = https://github.com/rust-lang/cargo.git [submodule "reference"] path = src/doc/reference url = https://github.com/rust-lang-nursery/reference.git From 8af30132f14737a8d41db48aad9e78df396d8990 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Tue, 14 Mar 2017 14:01:01 +0100 Subject: [PATCH 045/662] Inline functions Ordering::{then, then_with} @jongiddy noticed bad performance due to the lack of inlining on `then` and `then_with`. I confirmed that inlining really is the culprit by creating a custom `then` function and repeating his benchmark on my machine with and without the `#[inline]` attribute. The numbers were exactly the same on my machine without the attribute. With `#[inline]` I got the same performance as I did with manually inlined implementation. --- src/libcore/cmp.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index cc066099cf8b0..b43fe757d8473 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -277,6 +277,7 @@ impl Ordering { /// /// assert_eq!(result, Ordering::Less); /// ``` + #[inline] #[unstable(feature = "ordering_chaining", issue = "37053")] pub fn then(self, other: Ordering) -> Ordering { match self { @@ -315,6 +316,7 @@ impl Ordering { /// /// assert_eq!(result, Ordering::Less); /// ``` + #[inline] #[unstable(feature = "ordering_chaining", issue = "37053")] pub fn then_with Ordering>(self, f: F) -> Ordering { match self { From 9a7b789c3717146ca3ce3fca1eb23fa3a239f0fb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 15:04:32 -0400 Subject: [PATCH 046/662] Add doc example for `OsStr::to_os_string`. --- src/libstd/ffi/os_str.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 41bdd9c51d458..3914f398961e4 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -398,6 +398,16 @@ impl OsStr { /// Copies the slice into an owned [`OsString`]. /// /// [`OsString`]: struct.OsString.html + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsStr, OsString}; + /// + /// let os_str = OsStr::new("foo"); + /// let os_string = os_str.to_os_string(); + /// assert_eq!(os_string, OsString::from("foo")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } From 4d57d92f071d24a4c189cc8aef897be25bcd9d55 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 16:21:34 -0400 Subject: [PATCH 047/662] Add doc example for `OsString::reserve`. --- src/libstd/ffi/os_str.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 3914f398961e4..bdd8ce5e6d854 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -188,6 +188,16 @@ impl OsString { /// in the given `OsString`. /// /// The collection may reserve more space to avoid frequent reallocations. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::new(); + /// s.reserve(10); + /// assert!(s.capacity() >= 10); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) From 5537955b1747f8f8c873cf7681ec8a497404e730 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 16:21:58 -0400 Subject: [PATCH 048/662] Add doc example for `OsString::reserve_exact`. --- src/libstd/ffi/os_str.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index bdd8ce5e6d854..d960d76146fe9 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -210,6 +210,16 @@ impl OsString { /// Note that the allocator may give the collection more space than it /// requests. Therefore capacity can not be relied upon to be precisely /// minimal. Prefer reserve if future insertions are expected. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::new(); + /// s.reserve_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) From bda57dbc059a15222173b40a5e4d7e5579adcfec Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 16:22:12 -0400 Subject: [PATCH 049/662] Add doc example for `OsString::shrink_to_fit`. --- src/libstd/ffi/os_str.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index d960d76146fe9..9da6eca34086e 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -226,6 +226,22 @@ impl OsString { } /// Shrinks the capacity of the `OsString` to match its length. + /// + /// # Examples + /// + /// ``` + /// #![feature(osstring_shrink_to_fit)] + /// + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to_fit(); + /// assert_eq!(3, s.capacity()); + /// ``` #[unstable(feature = "osstring_shrink_to_fit", issue = "40421")] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() From 6adbbfc6ba8786ea91e1051ea14d64a91839f5b5 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 12 Mar 2017 16:22:29 -0400 Subject: [PATCH 050/662] Add doc example for `OsString::into_boxed_os_str`. --- src/libstd/ffi/os_str.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 9da6eca34086e..b0f79f9a395a6 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -248,6 +248,18 @@ impl OsString { } /// Converts this `OsString` into a boxed `OsStr`. + /// + /// # Examples + /// + /// ``` + /// #![feature(into_boxed_os_str)] + /// + /// use std::ffi::{OsString, OsStr}; + /// + /// let s = OsString::from("hello"); + /// + /// let b: Box = s.into_boxed_os_str(); + /// ``` #[unstable(feature = "into_boxed_os_str", issue = "0")] pub fn into_boxed_os_str(self) -> Box { unsafe { mem::transmute(self.inner.into_box()) } From b43c744318b76934cdbcc0c8a4fdbc7d0091bbd8 Mon Sep 17 00:00:00 2001 From: Tobias Schottdorf Date: Sat, 11 Mar 2017 10:54:45 -0500 Subject: [PATCH 051/662] Add feature toggle for rvalue-static-promotion RFC See https://github.com/rust-lang/rfcs/pull/1414. Updates #38865. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../src/rvalue-static-promotion.md | 5 +++++ src/librustc/middle/mem_categorization.rs | 5 ++--- src/libsyntax/feature_gate.rs | 3 +++ .../feature-gate-rvalue_static_promotion.rs | 15 +++++++++++++++ src/test/run-pass/rvalue-static-promotion.rs | 17 +++++++++++++++++ 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/doc/unstable-book/src/rvalue-static-promotion.md create mode 100644 src/test/compile-fail/feature-gate-rvalue_static_promotion.rs create mode 100644 src/test/run-pass/rvalue-static-promotion.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 5fb323d6ce909..034f9f4eb2523 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -71,6 +71,7 @@ - [repr_simd](repr-simd.md) - [rustc_attrs](rustc-attrs.md) - [rustc_diagnostic_macros](rustc-diagnostic-macros.md) +- [rvalue_static_promotion](rvalue-static-promotion.md) - [sanitizer_runtime](sanitizer-runtime.md) - [simd](simd.md) - [simd_ffi](simd-ffi.md) diff --git a/src/doc/unstable-book/src/rvalue-static-promotion.md b/src/doc/unstable-book/src/rvalue-static-promotion.md new file mode 100644 index 0000000000000..3b654960c8e3c --- /dev/null +++ b/src/doc/unstable-book/src/rvalue-static-promotion.md @@ -0,0 +1,5 @@ +# `rvalue_static_promotion` + +The tracking issue for this feature is: [#38865] + +------------------------ diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b0c85e2ef4cd4..a669ac3a69b98 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -843,11 +843,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned() .unwrap_or(false); - // Only promote `[T; 0]` before an RFC for rvalue promotions - // is accepted. + // When the corresponding feature isn't toggled, only promote `[T; 0]`. let promotable = match expr_ty.sty { ty::TyArray(_, 0) => true, - _ => promotable & false + _ => promotable & self.tcx().sess.features.borrow().rvalue_static_promotion, }; // Compute maximum lifetime of this rvalue. This is 'static if diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 15913d56d162f..59e9ab30e0e8c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -342,6 +342,9 @@ declare_features! ( // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), + + // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. + (active, rvalue_static_promotion, "1.15.1", Some(38865)), ); declare_features! ( diff --git a/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs b/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs new file mode 100644 index 0000000000000..41dc282be41f0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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(unused_variables)] +fn main() { + let x: &'static u32 = &42; //~ error: does not live long enough + let y: &'static Option = &None; //~ error: does not live long enough +} \ No newline at end of file diff --git a/src/test/run-pass/rvalue-static-promotion.rs b/src/test/run-pass/rvalue-static-promotion.rs new file mode 100644 index 0000000000000..f8d93783877bb --- /dev/null +++ b/src/test/run-pass/rvalue-static-promotion.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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(rvalue_static_promotion)] + +#[allow(unused_variables)] +fn main() { + let x: &'static u32 = &42; + let y: &'static Option = &None; +} \ No newline at end of file From 20c0f323fc26fb913256301e242f34bccc788e31 Mon Sep 17 00:00:00 2001 From: Tobias Schottdorf Date: Sun, 12 Mar 2017 00:24:11 -0500 Subject: [PATCH 052/662] Use `&&` instead of `&` It does not seem valuable to always evaluate the right-hand side here. --- src/librustc/middle/mem_categorization.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a669ac3a69b98..a1deda0ab3ec1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -846,7 +846,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // When the corresponding feature isn't toggled, only promote `[T; 0]`. let promotable = match expr_ty.sty { ty::TyArray(_, 0) => true, - _ => promotable & self.tcx().sess.features.borrow().rvalue_static_promotion, + _ => promotable && self.tcx().sess.features.borrow().rvalue_static_promotion, }; // Compute maximum lifetime of this rvalue. This is 'static if From f06b04949f7944bfe31405d3735240bb02ee9bd1 Mon Sep 17 00:00:00 2001 From: Tobias Schottdorf Date: Sun, 12 Mar 2017 18:31:17 -0400 Subject: [PATCH 053/662] Improve the documentation for `rvalue_static_promotion` --- .../src/rvalue-static-promotion.md | 18 ++++++++++++++++++ .../feature-gate-rvalue_static_promotion.rs | 2 +- src/test/run-pass/rvalue-static-promotion.rs | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/rvalue-static-promotion.md b/src/doc/unstable-book/src/rvalue-static-promotion.md index 3b654960c8e3c..2583d350ebe11 100644 --- a/src/doc/unstable-book/src/rvalue-static-promotion.md +++ b/src/doc/unstable-book/src/rvalue-static-promotion.md @@ -2,4 +2,22 @@ The tracking issue for this feature is: [#38865] +[#38865]: https://github.com/rust-lang/rust/issues/38865 + ------------------------ + +The `rvalue_static_promotion` feature allows directly creating `'static` references to +constant `rvalue`s, which in particular allowing for more concise code in the common case +in which a `'static` reference is all that's needed. + + +## Examples + +```rust +#![feature(rvalue_static_promotion)] + +fn main() { + let DEFAULT_VALUE: &'static u32 = &42; + assert_eq!(*DEFAULT_VALUE, 42); +} +``` diff --git a/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs b/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs index 41dc282be41f0..f33d0a71481d2 100644 --- a/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs +++ b/src/test/compile-fail/feature-gate-rvalue_static_promotion.rs @@ -12,4 +12,4 @@ fn main() { let x: &'static u32 = &42; //~ error: does not live long enough let y: &'static Option = &None; //~ error: does not live long enough -} \ No newline at end of file +} diff --git a/src/test/run-pass/rvalue-static-promotion.rs b/src/test/run-pass/rvalue-static-promotion.rs index f8d93783877bb..30643cfc3eb7d 100644 --- a/src/test/run-pass/rvalue-static-promotion.rs +++ b/src/test/run-pass/rvalue-static-promotion.rs @@ -14,4 +14,4 @@ fn main() { let x: &'static u32 = &42; let y: &'static Option = &None; -} \ No newline at end of file +} From cc08edc85425b42073a93d366059aa258690a730 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 14 Mar 2017 11:16:34 -0400 Subject: [PATCH 054/662] Remove incorrect feature from the 1.16 relnotes --- RELEASES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 606936778c49a..224bd2420a93f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,7 +4,6 @@ Version 1.16.0 (2017-03-16) Language -------- -* Lifetimes in statics and consts default to `'static`. [RFC 1623] * [The compiler's `dead_code` lint now accounts for type aliases][38051]. * [Uninhabitable enums (those without any variants) no longer permit wildcard match patterns][38069] From 61d93877b70cfb9cab974ef2fb3c60d9cb50f72f Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Mon, 13 Mar 2017 11:36:44 -0700 Subject: [PATCH 055/662] Target builds for older macOS --- .travis.yml | 10 ++++++++++ src/bootstrap/compile.rs | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/.travis.yml b/.travis.yml index 988ef66f8fadd..ba70497ba3fd9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,8 @@ matrix: RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log RUST_LOG=sccache=debug + MACOSX_DEPLOYMENT_TARGET=10.8 + MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx osx_image: xcode8.2 install: &osx_install_sccache > @@ -60,6 +62,8 @@ matrix: RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log RUST_LOG=sccache=debug + MACOSX_DEPLOYMENT_TARGET=10.8 + MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx osx_image: xcode8.2 install: *osx_install_sccache @@ -72,6 +76,8 @@ matrix: RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log RUST_LOG=sccache=debug + MACOSX_DEPLOYMENT_TARGET=10.8 + MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx osx_image: xcode8.2 install: > @@ -85,6 +91,8 @@ matrix: RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log RUST_LOG=sccache=debug + MACOSX_DEPLOYMENT_TARGET=10.8 + MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx osx_image: xcode8.2 install: *osx_install_sccache @@ -102,6 +110,8 @@ matrix: RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log RUST_LOG=sccache=debug + MACOSX_DEPLOYMENT_TARGET=10.8 + MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx osx_image: xcode8.2 install: *osx_install_sccache diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 3459c1d2b8425..af1f43eb4c1ae 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -20,6 +20,7 @@ use std::collections::HashMap; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; +use std::env; use build_helper::{output, mtime, up_to_date}; use filetime::FileTime; @@ -44,6 +45,11 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) { build.clear_if_dirty(&out_dir, &build.compiler_path(compiler)); let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build"); let mut features = build.std_features(); + + if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") { + cargo.env("MACOSX_DEPLOYMENT_TARGET", target); + } + // When doing a local rebuild we tell cargo that we're stage1 rather than // stage0. This works fine if the local rust and being-built rust have the // same view of what the default allocator is, but fails otherwise. Since @@ -170,6 +176,9 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) { let out_dir = build.cargo_out(compiler, Mode::Libtest, target); build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); + if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") { + cargo.env("MACOSX_DEPLOYMENT_TARGET", target); + } cargo.arg("--manifest-path") .arg(build.src.join("src/libtest/Cargo.toml")); build.run(&mut cargo); From 8b7c7f3fa5c24d573c9aaa9d08e6628721833536 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 14 Mar 2017 13:42:12 -0400 Subject: [PATCH 056/662] Link core::slice to std::slice --- src/libcore/slice.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 0331c5d4ba401..22658f9a81b0d 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -10,7 +10,9 @@ //! Slice management and manipulation //! -//! For more details `std::slice`. +//! For more details see [`std::slice`]. +//! +//! [`std::slice`]: ../../std/slice/index.html #![stable(feature = "rust1", since = "1.0.0")] From e3b8550a601ca920284f91ceff30a29340832fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 13 Mar 2017 19:07:47 -0700 Subject: [PATCH 057/662] Point out correct turbofish usage on `Foo>` Whenever we parse a chain of binary operations, as long as the first operation is `<` and the subsequent operations are either `>` or `<`, present the following diagnostic help: use `::<...>` instead of `<...>` if you meant to specify type arguments This will lead to spurious recommendations on situations like `2 < 3 < 4` but should be clear from context that the help doesn't apply in that case. --- src/libsyntax/parse/parser.rs | 5 ++- src/test/ui/did_you_mean/issue-40396.rs | 23 ++++++++++++++ src/test/ui/did_you_mean/issue-40396.stderr | 34 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/did_you_mean/issue-40396.rs create mode 100644 src/test/ui/did_you_mean/issue-40396.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8f66c1a2b8cf6..208db8391441c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2919,7 +2919,10 @@ impl<'a> Parser<'a> { let op_span = mk_sp(op.span.lo, self.span.hi); let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); - if op.node == BinOpKind::Lt && *outer_op == AssocOp::Greater { + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo>> err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs new file mode 100644 index 0000000000000..1eae180976ad3 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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 foo() { + println!("{:?}", (0..13).collect>()); +} + +fn bar() { + println!("{:?}", Vec::new()); +} + +fn qux() { + println!("{:?}", (0..13).collect()); +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr new file mode 100644 index 0000000000000..1a0c74dc01a09 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -0,0 +1,34 @@ +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:12:37 + | +12 | println!("{:?}", (0..13).collect>()); + | ^^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:16:25 + | +16 | println!("{:?}", Vec::new()); + | ^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:20:37 + | +20 | println!("{:?}", (0..13).collect()); + | ^^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:20:41 + | +20 | println!("{:?}", (0..13).collect()); + | ^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: aborting due to 4 previous errors + From 3554ff32db74b431dfb356cc4533514544c67bf9 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 14 Mar 2017 19:31:20 +0000 Subject: [PATCH 058/662] Make docs required again --- src/tools/build-manifest/src/main.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index c2ec42195fcb7..adddd7b7e89b0 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -250,12 +250,13 @@ impl Builder { let mut components = Vec::new(); let mut extensions = Vec::new(); - // rustc/rust-std/cargo are all required, and so is rust-mingw if it's - // available for the target. + // rustc/rust-std/cargo/docs are all required, and so is rust-mingw + // if it's available for the target. components.extend(vec![ Component { pkg: "rustc".to_string(), target: host.to_string() }, Component { pkg: "rust-std".to_string(), target: host.to_string() }, Component { pkg: "cargo".to_string(), target: host.to_string() }, + Component { pkg: "rust-docs".to_string(), target: host.to_string() }, ]); if host.contains("pc-windows-gnu") { components.push(Component { @@ -264,12 +265,6 @@ impl Builder { }); } - // Docs, other standard libraries, and the source package are all - // optional. - extensions.push(Component { - pkg: "rust-docs".to_string(), - target: host.to_string(), - }); for target in TARGETS { if target != host { extensions.push(Component { From 18a8494485569641ba27d9adf5c9057fdc966d38 Mon Sep 17 00:00:00 2001 From: Eric Findlay Date: Wed, 15 Mar 2017 10:05:55 +0900 Subject: [PATCH 059/662] Ammended minor documentation detail abour Unicode cases. --- src/libstd_unicode/char.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index f5dfd9fa471f1..def2b7cc36d3d 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -829,7 +829,8 @@ impl char { /// // Sometimes the result is more than one character: /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); /// - /// // Japanese kanji characters do not have case, and so: + /// // Characters that do not have both uppercase and lowercase + /// // convert into themselves. /// assert_eq!('山'.to_lowercase().to_string(), "山"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -889,7 +890,8 @@ impl char { /// // Sometimes the result is more than one character: /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); /// - /// // Japanese kanji characters do not have case, and so: + /// // Characters that do not have both uppercase and lowercase + /// // convert into themselves. /// assert_eq!('山'.to_uppercase().to_string(), "山"); /// ``` /// From cc23d17ce9288cee77f0441018a248a6bd106880 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 14 Mar 2017 16:35:11 +0100 Subject: [PATCH 060/662] make shift builtins panic-free with new unchecked_sh* intrinsics Also update some 128 bit builtins to be panic-free without relying on the const evaluator. --- src/libcompiler_builtins/lib.rs | 18 ++-- src/libcore/intrinsics.rs | 9 ++ src/libcore/num/mod.rs | 113 +++++++++++++++++++++---- src/librustc_trans/intrinsic.rs | 9 +- src/librustc_typeck/check/intrinsic.rs | 2 + 5 files changed, 123 insertions(+), 28 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index fb42b915c7694..58aba11e4394f 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -34,8 +34,8 @@ pub mod reimpls { macro_rules! ashl { ($a:expr, $b:expr, $ty:ty) => {{ let (a, b) = ($a, $b); - let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; - let half_bits = bits >> 1; + let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty; + let half_bits = bits.wrapping_shr(1); if b & half_bits != 0 { <$ty>::from_parts(0, a.low().wrapping_shl( b.wrapping_sub(half_bits) as u32)) @@ -58,8 +58,8 @@ pub mod reimpls { macro_rules! ashr { ($a: expr, $b: expr, $ty:ty) => {{ let (a, b) = ($a, $b); - let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; - let half_bits = bits >> 1; + let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty; + let half_bits = bits.wrapping_shr(1); if b & half_bits != 0 { <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32) as <$ty as LargeInt>::LowHalf, @@ -83,8 +83,8 @@ pub mod reimpls { macro_rules! lshr { ($a: expr, $b: expr, $ty:ty) => {{ let (a, b) = ($a, $b); - let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; - let half_bits = bits >> 1; + let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty; + let half_bits = bits.wrapping_shr(1); if b & half_bits != 0 { <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0) } else if b == 0 { @@ -370,7 +370,7 @@ pub mod reimpls { macro_rules! mul { ($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{ let (a, b) = ($a, $b); - let half_bits = ((::core::mem::size_of::<$tyh>() * 8) / 2) as u32; + let half_bits = ::core::mem::size_of::<$tyh>().wrapping_mul(4) as u32; let lower_mask = (!0u64).wrapping_shr(half_bits); let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); let mut t = low.wrapping_shr(half_bits); @@ -478,7 +478,7 @@ pub mod reimpls { let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; if sign == -1.0 || exponent < 0 { return 0 as u128; } - if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 { return !(0 as u128); } (if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { @@ -503,7 +503,7 @@ pub mod reimpls { let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; if exponent < 0 { return 0 as i128; } - if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 { let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; return ret } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 12410c08f399b..f8d067e9696fd 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1238,6 +1238,15 @@ extern "rust-intrinsic" { /// undefined behavior where y = 0 or x = `T::min_value()` and y = -1 pub fn unchecked_rem(x: T, y: T) -> T; + /// Performs an unchecked left shift, resulting in undefined behavior when + /// y < 0 or y >= N, where N is the width of T in bits. + #[cfg(not(stage0))] + pub fn unchecked_shl(x: T, y: T) -> T; + /// Performs an unchecked right shift, resulting in undefined behavior when + /// y < 0 or y >= N, where N is the width of T in bits. + #[cfg(not(stage0))] + pub fn unchecked_shr(x: T, y: T) -> T; + /// Returns (a + b) mod 2^N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97ea6bb347b54..d12002fdfa7f2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -177,7 +177,7 @@ macro_rules! checked_op { // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { - ($ActualT:ident, $UnsignedT:ty, $BITS:expr, + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $add_with_overflow:path, $sub_with_overflow:path, $mul_with_overflow:path) => { @@ -850,6 +850,16 @@ macro_rules! int_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] + #[cfg(not(stage0))] + pub fn wrapping_shl(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + + /// Stage 0 + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[cfg(stage0)] pub fn wrapping_shl(self, rhs: u32) -> Self { self.overflowing_shl(rhs).0 } @@ -875,6 +885,16 @@ macro_rules! int_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] + #[cfg(not(stage0))] + pub fn wrapping_shr(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + + /// Stage 0 + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[cfg(stage0)] pub fn wrapping_shr(self, rhs: u32) -> Self { self.overflowing_shr(rhs).0 } @@ -1089,6 +1109,15 @@ macro_rules! int_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(not(stage0))] + pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + + /// Stage 0 + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(stage0)] pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) } @@ -1111,6 +1140,15 @@ macro_rules! int_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(not(stage0))] + pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + + /// Stage 0 + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(stage0)] pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) } @@ -1268,7 +1306,7 @@ macro_rules! int_impl { #[lang = "i8"] impl i8 { - int_impl! { i8, u8, 8, + int_impl! { i8, i8, u8, 8, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1276,7 +1314,7 @@ impl i8 { #[lang = "i16"] impl i16 { - int_impl! { i16, u16, 16, + int_impl! { i16, i16, u16, 16, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1284,7 +1322,7 @@ impl i16 { #[lang = "i32"] impl i32 { - int_impl! { i32, u32, 32, + int_impl! { i32, i32, u32, 32, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1292,7 +1330,7 @@ impl i32 { #[lang = "i64"] impl i64 { - int_impl! { i64, u64, 64, + int_impl! { i64, i64, u64, 64, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1300,7 +1338,7 @@ impl i64 { #[lang = "i128"] impl i128 { - int_impl! { i128, u128, 128, + int_impl! { i128, i128, u128, 128, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1309,7 +1347,7 @@ impl i128 { #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { - int_impl! { i16, u16, 16, + int_impl! { isize, i16, u16, 16, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1318,7 +1356,7 @@ impl isize { #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { - int_impl! { i32, u32, 32, + int_impl! { isize, i32, u32, 32, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1327,7 +1365,7 @@ impl isize { #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - int_impl! { i64, u64, 64, + int_impl! { isize, i64, u64, 64, intrinsics::add_with_overflow, intrinsics::sub_with_overflow, intrinsics::mul_with_overflow } @@ -1335,7 +1373,7 @@ impl isize { // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { - ($ActualT:ty, $BITS:expr, + ($SelfT:ty, $ActualT:ty, $BITS:expr, $ctpop:path, $ctlz:path, $cttz:path, @@ -1978,6 +2016,16 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] + #[cfg(not(stage0))] + pub fn wrapping_shl(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + + /// Stage 0 + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[cfg(stage0)] pub fn wrapping_shl(self, rhs: u32) -> Self { self.overflowing_shl(rhs).0 } @@ -2003,6 +2051,16 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] + #[cfg(not(stage0))] + pub fn wrapping_shr(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + + /// Stage 0 + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[cfg(stage0)] pub fn wrapping_shr(self, rhs: u32) -> Self { self.overflowing_shr(rhs).0 } @@ -2170,6 +2228,15 @@ macro_rules! uint_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(not(stage0))] + pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + + /// Stage 0 + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(stage0)] pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) } @@ -2192,6 +2259,16 @@ macro_rules! uint_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(not(stage0))] + pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + + } + + /// Stage 0 + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[cfg(stage0)] pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) } @@ -2292,7 +2369,7 @@ macro_rules! uint_impl { #[lang = "u8"] impl u8 { - uint_impl! { u8, 8, + uint_impl! { u8, u8, 8, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2304,7 +2381,7 @@ impl u8 { #[lang = "u16"] impl u16 { - uint_impl! { u16, 16, + uint_impl! { u16, u16, 16, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2316,7 +2393,7 @@ impl u16 { #[lang = "u32"] impl u32 { - uint_impl! { u32, 32, + uint_impl! { u32, u32, 32, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2328,7 +2405,7 @@ impl u32 { #[lang = "u64"] impl u64 { - uint_impl! { u64, 64, + uint_impl! { u64, u64, 64, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2340,7 +2417,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, 128, + uint_impl! { u128, u128, 128, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2353,7 +2430,7 @@ impl u128 { #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { - uint_impl! { u16, 16, + uint_impl! { usize, u16, 16, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2365,7 +2442,7 @@ impl usize { #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { - uint_impl! { u32, 32, + uint_impl! { usize, u32, 32, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, @@ -2378,7 +2455,7 @@ impl usize { #[cfg(target_pointer_width = "64")] #[lang = "usize"] impl usize { - uint_impl! { u64, 64, + uint_impl! { usize, u64, 64, intrinsics::ctpop, intrinsics::ctlz, intrinsics::cttz, diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b7aedb742db02..762bf8592ffcc 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -261,7 +261,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, "ctlz" | "cttz" | "ctpop" | "bswap" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | - "unchecked_div" | "unchecked_rem" => { + "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => { let sty = &arg_tys[0].sty; match int_type_width_signed(sty, ccx) { Some((width, signed)) => @@ -311,6 +311,13 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } else { bcx.urem(llargs[0], llargs[1]) }, + "unchecked_shl" => bcx.shl(llargs[0], llargs[1]), + "unchecked_shr" => + if signed { + bcx.ashr(llargs[0], llargs[1]) + } else { + bcx.lshr(llargs[0], llargs[1]) + }, _ => bug!(), }, None => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 28996b40cfdfe..2861fd288326b 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -273,6 +273,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "unchecked_div" | "unchecked_rem" => (1, vec![param(0), param(0)], param(0)), + "unchecked_shl" | "unchecked_shr" => + (1, vec![param(0), param(0)], param(0)), "overflowing_add" | "overflowing_sub" | "overflowing_mul" => (1, vec![param(0), param(0)], param(0)), From fee1f64434d5e6e13b803a218bf51796222c89f3 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 14 Mar 2017 15:16:44 +1300 Subject: [PATCH 061/662] save-analysis: depend on the rls-data crate --- src/Cargo.lock | 53 +++++++++++++++++++++------ src/librustc_save_analysis/Cargo.toml | 3 +- src/librustc_save_analysis/lib.rs | 2 + 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index b34007db8ac7a..f7fcedf26d5ef 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -48,6 +48,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "arena" version = "0.0.0" +[[package]] +name = "atty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.5.0" @@ -55,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -94,17 +104,17 @@ version = "0.1.0" [[package]] name = "clap" -version = "2.20.5" +version = "2.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -274,7 +284,7 @@ name = "mdbook" version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -397,11 +407,28 @@ name = "regex-syntax" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rls-data" +version = "0.1.0" +source = "git+https://github.com/nrc/rls-data#eb8de823771ef33edf78dc18fc0b279e6c4b6336" +dependencies = [ + "rls-span 0.1.0 (git+https://github.com/nrc/rls-span)", + "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rls-span" +version = "0.1.0" +source = "git+https://github.com/nrc/rls-span#e9224b1c52d1d43f9f7b3bb065653c9e18bb532d" +dependencies = [ + "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -690,6 +717,7 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.0.0", + "rls-data 0.1.0 (git+https://github.com/nrc/rls-data)", "rustc 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -940,7 +968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vec_map" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -961,9 +989,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" +"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758" +"checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" +"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" "checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" @@ -987,6 +1016,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" +"checksum rls-data 0.1.0 (git+https://github.com/nrc/rls-data)" = "" +"checksum rls-span 0.1.0 (git+https://github.com/nrc/rls-span)" = "" "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" "checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f" "checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" @@ -1000,7 +1031,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" +"checksum vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cdc8b93bd0198ed872357fb2e667f7125646b1762f16d60b2c96350d361897" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 3d66e5a300787..130e4fd6266fb 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -13,4 +13,5 @@ log = { path = "../liblog" } rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } +rls-data = { git = "https://github.com/nrc/rls-data" } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 111c8370be2b1..39b47b1645a70 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -29,6 +29,8 @@ extern crate serialize as rustc_serialize; extern crate syntax_pos; +extern crate rls_data; + mod csv_dumper; mod json_api_dumper; From a77e52875b13ec4554cf963b3b0e25743772752d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 14 Mar 2017 17:08:47 +1300 Subject: [PATCH 062/662] Change json dumper (and a few other bits and pieces) to use rls-data rather than its own data structures --- src/librustc_save_analysis/csv_dumper.rs | 6 +- src/librustc_save_analysis/data.rs | 10 +- src/librustc_save_analysis/dump.rs | 2 + src/librustc_save_analysis/dump_visitor.rs | 2 + src/librustc_save_analysis/external_data.rs | 109 ++-- src/librustc_save_analysis/json_api_dumper.rs | 2 + src/librustc_save_analysis/json_dumper.rs | 528 +++++++----------- 7 files changed, 261 insertions(+), 398 deletions(-) diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index 0fd95500422ff..59340ae87ee5d 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -13,6 +13,8 @@ use std::io::Write; use super::external_data::*; use super::dump::Dump; +use rls_data::{SpanData, CratePreludeData}; + pub struct CsvDumper<'b, W: 'b> { output: &'b mut W } @@ -429,6 +431,6 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String { fn span_extent_str(span: SpanData) -> String { format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{},\ file_line_end,{},file_col_end,{},byte_end,{}", - span.file_name, span.line_start, span.column_start, span.byte_start, - span.line_end, span.column_end, span.byte_end) + span.file_name.to_str().unwrap(), span.line_start.0, span.column_start.0, + span.byte_start, span.line_end.0, span.column_end.0, span.byte_end) } diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 6caf81380e40d..6a80b703d9da3 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -18,6 +18,8 @@ use rustc::hir::def_id::{CrateNum, DefId}; use syntax::ast::{self, Attribute, NodeId}; use syntax_pos::Span; +use rls_data::ExternalCrateData; + pub struct CrateData { pub name: String, pub number: u32, @@ -115,14 +117,6 @@ pub struct CratePreludeData { pub span: Span, } -/// Data for external crates in the prelude of a crate. -#[derive(Debug, RustcEncodable)] -pub struct ExternalCrateData { - pub name: String, - pub num: CrateNum, - pub file_name: String, -} - /// Data for enum declarations. #[derive(Clone, Debug, RustcEncodable)] pub struct EnumData { diff --git a/src/librustc_save_analysis/dump.rs b/src/librustc_save_analysis/dump.rs index 18241b394cc17..84e1fb03f624e 100644 --- a/src/librustc_save_analysis/dump.rs +++ b/src/librustc_save_analysis/dump.rs @@ -10,6 +10,8 @@ use super::external_data::*; +use rls_data::CratePreludeData; + pub trait Dump { fn crate_prelude(&mut self, CratePreludeData) {} fn enum_data(&mut self, EnumData) {} diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 61956e5cd9d66..85bef9f3170ac 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -54,6 +54,8 @@ use super::external_data::{Lower, make_def_id}; use super::span_utils::SpanUtils; use super::recorder; +use rls_data::ExternalCrateData; + macro_rules! down_cast_data { ($id:ident, $kind:ident, $sp:expr) => { let $id = if let super::Data::$kind(data) = $id { diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 41658dc5b1b48..3555887007499 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -17,8 +17,12 @@ use syntax::print::pprust; use syntax::symbol::Symbol; use syntax_pos::Span; +use std::path::PathBuf; + use data::{self, Visibility, SigElement}; +use rls_data::{SpanData, CratePreludeData}; + // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet pub trait Lower { type Target; @@ -36,41 +40,26 @@ pub fn null_def_id() -> DefId { } } -#[derive(Clone, Debug, RustcEncodable)] -pub struct SpanData { - pub file_name: String, - pub byte_start: u32, - pub byte_end: u32, - /// 1-based. - pub line_start: usize, - pub line_end: usize, - /// 1-based, character offset. - pub column_start: usize, - pub column_end: usize, -} - -impl SpanData { - pub fn from_span(span: Span, cm: &CodeMap) -> SpanData { - let start = cm.lookup_char_pos(span.lo); - let end = cm.lookup_char_pos(span.hi); - - SpanData { - file_name: start.file.name.clone(), - byte_start: span.lo.0, - byte_end: span.hi.0, - line_start: start.line, - line_end: end.line, - column_start: start.col.0 + 1, - column_end: end.col.0 + 1, - } +pub fn span_from_span(span: Span, cm: &CodeMap) -> SpanData { + let start = cm.lookup_char_pos(span.lo); + let end = cm.lookup_char_pos(span.hi); + + SpanData { + file_name: start.file.name.clone().into(), + byte_start: span.lo.0, + byte_end: span.hi.0, + line_start: start.line, + line_end: end.line, + column_start: start.col.0 + 1, + column_end: end.col.0 + 1, } } /// Represent an arbitrary attribute on a code element #[derive(Clone, Debug, RustcEncodable)] pub struct Attribute { - value: String, - span: SpanData, + pub value: String, + pub span: SpanData, } impl Lower for Vec { @@ -93,20 +82,12 @@ impl Lower for Vec { Attribute { value: value, - span: SpanData::from_span(attr.span, tcx.sess.codemap()), + span: span_from_span(attr.span, tcx.sess.codemap()), } }).collect() } } -#[derive(Debug, RustcEncodable)] -pub struct CratePreludeData { - pub crate_name: String, - pub crate_root: String, - pub external_crates: Vec, - pub span: SpanData, -} - impl Lower for data::CratePreludeData { type Target = CratePreludeData; @@ -115,7 +96,7 @@ impl Lower for data::CratePreludeData { crate_name: self.crate_name, crate_root: self.crate_root, external_crates: self.external_crates, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), } } } @@ -145,7 +126,7 @@ impl Lower for data::EnumData { name: self.name, value: self.value, qualname: self.qualname, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), visibility: self.visibility, @@ -176,7 +157,7 @@ impl Lower for data::ExternCrateData { name: self.name, crate_num: self.crate_num, location: self.location, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), } } @@ -195,7 +176,7 @@ impl Lower for data::FunctionCallData { fn lower(self, tcx: TyCtxt) -> FunctionCallData { FunctionCallData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), ref_id: self.ref_id, } @@ -228,7 +209,7 @@ impl Lower for data::FunctionData { name: self.name, qualname: self.qualname, declaration: self.declaration, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), value: self.value, visibility: self.visibility, @@ -253,7 +234,7 @@ impl Lower for data::FunctionRefData { fn lower(self, tcx: TyCtxt) -> FunctionRefData { FunctionRefData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), ref_id: self.ref_id, } @@ -274,7 +255,7 @@ impl Lower for data::ImplData { fn lower(self, tcx: TyCtxt) -> ImplData { ImplData { id: make_def_id(self.id, &tcx.hir), - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), trait_ref: self.trait_ref, self_ref: self.self_ref, @@ -294,7 +275,7 @@ impl Lower for data::InheritanceData { fn lower(self, tcx: TyCtxt) -> InheritanceData { InheritanceData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), base_id: self.base_id, deriv_id: make_def_id(self.deriv_id, &tcx.hir) } @@ -315,7 +296,7 @@ impl Lower for data::MacroData { fn lower(self, tcx: TyCtxt) -> MacroData { MacroData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, qualname: self.qualname, docs: self.docs, @@ -340,10 +321,10 @@ impl Lower for data::MacroUseData { fn lower(self, tcx: TyCtxt) -> MacroUseData { MacroUseData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, qualname: self.qualname, - callee_span: SpanData::from_span(self.callee_span, tcx.sess.codemap()), + callee_span: span_from_span(self.callee_span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), } } @@ -363,7 +344,7 @@ impl Lower for data::MethodCallData { fn lower(self, tcx: TyCtxt) -> MethodCallData { MethodCallData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), ref_id: self.ref_id, decl_id: self.decl_id, @@ -393,7 +374,7 @@ impl Lower for data::MethodData { fn lower(self, tcx: TyCtxt) -> MethodData { MethodData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, scope: make_def_id(self.scope, &tcx.hir), id: make_def_id(self.id, &tcx.hir), @@ -433,7 +414,7 @@ impl Lower for data::ModData { id: make_def_id(self.id, &tcx.hir), name: self.name, qualname: self.qualname, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), filename: self.filename, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), @@ -459,7 +440,7 @@ impl Lower for data::ModRefData { fn lower(self, tcx: TyCtxt) -> ModRefData { ModRefData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), ref_id: self.ref_id, qualname: self.qualname, @@ -488,7 +469,7 @@ impl Lower for data::StructData { fn lower(self, tcx: TyCtxt) -> StructData { StructData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, id: make_def_id(self.id, &tcx.hir), ctor_id: make_def_id(self.ctor_id, &tcx.hir), @@ -524,7 +505,7 @@ impl Lower for data::StructVariantData { fn lower(self, tcx: TyCtxt) -> StructVariantData { StructVariantData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, id: make_def_id(self.id, &tcx.hir), qualname: self.qualname, @@ -559,7 +540,7 @@ impl Lower for data::TraitData { fn lower(self, tcx: TyCtxt) -> TraitData { TraitData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, id: make_def_id(self.id, &tcx.hir), qualname: self.qualname, @@ -594,7 +575,7 @@ impl Lower for data::TupleVariantData { fn lower(self, tcx: TyCtxt) -> TupleVariantData { TupleVariantData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), id: make_def_id(self.id, &tcx.hir), name: self.name, qualname: self.qualname, @@ -631,7 +612,7 @@ impl Lower for data::TypeDefData { TypeDefData { id: make_def_id(self.id, &tcx.hir), name: self.name, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), qualname: self.qualname, value: self.value, visibility: self.visibility, @@ -657,7 +638,7 @@ impl Lower for data::TypeRefData { fn lower(self, tcx: TyCtxt) -> TypeRefData { TypeRefData { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), ref_id: self.ref_id, qualname: self.qualname, @@ -681,7 +662,7 @@ impl Lower for data::UseData { fn lower(self, tcx: TyCtxt) -> UseData { UseData { id: make_def_id(self.id, &tcx.hir), - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), name: self.name, mod_id: self.mod_id, scope: make_def_id(self.scope, &tcx.hir), @@ -705,7 +686,7 @@ impl Lower for data::UseGlobData { fn lower(self, tcx: TyCtxt) -> UseGlobData { UseGlobData { id: make_def_id(self.id, &tcx.hir), - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), names: self.names, scope: make_def_id(self.scope, &tcx.hir), visibility: self.visibility, @@ -740,7 +721,7 @@ impl Lower for data::VariableData { kind: self.kind, name: self.name, qualname: self.qualname, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), value: self.value, type_value: self.type_value, @@ -769,7 +750,7 @@ impl Lower for data::VariableRefData { fn lower(self, tcx: TyCtxt) -> VariableRefData { VariableRefData { name: self.name, - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.hir), ref_id: self.ref_id, } @@ -793,7 +774,7 @@ impl Lower for data::Signature { fn lower(self, tcx: TyCtxt) -> Signature { Signature { - span: SpanData::from_span(self.span, tcx.sess.codemap()), + span: span_from_span(self.span, tcx.sess.codemap()), text: self.text, ident_start: self.ident_start, ident_end: self.ident_end, diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 277535f9e6513..b779e8245ed6a 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -18,6 +18,8 @@ use data::{VariableKind, Visibility, SigElement}; use dump::Dump; use super::Format; +use rls_data::{SpanData, CratePreludeData}; + // A dumper to dump a restricted set of JSON information, designed for use with // libraries distributed without their source. Clients are likely to use type diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 1b72489f83c67..8a4146ad10507 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -13,8 +13,12 @@ use std::io::Write; use rustc::hir::def_id::DefId; use rustc_serialize::json::as_json; +use rls_data::{self, Id, Analysis, Import, ImportKind, Def, DefKind, Ref, RefKind, MacroRef, + Relation, RelationKind, Signature, SigElement, CratePreludeData}; + +use external_data; use external_data::*; -use data::{VariableKind, SigElement}; +use data::{self, VariableKind}; use dump::Dump; use super::Format; @@ -40,7 +44,7 @@ impl<'b, W: Write> Drop for JsonDumper<'b, W> { macro_rules! impl_fn { ($fn_name: ident, $data_type: ident, $bucket: ident) => { fn $fn_name(&mut self, data: $data_type) { - self.result.$bucket.push(From::from(data)); + self.result.$bucket.push(data.into()); } } } @@ -75,21 +79,22 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { impl_fn!(macro_use, MacroUseData, macro_refs); fn mod_data(&mut self, data: ModData) { - let id: Id = From::from(data.id); + let id: Id = id_from_def_id(data.id); let mut def = Def { kind: DefKind::Mod, id: id, - span: data.span, + span: data.span.into(), name: data.name, qualname: data.qualname, value: data.filename, - children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + children: data.items.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + sig: Some(data.sig.into()), + attributes: data.attributes.into_iter().map(|a| a.into()).collect(), }; - if def.span.file_name != def.value { + if data.span.file_name.to_str().unwrap() != def.value { // If the module is an out-of-line defintion, then we'll make the // defintion the first character in the module's file and turn the // the declaration into a reference to it. @@ -99,8 +104,8 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { ref_id: id, }; self.result.refs.push(rf); - def.span = SpanData { - file_name: def.value.clone(), + def.span = rls_data::SpanData { + file_name: def.value.clone().into(), byte_start: 0, byte_end: 0, line_start: 1, @@ -115,11 +120,11 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { fn impl_data(&mut self, data: ImplData) { if data.self_ref.is_some() { - self.result.relations.push(From::from(data)); + self.result.relations.push(data.into()); } } fn inheritance(&mut self, data: InheritanceData) { - self.result.relations.push(From::from(data)); + self.result.relations.push(data.into()); } } @@ -129,476 +134,351 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { // method, but not the supplied method). In both cases, we are currently // ignoring it. -#[derive(Debug, RustcEncodable)] -struct Analysis { - kind: Format, - prelude: Option, - imports: Vec, - defs: Vec, - refs: Vec, - macro_refs: Vec, - relations: Vec, -} - -impl Analysis { - fn new() -> Analysis { - Analysis { - kind: Format::Json, - prelude: None, - imports: vec![], - defs: vec![], - refs: vec![], - macro_refs: vec![], - relations: vec![], - } - } -} - // DefId::index is a newtype and so the JSON serialisation is ugly. Therefore // we use our own Id which is the same, but without the newtype. -#[derive(Clone, Copy, Debug, RustcEncodable)] -struct Id { - krate: u32, - index: u32, +fn id_from_def_id(id: DefId) -> Id { + Id { + krate: id.krate.as_u32(), + index: id.index.as_u32(), + } } -impl From for Id { - fn from(id: DefId) -> Id { - Id { - krate: id.krate.as_u32(), - index: id.index.as_u32(), +impl Into for Attribute { + fn into(self) -> rls_data::Attribute { + rls_data::Attribute { + value: self.value, + span: self.span, } } } -#[derive(Debug, RustcEncodable)] -struct Import { - kind: ImportKind, - ref_id: Option, - span: SpanData, - name: String, - value: String, -} - -#[derive(Debug, RustcEncodable)] -enum ImportKind { - ExternCrate, - Use, - GlobUse, -} - -impl From for Import { - fn from(data: ExternCrateData) -> Import { +impl Into for ExternCrateData { + fn into(self) -> Import { Import { kind: ImportKind::ExternCrate, ref_id: None, - span: data.span, - name: data.name, + span: self.span, + name: self.name, value: String::new(), } } } -impl From for Import { - fn from(data: UseData) -> Import { +impl Into for UseData { + fn into(self) -> Import { Import { kind: ImportKind::Use, - ref_id: data.mod_id.map(|id| From::from(id)), - span: data.span, - name: data.name, + ref_id: self.mod_id.map(|id| id_from_def_id(id)), + span: self.span, + name: self.name, value: String::new(), } } } -impl From for Import { - fn from(data: UseGlobData) -> Import { +impl Into for UseGlobData { + fn into(self) -> Import { Import { kind: ImportKind::GlobUse, ref_id: None, - span: data.span, + span: self.span, name: "*".to_owned(), - value: data.names.join(", "), + value: self.names.join(", "), } } } -#[derive(Debug, RustcEncodable)] -struct Def { - kind: DefKind, - id: Id, - span: SpanData, - name: String, - qualname: String, - value: String, - children: Vec, - decl_id: Option, - docs: String, - sig: Option, - attributes: Vec, -} - -#[derive(Debug, RustcEncodable)] -enum DefKind { - // value = variant names - Enum, - // value = enum name + variant name + types - Tuple, - // value = [enum name +] name + fields - Struct, - // value = signature - Trait, - // value = type + generics - Function, - // value = type + generics - Method, - // No id, no value. - Macro, - // value = file_name - Mod, - // value = aliased type - Type, - // value = type and init expression (for all variable kinds). - Local, - Static, - Const, - Field, -} - -impl From for Def { - fn from(data: EnumData) -> Def { +impl Into for EnumData { + fn into(self) -> Def { Def { kind: DefKind::Enum, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: data.variants.into_iter().map(|id| From::from(id)).collect(), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, + children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: TupleVariantData) -> Def { +impl Into for TupleVariantData { + fn into(self) -> Def { Def { kind: DefKind::Tuple, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, children: vec![], decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: StructVariantData) -> Def { +impl Into for StructVariantData { + fn into(self) -> Def { Def { kind: DefKind::Struct, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, children: vec![], decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: StructData) -> Def { +impl Into for StructData { + fn into(self) -> Def { Def { kind: DefKind::Struct, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: data.fields.into_iter().map(|id| From::from(id)).collect(), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, + children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: TraitData) -> Def { +impl Into for TraitData { + fn into(self) -> Def { Def { kind: DefKind::Trait, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: data.items.into_iter().map(|id| From::from(id)).collect(), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, + children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: FunctionData) -> Def { +impl Into for FunctionData { + fn into(self) -> Def { Def { kind: DefKind::Function, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, children: vec![], decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: MethodData) -> Def { +impl Into for MethodData { + fn into(self) -> Def { Def { kind: DefKind::Method, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, children: vec![], - decl_id: data.decl_id.map(|id| From::from(id)), - docs: data.docs, - sig: Some(From::from(data.sig)), - attributes: data.attributes, + decl_id: self.decl_id.map(|id| id_from_def_id(id)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: MacroData) -> Def { +impl Into for MacroData { + fn into(self) -> Def { Def { kind: DefKind::Macro, - id: From::from(null_def_id()), - span: data.span, - name: data.name, - qualname: data.qualname, + id: id_from_def_id(null_def_id()), + span: self.span, + name: self.name, + qualname: self.qualname, value: String::new(), + parent: None, children: vec![], decl_id: None, - docs: data.docs, + docs: self.docs, sig: None, attributes: vec![], } } } -impl From for Def { - fn from(data: TypeDefData) -> Def { +impl Into for TypeDefData { + fn into(self) -> Def { Def { kind: DefKind::Type, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: None, children: vec![], decl_id: None, docs: String::new(), - sig: data.sig.map(|s| From::from(s)), - attributes: data.attributes, + sig: self.sig.map(|s| s.into()), + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -impl From for Def { - fn from(data: VariableData) -> Def { +impl Into for VariableData { + fn into(self) -> Def { Def { - kind: match data.kind { + kind: match self.kind { VariableKind::Static => DefKind::Static, VariableKind::Const => DefKind::Const, VariableKind::Local => DefKind::Local, VariableKind::Field => DefKind::Field, }, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.type_value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.type_value, + parent: None, children: vec![], decl_id: None, - docs: data.docs, + docs: self.docs, sig: None, - attributes: data.attributes, + attributes: self.attributes.into_iter().map(|a| a.into()).collect(), } } } -#[derive(Debug, RustcEncodable)] -enum RefKind { - Function, - Mod, - Type, - Variable, -} - -#[derive(Debug, RustcEncodable)] -struct Ref { - kind: RefKind, - span: SpanData, - ref_id: Id, -} - -impl From for Ref { - fn from(data: FunctionRefData) -> Ref { +impl Into for FunctionRefData { + fn into(self) -> Ref { Ref { kind: RefKind::Function, - span: data.span, - ref_id: From::from(data.ref_id), + span: self.span, + ref_id: id_from_def_id(self.ref_id), } } } -impl From for Ref { - fn from(data: FunctionCallData) -> Ref { +impl Into for FunctionCallData { + fn into(self) -> Ref { Ref { kind: RefKind::Function, - span: data.span, - ref_id: From::from(data.ref_id), + span: self.span, + ref_id: id_from_def_id(self.ref_id), } } } -impl From for Ref { - fn from(data: MethodCallData) -> Ref { +impl Into for MethodCallData { + fn into(self) -> Ref { Ref { kind: RefKind::Function, - span: data.span, - ref_id: From::from(data.ref_id.or(data.decl_id).unwrap_or(null_def_id())), + span: self.span, + ref_id: id_from_def_id(self.ref_id.or(self.decl_id).unwrap_or(null_def_id())), } } } -impl From for Ref { - fn from(data: ModRefData) -> Ref { +impl Into for ModRefData { + fn into(self) -> Ref { Ref { kind: RefKind::Mod, - span: data.span, - ref_id: From::from(data.ref_id.unwrap_or(null_def_id())), + span: self.span, + ref_id: id_from_def_id(self.ref_id.unwrap_or(null_def_id())), } } } -impl From for Ref { - fn from(data: TypeRefData) -> Ref { +impl Into for TypeRefData { + fn into(self) -> Ref { Ref { kind: RefKind::Type, - span: data.span, - ref_id: From::from(data.ref_id.unwrap_or(null_def_id())), + span: self.span, + ref_id: id_from_def_id(self.ref_id.unwrap_or(null_def_id())), } } } -impl From for Ref { - fn from(data: VariableRefData) -> Ref { +impl Into for VariableRefData { + fn into(self) -> Ref { Ref { kind: RefKind::Variable, - span: data.span, - ref_id: From::from(data.ref_id), + span: self.span, + ref_id: id_from_def_id(self.ref_id), } } } -#[derive(Debug, RustcEncodable)] -struct MacroRef { - span: SpanData, - qualname: String, - callee_span: SpanData, -} - -impl From for MacroRef { - fn from(data: MacroUseData) -> MacroRef { +impl Into for MacroUseData { + fn into(self) -> MacroRef { MacroRef { - span: data.span, - qualname: data.qualname, - callee_span: data.callee_span, + span: self.span, + qualname: self.qualname, + callee_span: self.callee_span.into(), } } } -#[derive(Debug, RustcEncodable)] -struct Relation { - span: SpanData, - kind: RelationKind, - from: Id, - to: Id, -} - -#[derive(Debug, RustcEncodable)] -enum RelationKind { - Impl, - SuperTrait, -} - -impl From for Relation { - fn from(data: ImplData) -> Relation { +impl Into for ImplData { + fn into(self) -> Relation { Relation { - span: data.span, + span: self.span, kind: RelationKind::Impl, - from: From::from(data.self_ref.unwrap_or(null_def_id())), - to: From::from(data.trait_ref.unwrap_or(null_def_id())), + from: id_from_def_id(self.self_ref.unwrap_or(null_def_id())), + to: id_from_def_id(self.trait_ref.unwrap_or(null_def_id())), } } } -impl From for Relation { - fn from(data: InheritanceData) -> Relation { +impl Into for InheritanceData { + fn into(self) -> Relation { Relation { - span: data.span, + span: self.span, kind: RelationKind::SuperTrait, - from: From::from(data.base_id), - to: From::from(data.deriv_id), + from: id_from_def_id(self.base_id), + to: id_from_def_id(self.deriv_id), } } } -#[derive(Debug, RustcEncodable)] -pub struct JsonSignature { - span: SpanData, - text: String, - ident_start: usize, - ident_end: usize, - defs: Vec, - refs: Vec, -} - -impl From for JsonSignature { - fn from(data: Signature) -> JsonSignature { - JsonSignature { - span: data.span, - text: data.text, - ident_start: data.ident_start, - ident_end: data.ident_end, - defs: data.defs.into_iter().map(|s| From::from(s)).collect(), - refs: data.refs.into_iter().map(|s| From::from(s)).collect(), +impl Into for external_data::Signature { + fn into(self) -> Signature { + Signature { + span: self.span, + text: self.text, + ident_start: self.ident_start, + ident_end: self.ident_end, + defs: self.defs.into_iter().map(|s| s.into()).collect(), + refs: self.refs.into_iter().map(|s| s.into()).collect(), } } } -#[derive(Debug, RustcEncodable)] -pub struct JsonSigElement { - id: Id, - start: usize, - end: usize, -} - -impl From for JsonSigElement { - fn from(data: SigElement) -> JsonSigElement { - JsonSigElement { - id: From::from(data.id), - start: data.start, - end: data.end, +impl Into for data::SigElement { + fn into(self) -> SigElement { + SigElement { + id: id_from_def_id(self.id), + start: self.start, + end: self.end, } } } From 83f84ff1bc002ef33c359626f6cafbd22c5d294d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Mar 2017 08:58:04 +1300 Subject: [PATCH 063/662] Use out-of-tree rustc serialize And remove a few data structures in favour of rls-data ones --- src/Cargo.lock | 24 ++++----- src/librustc_save_analysis/Cargo.toml | 3 +- src/librustc_save_analysis/data.rs | 60 ++++++++++----------- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/external_data.rs | 57 +++++++++----------- src/librustc_save_analysis/json_dumper.rs | 27 ++++------ src/librustc_save_analysis/lib.rs | 2 +- 7 files changed, 80 insertions(+), 95 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index f7fcedf26d5ef..818a6c2f7c5c9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -27,7 +27,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -75,7 +75,7 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -122,7 +122,7 @@ name = "cmake" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -140,7 +140,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -196,7 +196,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -205,7 +205,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -410,7 +410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-data" version = "0.1.0" -source = "git+https://github.com/nrc/rls-data#eb8de823771ef33edf78dc18fc0b279e6c4b6336" +source = "git+https://github.com/nrc/rls-data#aa5268cae09f4594303b0560c55627dfa8f75839" dependencies = [ "rls-span 0.1.0 (git+https://github.com/nrc/rls-span)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", @@ -604,7 +604,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -719,7 +719,7 @@ dependencies = [ "log 0.0.0", "rls-data 0.1.0 (git+https://github.com/nrc/rls-data)", "rustc 0.0.0", - "serialize 0.0.0", + "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -779,7 +779,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -827,7 +827,7 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", @@ -998,7 +998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d" +"checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 130e4fd6266fb..c4cbe426548a1 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["dylib"] log = { path = "../liblog" } rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } -serialize = { path = "../libserialize" } +# FIXME should move rustc serialize out of tree +rustc-serialize = "0.3" syntax_pos = { path = "../libsyntax_pos" } rls-data = { git = "https://github.com/nrc/rls-data" } diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 6a80b703d9da3..d4ded71a33390 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -28,7 +28,7 @@ pub struct CrateData { /// Data for any entity in the Rust language. The actual data contained varies /// with the kind of entity being queried. See the nested structs for details. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub enum Data { /// Data for Enums. EnumData(EnumData), @@ -79,7 +79,7 @@ pub enum Data { VariableRefData(VariableRefData), } -#[derive(Eq, PartialEq, Clone, Copy, Debug, RustcEncodable)] +#[derive(Eq, PartialEq, Clone, Copy, Debug)] pub enum Visibility { Public, Restricted, @@ -109,7 +109,7 @@ impl<'a> From<&'a hir::Visibility> for Visibility { } /// Data for the prelude of a crate. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct CratePreludeData { pub crate_name: String, pub crate_root: String, @@ -118,7 +118,7 @@ pub struct CratePreludeData { } /// Data for enum declarations. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct EnumData { pub id: NodeId, pub name: String, @@ -134,7 +134,7 @@ pub struct EnumData { } /// Data for extern crates. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ExternCrateData { pub id: NodeId, pub name: String, @@ -145,7 +145,7 @@ pub struct ExternCrateData { } /// Data about a function call. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct FunctionCallData { pub span: Span, pub scope: NodeId, @@ -153,7 +153,7 @@ pub struct FunctionCallData { } /// Data for all kinds of functions and methods. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct FunctionData { pub id: NodeId, pub name: String, @@ -170,14 +170,14 @@ pub struct FunctionData { } /// Data about a function call. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct FunctionRefData { pub span: Span, pub scope: NodeId, pub ref_id: DefId, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ImplData { pub id: NodeId, pub span: Span, @@ -186,7 +186,7 @@ pub struct ImplData { pub self_ref: Option, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] // FIXME: this struct should not exist. However, removing it requires heavy // refactoring of dump_visitor.rs. See PR 31838 for more info. pub struct ImplData2 { @@ -200,7 +200,7 @@ pub struct ImplData2 { pub self_ref: Option, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct InheritanceData { pub span: Span, pub base_id: DefId, @@ -208,7 +208,7 @@ pub struct InheritanceData { } /// Data about a macro declaration. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct MacroData { pub span: Span, pub name: String, @@ -217,7 +217,7 @@ pub struct MacroData { } /// Data about a macro use. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct MacroUseData { pub span: Span, pub name: String, @@ -230,7 +230,7 @@ pub struct MacroUseData { } /// Data about a method call. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct MethodCallData { pub span: Span, pub scope: NodeId, @@ -239,7 +239,7 @@ pub struct MethodCallData { } /// Data for method declarations (methods with a body are treated as functions). -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct MethodData { pub id: NodeId, pub name: String, @@ -256,7 +256,7 @@ pub struct MethodData { } /// Data for modules. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ModData { pub id: NodeId, pub name: String, @@ -272,7 +272,7 @@ pub struct ModData { } /// Data for a reference to a module. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ModRefData { pub span: Span, pub scope: NodeId, @@ -280,7 +280,7 @@ pub struct ModRefData { pub qualname: String } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct StructData { pub span: Span, pub name: String, @@ -296,7 +296,7 @@ pub struct StructData { pub attributes: Vec, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct StructVariantData { pub span: Span, pub name: String, @@ -311,7 +311,7 @@ pub struct StructVariantData { pub attributes: Vec, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct TraitData { pub span: Span, pub id: NodeId, @@ -326,7 +326,7 @@ pub struct TraitData { pub attributes: Vec, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct TupleVariantData { pub span: Span, pub id: NodeId, @@ -342,7 +342,7 @@ pub struct TupleVariantData { } /// Data for a typedef. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct TypeDefData { pub id: NodeId, pub name: String, @@ -357,7 +357,7 @@ pub struct TypeDefData { } /// Data for a reference to a type or trait. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct TypeRefData { pub span: Span, pub scope: NodeId, @@ -365,7 +365,7 @@ pub struct TypeRefData { pub qualname: String, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct UseData { pub id: NodeId, pub span: Span, @@ -375,7 +375,7 @@ pub struct UseData { pub visibility: Visibility, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct UseGlobData { pub id: NodeId, pub span: Span, @@ -385,7 +385,7 @@ pub struct UseGlobData { } /// Data for local and global variables (consts and statics). -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct VariableData { pub id: NodeId, pub kind: VariableKind, @@ -402,7 +402,7 @@ pub struct VariableData { pub attributes: Vec, } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub enum VariableKind { Static, Const, @@ -412,7 +412,7 @@ pub enum VariableKind { /// Data for the use of some item (e.g., the use of a local variable, which /// will refer to that variables declaration (by ref_id)). -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct VariableRefData { pub name: String, pub span: Span, @@ -424,7 +424,7 @@ pub struct VariableRefData { /// Encodes information about the signature of a definition. This should have /// enough information to create a nice display about a definition without /// access to the source code. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct Signature { pub span: Span, pub text: String, @@ -438,7 +438,7 @@ pub struct Signature { /// An element of a signature. `start` and `end` are byte offsets into the `text` /// of the parent `Signature`. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct SigElement { pub id: DefId, pub start: usize, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 85bef9f3170ac..4efc3d7baa649 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -139,7 +139,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo); ExternalCrateData { name: c.name, - num: CrateNum::from_u32(c.number), + num: c.number, file_name: SpanUtils::make_path_string(&lo_loc.file.name), } }).collect(); diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 3555887007499..bf296283da426 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; use data::{self, Visibility, SigElement}; -use rls_data::{SpanData, CratePreludeData}; +use rls_data::{SpanData, CratePreludeData, Attribute}; // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet pub trait Lower { @@ -55,13 +55,6 @@ pub fn span_from_span(span: Span, cm: &CodeMap) -> SpanData { } } -/// Represent an arbitrary attribute on a code element -#[derive(Clone, Debug, RustcEncodable)] -pub struct Attribute { - pub value: String, - pub span: SpanData, -} - impl Lower for Vec { type Target = Vec; @@ -102,7 +95,7 @@ impl Lower for data::CratePreludeData { } /// Data for enum declarations. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct EnumData { pub id: DefId, pub value: String, @@ -138,7 +131,7 @@ impl Lower for data::EnumData { } /// Data for extern crates. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ExternCrateData { pub id: DefId, pub name: String, @@ -164,7 +157,7 @@ impl Lower for data::ExternCrateData { } /// Data about a function call. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct FunctionCallData { pub span: SpanData, pub scope: DefId, @@ -184,7 +177,7 @@ impl Lower for data::FunctionCallData { } /// Data for all kinds of functions and methods. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct FunctionData { pub id: DefId, pub name: String, @@ -222,7 +215,7 @@ impl Lower for data::FunctionData { } /// Data about a function call. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct FunctionRefData { pub span: SpanData, pub scope: DefId, @@ -240,7 +233,7 @@ impl Lower for data::FunctionRefData { } } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ImplData { pub id: DefId, pub span: SpanData, @@ -263,7 +256,7 @@ impl Lower for data::ImplData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct InheritanceData { pub span: SpanData, pub base_id: DefId, @@ -283,7 +276,7 @@ impl Lower for data::InheritanceData { } /// Data about a macro declaration. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct MacroData { pub span: SpanData, pub name: String, @@ -305,7 +298,7 @@ impl Lower for data::MacroData { } /// Data about a macro use. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct MacroUseData { pub span: SpanData, pub name: String, @@ -331,7 +324,7 @@ impl Lower for data::MacroUseData { } /// Data about a method call. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct MethodCallData { pub span: SpanData, pub scope: DefId, @@ -353,7 +346,7 @@ impl Lower for data::MethodCallData { } /// Data for method declarations (methods with a body are treated as functions). -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct MethodData { pub id: DefId, pub name: String, @@ -391,7 +384,7 @@ impl Lower for data::MethodData { } /// Data for modules. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ModData { pub id: DefId, pub name: String, @@ -427,7 +420,7 @@ impl Lower for data::ModData { } /// Data for a reference to a module. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct ModRefData { pub span: SpanData, pub scope: DefId, @@ -448,7 +441,7 @@ impl Lower for data::ModRefData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct StructData { pub span: SpanData, pub name: String, @@ -485,7 +478,7 @@ impl Lower for data::StructData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct StructVariantData { pub span: SpanData, pub name: String, @@ -520,7 +513,7 @@ impl Lower for data::StructVariantData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct TraitData { pub span: SpanData, pub name: String, @@ -555,7 +548,7 @@ impl Lower for data::TraitData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct TupleVariantData { pub span: SpanData, pub id: DefId, @@ -591,7 +584,7 @@ impl Lower for data::TupleVariantData { } /// Data for a typedef. -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct TypeDefData { pub id: DefId, pub name: String, @@ -625,7 +618,7 @@ impl Lower for data::TypeDefData { } /// Data for a reference to a type or trait. -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct TypeRefData { pub span: SpanData, pub scope: DefId, @@ -646,7 +639,7 @@ impl Lower for data::TypeRefData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct UseData { pub id: DefId, pub span: SpanData, @@ -671,7 +664,7 @@ impl Lower for data::UseData { } } -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct UseGlobData { pub id: DefId, pub span: SpanData, @@ -695,7 +688,7 @@ impl Lower for data::UseGlobData { } /// Data for local and global variables (consts and statics). -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct VariableData { pub id: DefId, pub name: String, @@ -736,7 +729,7 @@ impl Lower for data::VariableData { /// Data for the use of some item (e.g., the use of a local variable, which /// will refer to that variables declaration (by ref_id)). -#[derive(Debug, RustcEncodable)] +#[derive(Debug)] pub struct VariableRefData { pub name: String, pub span: SpanData, @@ -757,7 +750,7 @@ impl Lower for data::VariableRefData { } } -#[derive(Clone, Debug, RustcEncodable)] +#[derive(Clone, Debug)] pub struct Signature { pub span: SpanData, pub text: String, diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 8a4146ad10507..3b7625bdcc1be 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -143,15 +143,6 @@ fn id_from_def_id(id: DefId) -> Id { } } -impl Into for Attribute { - fn into(self) -> rls_data::Attribute { - rls_data::Attribute { - value: self.value, - span: self.span, - } - } -} - impl Into for ExternCrateData { fn into(self) -> Import { Import { @@ -200,7 +191,7 @@ impl Into for EnumData { decl_id: None, docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -219,7 +210,7 @@ impl Into for TupleVariantData { decl_id: None, docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -237,7 +228,7 @@ impl Into for StructVariantData { decl_id: None, docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -255,7 +246,7 @@ impl Into for StructData { decl_id: None, docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -273,7 +264,7 @@ impl Into for TraitData { decl_id: None, docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -291,7 +282,7 @@ impl Into for FunctionData { decl_id: None, docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -309,7 +300,7 @@ impl Into for MethodData { decl_id: self.decl_id.map(|id| id_from_def_id(id)), docs: self.docs, sig: Some(self.sig.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -345,7 +336,7 @@ impl Into for TypeDefData { decl_id: None, docs: String::new(), sig: self.sig.map(|s| s.into()), - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } @@ -368,7 +359,7 @@ impl Into for VariableData { decl_id: None, docs: self.docs, sig: None, - attributes: self.attributes.into_iter().map(|a| a.into()).collect(), + attributes: self.attributes, } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 39b47b1645a70..ec637268d91a4 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -26,7 +26,7 @@ #[macro_use] extern crate log; #[macro_use] extern crate syntax; -extern crate serialize as rustc_serialize; +extern crate rustc_serialize; extern crate syntax_pos; extern crate rls_data; From bf07f1c6bb2a93eb02325a76ad855449b8f0ea5b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Mar 2017 09:14:15 +1300 Subject: [PATCH 064/662] Add rls-span to do some conversions into rls-data. And fix some warnings and borrow errors --- src/Cargo.lock | 1 + src/librustc_save_analysis/Cargo.toml | 1 + src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/external_data.rs | 11 +++++------ src/librustc_save_analysis/json_dumper.rs | 12 ++++++------ src/librustc_save_analysis/lib.rs | 1 + 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 818a6c2f7c5c9..7e61014b17812 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -718,6 +718,7 @@ version = "0.0.0" dependencies = [ "log 0.0.0", "rls-data 0.1.0 (git+https://github.com/nrc/rls-data)", + "rls-span 0.1.0 (git+https://github.com/nrc/rls-span)", "rustc 0.0.0", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index c4cbe426548a1..3e6f85a7bb982 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -16,3 +16,4 @@ syntax = { path = "../libsyntax" } rustc-serialize = "0.3" syntax_pos = { path = "../libsyntax_pos" } rls-data = { git = "https://github.com/nrc/rls-data" } +rls-span = { git = "https://github.com/nrc/rls-span" } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 4efc3d7baa649..f2aa89ba4b66e 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -29,7 +29,7 @@ use rustc::hir; use rustc::hir::def::Def; -use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; use rustc::ty::{self, TyCtxt, AssociatedItemContainer}; diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index bf296283da426..6ea8e90fec571 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -17,11 +17,10 @@ use syntax::print::pprust; use syntax::symbol::Symbol; use syntax_pos::Span; -use std::path::PathBuf; - use data::{self, Visibility, SigElement}; use rls_data::{SpanData, CratePreludeData, Attribute}; +use rls_span::{Column, Row}; // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet pub trait Lower { @@ -48,10 +47,10 @@ pub fn span_from_span(span: Span, cm: &CodeMap) -> SpanData { file_name: start.file.name.clone().into(), byte_start: span.lo.0, byte_end: span.hi.0, - line_start: start.line, - line_end: end.line, - column_start: start.col.0 + 1, - column_end: end.col.0 + 1, + line_start: Row::new_one_indexed(start.line as u32), + line_end: Row::new_one_indexed(end.line as u32), + column_start: Column::new_one_indexed(start.col.0 as u32 + 1), + column_end: Column::new_one_indexed(end.col.0 as u32 + 1), } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 3b7625bdcc1be..dbc0909b7e05f 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -15,12 +15,12 @@ use rustc_serialize::json::as_json; use rls_data::{self, Id, Analysis, Import, ImportKind, Def, DefKind, Ref, RefKind, MacroRef, Relation, RelationKind, Signature, SigElement, CratePreludeData}; +use rls_span::{Column, Row}; use external_data; use external_data::*; use data::{self, VariableKind}; use dump::Dump; -use super::Format; pub struct JsonDumper<'b, W: Write + 'b> { output: &'b mut W, @@ -94,7 +94,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { sig: Some(data.sig.into()), attributes: data.attributes.into_iter().map(|a| a.into()).collect(), }; - if data.span.file_name.to_str().unwrap() != def.value { + if def.span.file_name.to_str().unwrap() != def.value { // If the module is an out-of-line defintion, then we'll make the // defintion the first character in the module's file and turn the // the declaration into a reference to it. @@ -108,10 +108,10 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { file_name: def.value.clone().into(), byte_start: 0, byte_end: 0, - line_start: 1, - line_end: 1, - column_start: 1, - column_end: 1, + line_start: Row::new_one_indexed(1), + line_end: Row::new_one_indexed(1), + column_start: Column::new_one_indexed(1), + column_end: Column::new_one_indexed(1), } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ec637268d91a4..eb7511f9e1608 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -30,6 +30,7 @@ extern crate rustc_serialize; extern crate syntax_pos; extern crate rls_data; +extern crate rls_span; mod csv_dumper; From 979a9881ea1f113f8a384977eb1df5b01f3794b2 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Mar 2017 09:48:36 +1300 Subject: [PATCH 065/662] Move the API json dumper to use rls-data too --- src/librustc_save_analysis/json_api_dumper.rs | 459 ++++++------------ src/librustc_save_analysis/json_dumper.rs | 2 +- 2 files changed, 147 insertions(+), 314 deletions(-) diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index b779e8245ed6a..41221ad986379 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -10,15 +10,14 @@ use std::io::Write; -use rustc::hir::def_id::DefId; use rustc_serialize::json::as_json; use external_data::*; -use data::{VariableKind, Visibility, SigElement}; +use data::{VariableKind, Visibility}; use dump::Dump; -use super::Format; +use json_dumper::id_from_def_id; -use rls_data::{SpanData, CratePreludeData}; +use rls_data::{Analysis, Import, ImportKind, Def, DefKind, CratePreludeData}; // A dumper to dump a restricted set of JSON information, designed for use with @@ -26,8 +25,7 @@ use rls_data::{SpanData, CratePreludeData}; // information here, and (for example) generate Rustdoc URLs, but don't need // information for navigating the source of the crate. // Relative to the regular JSON save-analysis info, this form is filtered to -// remove non-visible items, but includes some extra info for items (e.g., the -// parent field for finding the struct to which a field belongs). +// remove non-visible items. pub struct JsonApiDumper<'b, W: Write + 'b> { output: &'b mut W, result: Analysis, @@ -50,7 +48,7 @@ impl<'b, W: Write> Drop for JsonApiDumper<'b, W> { macro_rules! impl_fn { ($fn_name: ident, $data_type: ident, $bucket: ident) => { fn $fn_name(&mut self, data: $data_type) { - if let Some(datum) = From::from(data) { + if let Some(datum) = data.into() { self.result.$bucket.push(datum); } } @@ -79,11 +77,11 @@ impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { fn impl_data(&mut self, data: ImplData) { if data.self_ref.is_some() { - self.result.relations.push(From::from(data)); + self.result.relations.push(data.into()); } } fn inheritance(&mut self, data: InheritanceData) { - self.result.relations.push(From::from(data)); + self.result.relations.push(data.into()); } } @@ -92,426 +90,261 @@ impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { // method, but not the supplied method). In both cases, we are currently // ignoring it. -#[derive(Debug, RustcEncodable)] -struct Analysis { - kind: Format, - prelude: Option, - imports: Vec, - defs: Vec, - relations: Vec, - // These two fields are dummies so that clients can parse the two kinds of - // JSON data in the same way. - refs: Vec<()>, - macro_refs: Vec<()>, -} - -impl Analysis { - fn new() -> Analysis { - Analysis { - kind: Format::JsonApi, - prelude: None, - imports: vec![], - defs: vec![], - relations: vec![], - refs: vec![], - macro_refs: vec![], - } - } -} - -// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore -// we use our own Id which is the same, but without the newtype. -#[derive(Debug, RustcEncodable)] -struct Id { - krate: u32, - index: u32, -} - -impl From for Id { - fn from(id: DefId) -> Id { - Id { - krate: id.krate.as_u32(), - index: id.index.as_u32(), - } - } -} - -#[derive(Debug, RustcEncodable)] -struct Import { - kind: ImportKind, - id: Id, - span: SpanData, - name: String, - value: String, -} - -#[derive(Debug, RustcEncodable)] -enum ImportKind { - Use, - GlobUse, -} - -impl From for Option { - fn from(data: UseData) -> Option { - match data.visibility { +impl Into> for UseData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Import { kind: ImportKind::Use, - id: From::from(data.id), - span: data.span, - name: data.name, + ref_id: self.mod_id.map(|id| id_from_def_id(id)), + span: self.span, + name: self.name, value: String::new(), }), _ => None, } } } -impl From for Option { - fn from(data: UseGlobData) -> Option { - match data.visibility { +impl Into> for UseGlobData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Import { kind: ImportKind::GlobUse, - id: From::from(data.id), - span: data.span, + ref_id: None, + span: self.span, name: "*".to_owned(), - value: data.names.join(", "), + value: self.names.join(", "), }), _ => None, } } } -#[derive(Debug, RustcEncodable)] -struct Def { - kind: DefKind, - id: Id, - span: SpanData, - name: String, - qualname: String, - value: String, - parent: Option, - children: Vec, - decl_id: Option, - docs: String, - sig: Option, -} - -#[derive(Debug, RustcEncodable)] -enum DefKind { - // value = variant names - Enum, - // value = enum name + variant name + types - Tuple, - // value = [enum name +] name + fields - Struct, - // value = signature - Trait, - // value = type + generics - Function, - // value = type + generics - Method, - // No id, no value. - Macro, - // value = file_name - Mod, - // value = aliased type - Type, - // value = type and init expression (for all variable kinds). - Static, - Const, - Field, -} - -impl From for Option { - fn from(data: EnumData) -> Option { - match data.visibility { +impl Into> for EnumData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Enum, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, parent: None, - children: data.variants.into_iter().map(|id| From::from(id)).collect(), + children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: TupleVariantData) -> Option { +impl Into> for TupleVariantData { + fn into(self) -> Option { Some(Def { kind: DefKind::Tuple, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - parent: data.parent.map(|id| From::from(id)), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: self.parent.map(|id| id_from_def_id(id)), children: vec![], decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }) } } -impl From for Option { - fn from(data: StructVariantData) -> Option { +impl Into> for StructVariantData { + fn into(self) -> Option { Some(Def { kind: DefKind::Struct, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - parent: data.parent.map(|id| From::from(id)), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + parent: self.parent.map(|id| id_from_def_id(id)), children: vec![], decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }) } } -impl From for Option { - fn from(data: StructData) -> Option { - match data.visibility { +impl Into> for StructData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Struct, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, parent: None, - children: data.fields.into_iter().map(|id| From::from(id)).collect(), + children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: TraitData) -> Option { - match data.visibility { +impl Into> for TraitData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Trait, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: data.items.into_iter().map(|id| From::from(id)).collect(), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, + children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), parent: None, decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: FunctionData) -> Option { - match data.visibility { +impl Into> for FunctionData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Function, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, children: vec![], - parent: data.parent.map(|id| From::from(id)), + parent: self.parent.map(|id| id_from_def_id(id)), decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: MethodData) -> Option { - match data.visibility { +impl Into> for MethodData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Method, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, children: vec![], - parent: data.parent.map(|id| From::from(id)), - decl_id: data.decl_id.map(|id| From::from(id)), - docs: data.docs, - sig: Some(From::from(data.sig)), + parent: self.parent.map(|id| id_from_def_id(id)), + decl_id: self.decl_id.map(|id| id_from_def_id(id)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: MacroData) -> Option { +impl Into> for MacroData { + fn into(self) -> Option { Some(Def { kind: DefKind::Macro, - id: From::from(null_def_id()), - span: data.span, - name: data.name, - qualname: data.qualname, + id: id_from_def_id(null_def_id()), + span: self.span, + name: self.name, + qualname: self.qualname, value: String::new(), children: vec![], parent: None, decl_id: None, - docs: data.docs, + docs: self.docs, sig: None, + attributes: vec![], }) } } -impl From for Option { - fn from(data:ModData) -> Option { - match data.visibility { +impl Into> for ModData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Mod, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.filename, - children: data.items.into_iter().map(|id| From::from(id)).collect(), + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.filename, + children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), parent: None, decl_id: None, - docs: data.docs, - sig: Some(From::from(data.sig)), + docs: self.docs, + sig: Some(self.sig.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: TypeDefData) -> Option { - match data.visibility { +impl Into> for TypeDefData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { kind: DefKind::Type, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, children: vec![], - parent: data.parent.map(|id| From::from(id)), + parent: self.parent.map(|id| id_from_def_id(id)), decl_id: None, docs: String::new(), - sig: data.sig.map(|s| From::from(s)), + sig: self.sig.map(|s| s.into()), + attributes: vec![], }), _ => None, } } } -impl From for Option { - fn from(data: VariableData) -> Option { - match data.visibility { +impl Into> for VariableData { + fn into(self) -> Option { + match self.visibility { Visibility::Public => Some(Def { - kind: match data.kind { + kind: match self.kind { VariableKind::Static => DefKind::Static, VariableKind::Const => DefKind::Const, VariableKind::Local => { return None } VariableKind::Field => DefKind::Field, }, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, + id: id_from_def_id(self.id), + span: self.span, + name: self.name, + qualname: self.qualname, + value: self.value, children: vec![], - parent: data.parent.map(|id| From::from(id)), + parent: self.parent.map(|id| id_from_def_id(id)), decl_id: None, - docs: data.docs, - sig: data.sig.map(|s| From::from(s)), + docs: self.docs, + sig: self.sig.map(|s| s.into()), + attributes: vec![], }), _ => None, } } } - -#[derive(Debug, RustcEncodable)] -struct Relation { - span: SpanData, - kind: RelationKind, - from: Id, - to: Id, -} - -#[derive(Debug, RustcEncodable)] -enum RelationKind { - Impl, - SuperTrait, -} - -impl From for Relation { - fn from(data: ImplData) -> Relation { - Relation { - span: data.span, - kind: RelationKind::Impl, - from: From::from(data.self_ref.unwrap_or(null_def_id())), - to: From::from(data.trait_ref.unwrap_or(null_def_id())), - } - } -} - -impl From for Relation { - fn from(data: InheritanceData) -> Relation { - Relation { - span: data.span, - kind: RelationKind::SuperTrait, - from: From::from(data.base_id), - to: From::from(data.deriv_id), - } - } -} - -#[derive(Debug, RustcEncodable)] -pub struct JsonSignature { - span: SpanData, - text: String, - ident_start: usize, - ident_end: usize, - defs: Vec, - refs: Vec, -} - -impl From for JsonSignature { - fn from(data: Signature) -> JsonSignature { - JsonSignature { - span: data.span, - text: data.text, - ident_start: data.ident_start, - ident_end: data.ident_end, - defs: data.defs.into_iter().map(|s| From::from(s)).collect(), - refs: data.refs.into_iter().map(|s| From::from(s)).collect(), - } - } -} - -#[derive(Debug, RustcEncodable)] -pub struct JsonSigElement { - id: Id, - start: usize, - end: usize, -} - -impl From for JsonSigElement { - fn from(data: SigElement) -> JsonSigElement { - JsonSigElement { - id: From::from(data.id), - start: data.start, - end: data.end, - } - } -} diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index dbc0909b7e05f..acc877d394775 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -136,7 +136,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { // DefId::index is a newtype and so the JSON serialisation is ugly. Therefore // we use our own Id which is the same, but without the newtype. -fn id_from_def_id(id: DefId) -> Id { +pub fn id_from_def_id(id: DefId) -> Id { Id { krate: id.krate.as_u32(), index: id.index.as_u32(), From 2a3663f60688e8978fe5bc8b0398489ab9cd754f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Mar 2017 13:02:18 +1300 Subject: [PATCH 066/662] Handle feature=rustbuild Taken from https://github.com/rust-lang/rust/pull/40347/files And update rls-span to a version with the rustbuild boilerplate --- src/Cargo.lock | 2 +- src/bootstrap/bin/rustc.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 7e61014b17812..0670b1ce757e5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -419,7 +419,7 @@ dependencies = [ [[package]] name = "rls-span" version = "0.1.0" -source = "git+https://github.com/nrc/rls-span#e9224b1c52d1d43f9f7b3bb065653c9e18bb532d" +source = "git+https://github.com/nrc/rls-span#79375240da727c583ce656a6beb034c163313399" dependencies = [ "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61650..5e6f3e9e6cc0f 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -79,6 +79,7 @@ fn main() { cmd.args(&args) .arg("--cfg") .arg(format!("stage{}", stage)) + .arg("--cfg").arg("rustbuild") .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); From dc63eff86c7ab75848c7cd6a5114111eb11683f9 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Mar 2017 21:20:23 +1300 Subject: [PATCH 067/662] Move to using 0.1 versions of crates, rather than GH links Also adds a fixme and does cargo update --- src/Cargo.lock | 34 +++++++++++++-------------- src/librustc_save_analysis/Cargo.toml | 8 +++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 0670b1ce757e5..a9a6fabb5b23c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -79,7 +79,7 @@ dependencies = [ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -87,7 +87,7 @@ dependencies = [ name = "build-manifest" version = "0.1.0" dependencies = [ - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -150,7 +150,7 @@ dependencies = [ "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -231,7 +231,7 @@ dependencies = [ "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -410,18 +410,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-data" version = "0.1.0" -source = "git+https://github.com/nrc/rls-data#aa5268cae09f4594303b0560c55627dfa8f75839" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rls-span 0.1.0 (git+https://github.com/nrc/rls-span)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-span" version = "0.1.0" -source = "git+https://github.com/nrc/rls-span#79375240da727c583ce656a6beb034c163313399" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -462,7 +462,7 @@ dependencies = [ [[package]] name = "rustc-serialize" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -717,10 +717,10 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.0.0", - "rls-data 0.1.0 (git+https://github.com/nrc/rls-data)", - "rls-span 0.1.0 (git+https://github.com/nrc/rls-span)", + "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -933,7 +933,7 @@ name = "toml" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1017,9 +1017,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" -"checksum rls-data 0.1.0 (git+https://github.com/nrc/rls-data)" = "" -"checksum rls-span 0.1.0 (git+https://github.com/nrc/rls-span)" = "" -"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" +"checksum rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af1dfff00189fd7b78edb9af131b0de703676c04fa8126aed77fd2c586775a4d" +"checksum rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8656f7b850ac85fb204ef94318c641bbb15a32766e12f9a589a23e4c0fbc38db" +"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" "checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f" "checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 3e6f85a7bb982..06c5150fd13ad 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -12,8 +12,8 @@ crate-type = ["dylib"] log = { path = "../liblog" } rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } -# FIXME should move rustc serialize out of tree -rustc-serialize = "0.3" syntax_pos = { path = "../libsyntax_pos" } -rls-data = { git = "https://github.com/nrc/rls-data" } -rls-span = { git = "https://github.com/nrc/rls-span" } +rls-data = "0.1" +rls-span = "0.1" +# FIXME(#40527) should move rustc serialize out of tree +rustc-serialize = "0.3" From 5de04060ba0b402fde8e35ba826c3dd3691c2d8f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Mar 2017 07:13:59 -0700 Subject: [PATCH 068/662] rustbuild: Retry downloads of OpenSSL source We need this to compile Cargo and we download it at build time, but as like all other network requests it has a chance of failing. This commit moves the source of the tarball to a mirror (S3 seems semi-more-reliable most of the time) and also wraps the download in a retry loop. cc #40474 --- src/bootstrap/native.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 6cc1ca8d02ed0..dea1a607255a8 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -222,9 +222,24 @@ pub fn openssl(build: &Build, target: &str) { let tarball = out.join(&name); if !tarball.exists() { let tmp = tarball.with_extension("tmp"); - build.run(Command::new("curl") - .arg("-o").arg(&tmp) - .arg(format!("https://www.openssl.org/source/{}", name))); + // originally from https://www.openssl.org/source/... + let url = format!("https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/{}", + name); + let mut ok = false; + for _ in 0..3 { + let status = Command::new("curl") + .arg("-o").arg(&tmp) + .arg(&url) + .status() + .expect("failed to spawn curl"); + if status.success() { + ok = true; + break + } + } + if !ok { + panic!("failed to download openssl source") + } let mut shasum = if target.contains("apple") { let mut cmd = Command::new("shasum"); cmd.arg("-a").arg("256"); From ff63866edb511a73eed657a8a4f5c81f1ee5a9bb Mon Sep 17 00:00:00 2001 From: Piotr Jawniak Date: Fri, 3 Mar 2017 15:42:30 +0100 Subject: [PATCH 069/662] Change how the `0` flag works in format! Now it always implies right-alignment, so that padding zeroes are placed after the sign (if any) and before the digits. In other words, it always takes precedence over explicitly specified `[[fill]align]`. This also affects the '#' flag: zeroes are placed after the prefix (0b, 0o, 0x) and before the digits. :05 :<05 :>05 :^05 before |-0001| |-1000| |-0001| |-0100| after |-0001| |-0001| |-0001| |-0001| :#05x :<#05x :>#05x :^#05x before |0x001| |0x100| |000x1| |0x010| after |0x001| |0x001| |0x001| |0x001| Fixes #39997 [breaking-change] --- src/libcollections/fmt.rs | 4 ++++ src/libcore/fmt/mod.rs | 1 + src/test/run-pass/ifmt.rs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index dfd292176d2f9..2735293528e3f 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -366,6 +366,10 @@ //! like `{:08}` would yield `00000001` for the integer `1`, while the //! same format would yield `-0000001` for the integer `-1`. Notice that //! the negative version has one fewer zero than the positive version. +//! Note that padding zeroes are always placed after the sign (if any) +//! and before the digits. When used together with the `#` flag, a similar +//! rule applies: padding zeroes are inserted after the prefix but before +//! the digits. //! //! ## Width //! diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1657342ff6ac6..fd77201317f63 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1045,6 +1045,7 @@ impl<'a> Formatter<'a> { // is zero Some(min) if self.sign_aware_zero_pad() => { self.fill = '0'; + self.align = rt::v1::Alignment::Right; write_prefix(self)?; self.with_padding(min - width, rt::v1::Alignment::Right, |f| { f.buf.write_str(buf) diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 2a7a593d26800..dcd3920ffd9ad 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -160,6 +160,22 @@ pub fn main() { t!(format!("{:?}", -0.0), "-0"); t!(format!("{:?}", 0.0), "0"); + // sign aware zero padding + t!(format!("{:<3}", 1), "1 "); + t!(format!("{:>3}", 1), " 1"); + t!(format!("{:^3}", 1), " 1 "); + t!(format!("{:03}", 1), "001"); + t!(format!("{:<03}", 1), "001"); + t!(format!("{:>03}", 1), "001"); + t!(format!("{:^03}", 1), "001"); + t!(format!("{:+03}", 1), "+01"); + t!(format!("{:<+03}", 1), "+01"); + t!(format!("{:>+03}", 1), "+01"); + t!(format!("{:^+03}", 1), "+01"); + t!(format!("{:#05x}", 1), "0x001"); + t!(format!("{:<#05x}", 1), "0x001"); + t!(format!("{:>#05x}", 1), "0x001"); + t!(format!("{:^#05x}", 1), "0x001"); // Ergonomic format_args! t!(format!("{0:x} {0:X}", 15), "f F"); From 80654862831e27f249f05bcb50552510f1b5f643 Mon Sep 17 00:00:00 2001 From: Piotr Jawniak Date: Sat, 4 Mar 2017 21:29:17 +0100 Subject: [PATCH 070/662] Change how the 0 flag works in format! for floats Now it always implies right-alignment, so that padding zeroes are placed after the sign (if any) and before the digits. In other words, it always takes precedence over explicitly specified `[[fill]align]`. :06 :<06 :>06 :^06 before |-001.2| |-1.200| |-001.2| |-01.20| after |-001.2| |-001.2| |-001.2| |-001.2| --- src/libcore/fmt/mod.rs | 5 ++++- src/test/run-pass/ifmt.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index fd77201317f63..0bfab92fa5d51 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1154,8 +1154,9 @@ impl<'a> Formatter<'a> { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. let mut formatted = formatted.clone(); - let mut align = self.align; let old_fill = self.fill; + let old_align = self.align; + let mut align = old_align; if self.sign_aware_zero_pad() { // a sign always goes first let sign = unsafe { str::from_utf8_unchecked(formatted.sign) }; @@ -1166,6 +1167,7 @@ impl<'a> Formatter<'a> { width = if width < sign.len() { 0 } else { width - sign.len() }; align = rt::v1::Alignment::Right; self.fill = '0'; + self.align = rt::v1::Alignment::Right; } // remaining parts go through the ordinary padding process. @@ -1178,6 +1180,7 @@ impl<'a> Formatter<'a> { }) }; self.fill = old_fill; + self.align = old_align; ret } else { // this is the common case and we take a shortcut diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index dcd3920ffd9ad..cef2f879f9cd7 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -176,6 +176,18 @@ pub fn main() { t!(format!("{:<#05x}", 1), "0x001"); t!(format!("{:>#05x}", 1), "0x001"); t!(format!("{:^#05x}", 1), "0x001"); + t!(format!("{:05}", 1.2), "001.2"); + t!(format!("{:<05}", 1.2), "001.2"); + t!(format!("{:>05}", 1.2), "001.2"); + t!(format!("{:^05}", 1.2), "001.2"); + t!(format!("{:05}", -1.2), "-01.2"); + t!(format!("{:<05}", -1.2), "-01.2"); + t!(format!("{:>05}", -1.2), "-01.2"); + t!(format!("{:^05}", -1.2), "-01.2"); + t!(format!("{:+05}", 1.2), "+01.2"); + t!(format!("{:<+05}", 1.2), "+01.2"); + t!(format!("{:>+05}", 1.2), "+01.2"); + t!(format!("{:^+05}", 1.2), "+01.2"); // Ergonomic format_args! t!(format!("{0:x} {0:X}", 15), "f F"); From 2561dcddf9e61f5c52a65f1a42641e01bfabe3e2 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 5 Mar 2017 13:00:32 -0800 Subject: [PATCH 071/662] Rename TryFrom's associated type and implement str::parse using TryFrom. Per discussion on the tracking issue, naming `TryFrom`'s associated type `Error` is generally more consistent with similar traits in the Rust ecosystem, and what people seem to assume it should be called. It also helps disambiguate from `Result::Err`, the most common "Err". See https://github.com/rust-lang/rust/issues/33417#issuecomment-269108968. TryFrom<&str> and FromStr are equivalent, so have the latter provide the former to ensure that. Using TryFrom in the implementation of `str::parse` means types that implement either trait can use it. When we're ready to stabilize `TryFrom`, we should update `FromStr` to suggest implementing `TryFrom<&str>` instead for new code. See https://github.com/rust-lang/rust/issues/33417#issuecomment-277175994 and https://github.com/rust-lang/rust/issues/33417#issuecomment-277253827. Refs #33417. --- src/libcore/char.rs | 4 ++-- src/libcore/convert.rs | 24 ++++++++++++++++++------ src/libcore/num/mod.rs | 6 +++--- src/libcore/str/mod.rs | 7 +++++-- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 78764091cf032..a582180838f40 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -209,10 +209,10 @@ impl From for char { #[unstable(feature = "try_from", issue = "33417")] impl TryFrom for char { - type Err = CharTryFromError; + type Error = CharTryFromError; #[inline] - fn try_from(i: u32) -> Result { + fn try_from(i: u32) -> Result { if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { Err(CharTryFromError(())) } else { diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 4e170794c1d6e..a9ac9a7f77184 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -48,6 +48,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +use str::FromStr; + /// A cheap, reference-to-reference conversion. /// /// `AsRef` is very similar to, but different than, [`Borrow`]. See @@ -212,20 +214,20 @@ pub trait From: Sized { #[unstable(feature = "try_from", issue = "33417")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. - type Err; + type Error; /// Performs the conversion. - fn try_into(self) -> Result; + fn try_into(self) -> Result; } /// Attempt to construct `Self` via a conversion. #[unstable(feature = "try_from", issue = "33417")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. - type Err; + type Error; /// Performs the conversion. - fn try_from(value: T) -> Result; + fn try_from(value: T) -> Result; } //////////////////////////////////////////////////////////////////////////////// @@ -290,9 +292,9 @@ impl From for T { // TryFrom implies TryInto #[unstable(feature = "try_from", issue = "33417")] impl TryInto for T where U: TryFrom { - type Err = U::Err; + type Error = U::Error; - fn try_into(self) -> Result { + fn try_into(self) -> Result { U::try_from(self) } } @@ -322,3 +324,13 @@ impl AsRef for str { self } } + +// FromStr implies TryFrom<&str> +#[unstable(feature = "try_from", issue = "33417")] +impl<'a, T> TryFrom<&'a str> for T where T: FromStr { + type Error = ::Err; + + fn try_from(s: &'a str) -> Result { + FromStr::from_str(s) + } +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97ea6bb347b54..8edf690e7b521 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2591,7 +2591,7 @@ macro_rules! same_sign_try_from_int_impl { ($storage:ty, $target:ty, $($source:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { - type Err = TryFromIntError; + type Error = TryFromIntError; fn try_from(u: $source) -> Result<$target, TryFromIntError> { let min = <$target as FromStrRadixHelper>::min_value() as $storage; @@ -2623,7 +2623,7 @@ macro_rules! cross_sign_from_int_impl { ($unsigned:ty, $($signed:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$unsigned> for $signed { - type Err = TryFromIntError; + type Error = TryFromIntError; fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> { let max = <$signed as FromStrRadixHelper>::max_value() as u128; @@ -2637,7 +2637,7 @@ macro_rules! cross_sign_from_int_impl { #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$signed> for $unsigned { - type Err = TryFromIntError; + type Error = TryFromIntError; fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> { let max = <$unsigned as FromStrRadixHelper>::max_value() as u128; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 52e3301631052..9d48a8787079e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -18,6 +18,7 @@ use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char; +use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; use mem; @@ -1746,7 +1747,7 @@ pub trait StrExt { #[stable(feature = "core", since = "1.6.0")] fn is_empty(&self) -> bool; #[stable(feature = "core", since = "1.6.0")] - fn parse(&self) -> Result; + fn parse<'a, T: TryFrom<&'a str>>(&'a self) -> Result; } // truncate `&str` to length at most equal to `max` @@ -2045,7 +2046,9 @@ impl StrExt for str { fn is_empty(&self) -> bool { self.len() == 0 } #[inline] - fn parse(&self) -> Result { FromStr::from_str(self) } + fn parse<'a, T>(&'a self) -> Result where T: TryFrom<&'a str> { + T::try_from(self) + } } #[stable(feature = "rust1", since = "1.0.0")] From e66b3a20c88569d7fcf295523fcc2446ca90457b Mon Sep 17 00:00:00 2001 From: Kevin Mehall Date: Tue, 14 Mar 2017 20:51:00 -0700 Subject: [PATCH 072/662] Fix documentation for Vec::dedup_by. The previous docstring was copied from dedup_by_key. --- src/libcollections/vec.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d38c9f6e1cf80..7b0170ea65655 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -838,7 +838,11 @@ impl Vec { self.dedup_by(|a, b| key(a) == key(b)) } - /// Removes consecutive elements in the vector that resolve to the same key. + /// Removes consecutive elements in the vector according to a predicate. + /// + /// The `same_bucket` function is passed references to two elements from the vector, and + /// returns `true` if the elements compare equal, or `false` if they do not. Only the first + /// of adjacent equal items is kept. /// /// If the vector is sorted, this removes all duplicates. /// From 0739ecec618dc15332e1588a560ea449d4547d5e Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 15 Mar 2017 01:15:27 -0400 Subject: [PATCH 073/662] Removes Default for Box. --- src/libstd/path.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 49b01bc085373..b524af800c1c6 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1224,14 +1224,6 @@ impl Into> for PathBuf { } } -#[stable(feature = "box_default_extra", since = "1.17.0")] -impl Default for Box { - fn default() -> Box { - let boxed: Box = Default::default(); - unsafe { mem::transmute(boxed) } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + AsRef> From<&'a T> for PathBuf { fn from(s: &'a T) -> PathBuf { @@ -3730,10 +3722,4 @@ mod tests { assert_eq!(&*boxed, &*path_buf); assert_eq!(&*path_buf, path); } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert!(boxed.as_os_str().is_empty()); - } } From ce616a7d6ad838aacd080b47566c15e82ad8dd6d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 14 Mar 2017 22:04:46 +0000 Subject: [PATCH 074/662] Improve the `TokenStream` quoter. --- src/libproc_macro_plugin/lib.rs | 78 ++++++++++--------- .../{qquote.rs => quote.rs} | 26 ++++--- src/libsyntax/tokenstream.rs | 6 ++ .../auxiliary/cond_plugin.rs | 5 +- .../auxiliary/hello_macro.rs | 7 +- .../auxiliary/proc_macro_def.rs | 10 +-- src/test/run-pass-fulldeps/macro-quote-1.rs | 4 +- ...te-empty-delims.rs => macro-quote-test.rs} | 0 8 files changed, 77 insertions(+), 59 deletions(-) rename src/libproc_macro_plugin/{qquote.rs => quote.rs} (86%) rename src/test/run-pass-fulldeps/{macro-quote-empty-delims.rs => macro-quote-test.rs} (100%) diff --git a/src/libproc_macro_plugin/lib.rs b/src/libproc_macro_plugin/lib.rs index e904290957619..a6dad64125331 100644 --- a/src/libproc_macro_plugin/lib.rs +++ b/src/libproc_macro_plugin/lib.rs @@ -13,62 +13,64 @@ //! A library for procedural macro writers. //! //! ## Usage -//! This crate provides the `qquote!` macro for syntax creation. +//! This crate provides the `quote!` macro for syntax creation. //! -//! The `qquote!` macro uses the crate `syntax`, so users must declare `extern crate syntax;` +//! The `quote!` macro uses the crate `syntax`, so users must declare `extern crate syntax;` //! at the crate root. This is a temporary solution until we have better hygiene. //! //! ## Quasiquotation //! //! The quasiquoter creates output that, when run, constructs the tokenstream specified as -//! input. For example, `qquote!(5 + 5)` will produce a program, that, when run, will +//! input. For example, `quote!(5 + 5)` will produce a program, that, when run, will //! construct the TokenStream `5 | + | 5`. //! //! ### Unquoting //! -//! Unquoting is currently done as `unquote`, and works by taking the single next -//! TokenTree in the TokenStream as the unquoted term. Ergonomically, `unquote(foo)` works -//! fine, but `unquote foo` is also supported. +//! Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. +//! To quote `$` itself, use `$$`. //! -//! A simple example might be: +//! A simple example is: //! //!``` //!fn double(tmp: TokenStream) -> TokenStream { -//! qquote!(unquote(tmp) * 2) +//! quote!($tmp * 2) //!} //!``` //! -//! ### Large Example: Implementing Scheme's `cond` +//! ### Large example: Scheme's `cond` //! -//! Below is the full implementation of Scheme's `cond` operator. +//! Below is an example implementation of Scheme's `cond`. //! //! ``` -//! fn cond_rec(input: TokenStream) -> TokenStream { -//! if input.is_empty() { return quote!(); } -//! -//! let next = input.slice(0..1); -//! let rest = input.slice_from(1..); -//! -//! let clause : TokenStream = match next.maybe_delimited() { -//! Some(ts) => ts, -//! _ => panic!("Invalid input"), -//! }; -//! -//! // clause is ([test]) [rhs] -//! if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } -//! -//! let test: TokenStream = clause.slice(0..1); -//! let rhs: TokenStream = clause.slice_from(1..); -//! -//! if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { -//! quote!({unquote(rhs)}) -//! } else { -//! quote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) -//! } +//! fn cond(input: TokenStream) -> TokenStream { +//! let mut conds = Vec::new(); +//! let mut input = input.trees().peekable(); +//! while let Some(tree) = input.next() { +//! let mut cond = match tree { +//! TokenTree::Delimited(_, ref delimited) => delimited.stream(), +//! _ => panic!("Invalid input"), +//! }; +//! let mut trees = cond.trees(); +//! let test = trees.next(); +//! let rhs = trees.collect::(); +//! if rhs.is_empty() { +//! panic!("Invalid macro usage in cond: {}", cond); +//! } +//! let is_else = match test { +//! Some(TokenTree::Token(_, Token::Ident(ident))) if ident.name == "else" => true, +//! _ => false, +//! }; +//! conds.push(if is_else || input.peek().is_none() { +//! quote!({ $rhs }) +//! } else { +//! let test = test.unwrap(); +//! quote!(if $test { $rhs } else) +//! }); +//! } +//! +//! conds.into_iter().collect() //! } //! ``` -//! - #![crate_name = "proc_macro_plugin"] #![unstable(feature = "rustc_private", issue = "27812")] #![feature(plugin_registrar)] @@ -87,8 +89,8 @@ extern crate rustc_plugin; extern crate syntax; extern crate syntax_pos; -mod qquote; -use qquote::qquote; +mod quote; +use quote::quote; use rustc_plugin::Registry; use syntax::ext::base::SyntaxExtension; @@ -99,6 +101,6 @@ use syntax::symbol::Symbol; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("qquote"), - SyntaxExtension::ProcMacro(Box::new(qquote))); + reg.register_syntax_extension(Symbol::intern("quote"), + SyntaxExtension::ProcMacro(Box::new(quote))); } diff --git a/src/libproc_macro_plugin/qquote.rs b/src/libproc_macro_plugin/quote.rs similarity index 86% rename from src/libproc_macro_plugin/qquote.rs rename to src/libproc_macro_plugin/quote.rs index 0276587ed52b1..ad71584b61a0f 100644 --- a/src/libproc_macro_plugin/qquote.rs +++ b/src/libproc_macro_plugin/quote.rs @@ -19,7 +19,7 @@ use syntax_pos::DUMMY_SP; use std::iter; -pub fn qquote<'cx>(stream: TokenStream) -> TokenStream { +pub fn quote<'cx>(stream: TokenStream) -> TokenStream { stream.quote() } @@ -72,28 +72,32 @@ impl Quote for TokenStream { return quote!(::syntax::tokenstream::TokenStream::empty()); } - struct Quote(iter::Peekable); + struct Quoter(iter::Peekable); - impl Iterator for Quote { + impl Iterator for Quoter { type Item = TokenStream; fn next(&mut self) -> Option { - let is_unquote = match self.0.peek() { - Some(&TokenTree::Token(_, Token::Ident(ident))) if ident.name == "unquote" => { - self.0.next(); - true + let quoted_tree = if let Some(&TokenTree::Token(_, Token::Dollar)) = self.0.peek() { + self.0.next(); + match self.0.next() { + Some(tree @ TokenTree::Token(_, Token::Ident(..))) => Some(tree.into()), + Some(tree @ TokenTree::Token(_, Token::Dollar)) => Some(tree.quote()), + // FIXME(jseyfried): improve these diagnostics + Some(..) => panic!("`$` must be followed by an ident or `$` in `quote!`"), + None => panic!("unexpected trailing `$` in `quote!`"), } - _ => false, + } else { + self.0.next().as_ref().map(Quote::quote) }; - self.0.next().map(|tree| { - let quoted_tree = if is_unquote { tree.into() } else { tree.quote() }; + quoted_tree.map(|quoted_tree| { quote!(::syntax::tokenstream::TokenStream::from((unquote quoted_tree)),) }) } } - let quoted = Quote(self.trees().peekable()).collect::(); + let quoted = Quoter(self.trees().peekable()).collect::(); quote!([(unquote quoted)].iter().cloned().collect::<::syntax::tokenstream::TokenStream>()) } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 2da442a1a53da..8ce45f3fd08b6 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -162,6 +162,12 @@ impl From for TokenStream { } } +impl From for TokenStream { + fn from(token: Token) -> TokenStream { + TokenTree::Token(DUMMY_SP, token).into() + } +} + impl> iter::FromIterator for TokenStream { fn from_iter>(iter: I) -> Self { TokenStream::concat(iter.into_iter().map(Into::into).collect::>()) diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs index 2f94a440e72da..0433b95865ef8 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -49,9 +49,10 @@ fn cond(input: TokenStream) -> TokenStream { _ => false, }; conds.push(if is_else || input.peek().is_none() { - qquote!({ unquote rhs }) + quote!({ $rhs }) } else { - qquote!(if unquote(test.unwrap()) { unquote rhs } else) + let test = test.unwrap(); + quote!(if $test { $rhs } else) }); } diff --git a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs index 91075276a3020..9522592a5e9e6 100644 --- a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs +++ b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs @@ -29,6 +29,11 @@ pub fn plugin_registrar(reg: &mut Registry) { // This macro is not very interesting, but it does contain delimited tokens with // no content - `()` and `{}` - which has caused problems in the past. +// Also, it tests that we can escape `$` via `$$`. fn hello(_: TokenStream) -> TokenStream { - qquote!({ fn hello() {} hello(); }) + quote!({ + fn hello() {} + macro_rules! m { ($$($$t:tt)*) => { $$($$t)* } } + m!(hello()); + }) } diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs index 612c199e8281a..0e37a7a5dcce2 100644 --- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs +++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs @@ -34,21 +34,21 @@ pub fn plugin_registrar(reg: &mut Registry) { } fn attr_tru(_attr: TokenStream, _item: TokenStream) -> TokenStream { - qquote!(fn f1() -> bool { true }) + quote!(fn f1() -> bool { true }) } fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream { - qquote!(unquote item) + quote!($item) } fn tru(_ts: TokenStream) -> TokenStream { - qquote!(true) + quote!(true) } fn ret_tru(_ts: TokenStream) -> TokenStream { - qquote!(return true;) + quote!(return true;) } fn identity(ts: TokenStream) -> TokenStream { - qquote!(unquote ts) + quote!($ts) } diff --git a/src/test/run-pass-fulldeps/macro-quote-1.rs b/src/test/run-pass-fulldeps/macro-quote-1.rs index 57b6c3f0adb89..01b0ed802354c 100644 --- a/src/test/run-pass-fulldeps/macro-quote-1.rs +++ b/src/test/run-pass-fulldeps/macro-quote-1.rs @@ -22,6 +22,6 @@ use syntax::parse::token; use syntax::tokenstream::TokenTree; fn main() { - let true_tok = TokenTree::Token(syntax_pos::DUMMY_SP, token::Ident(Ident::from_str("true"))); - assert!(qquote!(true).eq_unspanned(&true_tok.into())); + let true_tok = token::Ident(Ident::from_str("true")); + assert!(quote!(true).eq_unspanned(&true_tok.into())); } diff --git a/src/test/run-pass-fulldeps/macro-quote-empty-delims.rs b/src/test/run-pass-fulldeps/macro-quote-test.rs similarity index 100% rename from src/test/run-pass-fulldeps/macro-quote-empty-delims.rs rename to src/test/run-pass-fulldeps/macro-quote-test.rs From befeb0437018820ee651ed6096a341ba1fd64a28 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 15 Mar 2017 16:32:30 -0700 Subject: [PATCH 075/662] Remove unused param from bootstrap::clean::rm_rf --- src/bootstrap/clean.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index a66ed46fe464f..e9547ee42d077 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -22,9 +22,9 @@ use std::path::Path; use Build; pub fn clean(build: &Build) { - rm_rf(build, "tmp".as_ref()); - rm_rf(build, &build.out.join("tmp")); - rm_rf(build, &build.out.join("dist")); + rm_rf("tmp".as_ref()); + rm_rf(&build.out.join("tmp")); + rm_rf(&build.out.join("dist")); for host in build.config.host.iter() { let entries = match build.out.join(host).read_dir() { @@ -38,12 +38,12 @@ pub fn clean(build: &Build) { continue } let path = t!(entry.path().canonicalize()); - rm_rf(build, &path); + rm_rf(&path); } } } -fn rm_rf(build: &Build, path: &Path) { +fn rm_rf(path: &Path) { if !path.exists() { return } @@ -55,7 +55,7 @@ fn rm_rf(build: &Build, path: &Path) { let file = t!(file).path(); if file.is_dir() { - rm_rf(build, &file); + rm_rf(&file); } else { // On windows we can't remove a readonly file, and git will // often clone files as readonly. As a result, we have some From 9b892745ad1da5ce9fc374da10f0f06174f13e48 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Mar 2017 02:15:10 +0100 Subject: [PATCH 076/662] Fix const not displayed in rustdoc --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/html/render.rs | 8 +++++--- src/test/rustdoc/const.rs | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc/const.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1294296840ebd..b51a298c72dd5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1388,7 +1388,7 @@ impl<'tcx> Clean for ty::AssociatedItem { decl: decl, abi: sig.abi(), - // trait methods canot (currently, at least) be const + // trait methods cannot (currently, at least) be const constness: hir::Constness::NotConst, }) } else { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c571bcb08e4b7..8f65c30602c5a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -60,6 +60,7 @@ use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::hir; use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::session::config::nightly_options::is_nightly_build; use rustc_data_structures::flock; use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability}; @@ -2316,9 +2317,10 @@ fn render_assoc_item(w: &mut fmt::Formatter, } }; // FIXME(#24111): remove when `const_fn` is stabilized - let vis_constness = match UnstableFeatures::from_environment() { - UnstableFeatures::Allow => constness, - _ => hir::Constness::NotConst + let vis_constness = if is_nightly_build() { + constness + } else { + hir::Constness::NotConst }; let prefix = format!("{}{}{:#}fn {}{:#}", ConstnessSpace(vis_constness), diff --git a/src/test/rustdoc/const.rs b/src/test/rustdoc/const.rs new file mode 100644 index 0000000000000..380feb941d6fe --- /dev/null +++ b/src/test/rustdoc/const.rs @@ -0,0 +1,22 @@ +// 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. + +#![crate_type="lib"] + +#![feature(const_fn)] + +pub struct Foo; + +impl Foo { + // @has const/struct.Foo.html '//*[@id="new.v"]//code' 'const unsafe fn new' + pub const unsafe fn new() -> Foo { + Foo + } +} From a5cf55125c9e5d36547a31f2ff0f028cc51b4855 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 15 Mar 2017 23:07:28 -0400 Subject: [PATCH 077/662] Implement Error for !. --- src/libstd/error.rs | 5 +++++ src/libstd/lib.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index e115263d2eb95..3d80120f6b2bd 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -216,6 +216,11 @@ impl<'a> From<&'a str> for Box { } } +#[stable(feature = "never_error", since = "1.18.0")] +impl Error for ! { + fn description(&self) -> &str { *self } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::ParseBoolError { fn description(&self) -> &str { "failed to parse bool" } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7fa5ad255609c..c8437fefe84b1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -273,6 +273,7 @@ #![feature(linkage)] #![feature(macro_reexport)] #![feature(needs_panic_runtime)] +#![feature(never_type)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] From 28626ca5b1228f283fbc7c85d88cf897c7750267 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 15 Mar 2017 14:24:02 -0700 Subject: [PATCH 078/662] Stabilize pub(restricted) --- src/doc/unstable-book/src/SUMMARY.md | 1 - src/doc/unstable-book/src/pub-restricted.md | 10 ------ src/librustc/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_privacy/lib.rs | 4 +-- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 17 ++-------- .../auxiliary/pub_and_stability.rs | 1 - src/test/compile-fail/imports/unused.rs | 1 - .../restricted/auxiliary/pub_restricted.rs | 2 -- .../privacy/restricted/feature-gate.rs | 27 ---------------- .../restricted/lookup-ignores-private.rs | 2 +- .../privacy/restricted/private-in-public.rs | 4 ++- .../restricted/struct-literal-field.rs | 1 - .../compile-fail/privacy/restricted/test.rs | 1 - .../restricted/tuple-struct-fields/test.rs | 2 -- .../restricted/tuple-struct-fields/test2.rs | 2 -- .../restricted/tuple-struct-fields/test3.rs | 2 -- .../privacy/restricted/ty-params.rs | 2 -- .../privacy/union-field-privacy-1.rs | 1 - .../privacy/union-field-privacy-2.rs | 1 - .../compile-fail/resolve-bad-visibility.rs | 2 -- .../resolve/auxiliary/privacy-struct-ctor.rs | 2 -- src/test/ui/resolve/privacy-struct-ctor.rs | 2 -- .../ui/resolve/privacy-struct-ctor.stderr | 32 +++++++++---------- src/test/ui/span/pub-struct-field.rs | 2 -- src/test/ui/span/pub-struct-field.stderr | 14 ++++---- 27 files changed, 35 insertions(+), 106 deletions(-) delete mode 100644 src/doc/unstable-book/src/pub-restricted.md delete mode 100644 src/test/compile-fail/privacy/restricted/feature-gate.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 5fb323d6ce909..f5d6785d44559 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -65,7 +65,6 @@ - [plugin_registrar](plugin-registrar.md) - [prelude_import](prelude-import.md) - [proc_macro](proc-macro.md) -- [pub_restricted](pub-restricted.md) - [quote](quote.md) - [relaxed_adts](relaxed-adts.md) - [repr_simd](repr-simd.md) diff --git a/src/doc/unstable-book/src/pub-restricted.md b/src/doc/unstable-book/src/pub-restricted.md deleted file mode 100644 index 730461813cbec..0000000000000 --- a/src/doc/unstable-book/src/pub-restricted.md +++ /dev/null @@ -1,10 +0,0 @@ -# `pub_restricted` - -The tracking issue for this feature is: [#32409] - -[#32409]: https://github.com/rust-lang/rust/issues/32409 - ------------------------- - - - diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c4fccdcb9eb62..a007c9d2c43a9 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -34,7 +34,7 @@ #![feature(libc)] #![feature(loop_break_value)] #![feature(nonzero)] -#![feature(pub_restricted)] +#![cfg_attr(stage0, feature(pub_restricted))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 906c4b7256fdc..0a8719c125329 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -25,7 +25,7 @@ #![feature(core_intrinsics)] #![feature(conservative_impl_trait)] #![cfg_attr(stage0,feature(field_init_shorthand))] -#![feature(pub_restricted)] +#![cfg_attr(stage0, feature(pub_restricted))] extern crate graphviz; #[macro_use] extern crate rustc; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 72347f1616eb6..074e2b873ec60 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' self.min_visibility = vis; } if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors { + if self.has_old_errors { let mut err = struct_span_err!(self.tcx.sess, self.span, E0446, "private type `{}` in public interface", ty); err.span_label(self.span, &format!("can't leak private type")); @@ -986,7 +986,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' self.min_visibility = vis; } if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors { + if self.has_old_errors { struct_span_err!(self.tcx.sess, self.span, E0445, "private trait `{}` in public interface", trait_ref) .span_label(self.span, &format!( diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7fa5ad255609c..aa49ecfd3332c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,7 +283,6 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(prelude_import)] -#![feature(pub_restricted)] #![feature(rand)] #![feature(raw)] #![feature(repr_simd)] @@ -309,6 +308,7 @@ #![feature(vec_push_all)] #![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] +#![cfg_attr(stage0, feature(pub_restricted))] // Explicitly import the prelude. The compiler uses this same unstable attribute // to import the prelude implicitly when building crates that depend on std. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 15913d56d162f..5eb9366fb2faf 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -260,9 +260,6 @@ declare_features! ( // impl specialization (RFC 1210) (active, specialization, "1.7.0", Some(31844)), - // pub(restricted) visibilities (RFC 1422) - (active, pub_restricted, "1.9.0", Some(32409)), - // Allow Drop types in statics/const functions (RFC 1440) (active, drop_types_in_const, "1.9.0", Some(33156)), @@ -406,6 +403,9 @@ declare_features! ( (accepted, field_init_shorthand, "1.17.0", Some(37340)), // Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719)), + // pub(restricted) visibilities (RFC 1422) + (accepted, pub_restricted, "1.17.0", Some(32409)), + ); // If you change this, please modify src/doc/unstable-book as well. You must // move that documentation into the relevant place in the other docs, and @@ -1410,17 +1410,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_impl_item(self, ii); } - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - let span = match *vis { - ast::Visibility::Crate(span) => span, - ast::Visibility::Restricted { ref path, .. } => path.span, - _ => return, - }; - gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental"); - - visit::walk_vis(self, vis) - } - fn visit_generics(&mut self, g: &'a ast::Generics) { for t in &g.ty_params { if !t.attrs.is_empty() { diff --git a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs index 6f458da9b527b..dfbe35dfd56ba 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs @@ -35,7 +35,6 @@ // non-pub fields, marked with SILLY below) #![feature(staged_api)] -#![feature(pub_restricted)] #![stable(feature = "unit_test", since = "0.0.0")] diff --git a/src/test/compile-fail/imports/unused.rs b/src/test/compile-fail/imports/unused.rs index 05ecc781af30d..1eb756fe9e4ec 100644 --- a/src/test/compile-fail/imports/unused.rs +++ b/src/test/compile-fail/imports/unused.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] #![deny(unused)] mod foo { diff --git a/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs b/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs index b1c88ce6ce55c..82d14ddb502b3 100644 --- a/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs +++ b/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - pub(crate) struct Crate; #[derive(Default)] pub struct Universe { diff --git a/src/test/compile-fail/privacy/restricted/feature-gate.rs b/src/test/compile-fail/privacy/restricted/feature-gate.rs deleted file mode 100644 index e81e1e30d1750..0000000000000 --- a/src/test/compile-fail/privacy/restricted/feature-gate.rs +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -// gate-test-pub_restricted - -pub(crate) //~ ERROR experimental -mod foo {} - -pub(self) //~ ERROR experimental -mod bar {} - -struct S { - pub(self) x: i32, //~ ERROR experimental -} -impl S { - pub(self) fn f() {} //~ ERROR experimental -} -extern { - pub(self) fn f(); //~ ERROR experimental -} diff --git a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs index 2d4b5545544c6..abd71b9c90b22 100644 --- a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs +++ b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, pub_restricted)] +#![feature(rustc_attrs)] #![allow(warnings)] mod foo { diff --git a/src/test/compile-fail/privacy/restricted/private-in-public.rs b/src/test/compile-fail/privacy/restricted/private-in-public.rs index 84328ca387d73..2f06362880315 100644 --- a/src/test/compile-fail/privacy/restricted/private-in-public.rs +++ b/src/test/compile-fail/privacy/restricted/private-in-public.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] +#![deny(warnings)] +#![allow(unused)] mod foo { struct Priv; @@ -16,6 +17,7 @@ mod foo { use foo::Priv; pub(super) fn f(_: Priv) {} pub(crate) fn g(_: Priv) {} //~ ERROR E0446 + //~^ this was previously accepted } } diff --git a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs index 53786d45c73ee..68458fe3f04ba 100644 --- a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs +++ b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] #![deny(private_in_public)] #![allow(warnings)] diff --git a/src/test/compile-fail/privacy/restricted/test.rs b/src/test/compile-fail/privacy/restricted/test.rs index d55ee8221cd73..12697d51042ed 100644 --- a/src/test/compile-fail/privacy/restricted/test.rs +++ b/src/test/compile-fail/privacy/restricted/test.rs @@ -10,7 +10,6 @@ // aux-build:pub_restricted.rs -#![feature(pub_restricted)] #![deny(private_in_public)] #![allow(warnings)] extern crate pub_restricted; diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index f3dcf405a68a6..bb212b3114d11 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - mod foo { type T = (); struct S1(pub(foo) (), pub(T), pub(crate) (), pub(((), T))); diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 3bf8ca30a6c3f..2c6e71d7c55e6 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index febe224fb84dc..e15eeae8159a3 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); diff --git a/src/test/compile-fail/privacy/restricted/ty-params.rs b/src/test/compile-fail/privacy/restricted/ty-params.rs index cd0edc8fe7c44..c83a4e568528f 100644 --- a/src/test/compile-fail/privacy/restricted/ty-params.rs +++ b/src/test/compile-fail/privacy/restricted/ty-params.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - macro_rules! m { ($p: path) => (pub(in $p) struct Z;) } diff --git a/src/test/compile-fail/privacy/union-field-privacy-1.rs b/src/test/compile-fail/privacy/union-field-privacy-1.rs index 4924fabafb0a0..bddcd391b205d 100644 --- a/src/test/compile-fail/privacy/union-field-privacy-1.rs +++ b/src/test/compile-fail/privacy/union-field-privacy-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] #![feature(untagged_unions)] mod m { diff --git a/src/test/compile-fail/privacy/union-field-privacy-2.rs b/src/test/compile-fail/privacy/union-field-privacy-2.rs index 7151538f41256..e26b5e99ec1a5 100644 --- a/src/test/compile-fail/privacy/union-field-privacy-2.rs +++ b/src/test/compile-fail/privacy/union-field-privacy-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] #![feature(untagged_unions)] mod m { diff --git a/src/test/compile-fail/resolve-bad-visibility.rs b/src/test/compile-fail/resolve-bad-visibility.rs index 20878a91ede99..420a45a2147e6 100644 --- a/src/test/compile-fail/resolve-bad-visibility.rs +++ b/src/test/compile-fail/resolve-bad-visibility.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - enum E {} trait Tr {} diff --git a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs index 383224b2f9273..704b20c6e712e 100644 --- a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(pub_restricted)] - pub mod m { pub struct S(u8); diff --git a/src/test/ui/resolve/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs index 68bd74719f55c..87e7b4f42a1c0 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/privacy-struct-ctor.rs @@ -10,8 +10,6 @@ // aux-build:privacy-struct-ctor.rs -#![feature(pub_restricted)] - extern crate privacy_struct_ctor as xcrate; mod m { diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index 30fdbb02cc715..25afb6147e422 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -1,7 +1,7 @@ error[E0423]: expected value, found struct `Z` - --> $DIR/privacy-struct-ctor.rs:28:9 + --> $DIR/privacy-struct-ctor.rs:26:9 | -28 | Z; +26 | Z; | ^ | | | did you mean `Z { /* fields */ }`? @@ -11,9 +11,9 @@ error[E0423]: expected value, found struct `Z` `use m::n::Z;` error[E0423]: expected value, found struct `S` - --> $DIR/privacy-struct-ctor.rs:38:5 + --> $DIR/privacy-struct-ctor.rs:36:5 | -38 | S; +36 | S; | ^ | | | did you mean `S { /* fields */ }`? @@ -23,9 +23,9 @@ error[E0423]: expected value, found struct `S` `use m::S;` error[E0423]: expected value, found struct `xcrate::S` - --> $DIR/privacy-struct-ctor.rs:44:5 + --> $DIR/privacy-struct-ctor.rs:42:5 | -44 | xcrate::S; +42 | xcrate::S; | ^^^^^^^^^ | | | did you mean `xcrate::S { /* fields */ }`? @@ -35,33 +35,33 @@ error[E0423]: expected value, found struct `xcrate::S` `use m::S;` error: tuple struct `Z` is private - --> $DIR/privacy-struct-ctor.rs:27:9 + --> $DIR/privacy-struct-ctor.rs:25:9 | -27 | n::Z; //~ ERROR tuple struct `Z` is private +25 | n::Z; //~ ERROR tuple struct `Z` is private | ^^^^ error: tuple struct `S` is private - --> $DIR/privacy-struct-ctor.rs:37:5 + --> $DIR/privacy-struct-ctor.rs:35:5 | -37 | m::S; //~ ERROR tuple struct `S` is private +35 | m::S; //~ ERROR tuple struct `S` is private | ^^^^ error: tuple struct `Z` is private - --> $DIR/privacy-struct-ctor.rs:41:5 + --> $DIR/privacy-struct-ctor.rs:39:5 | -41 | m::n::Z; //~ ERROR tuple struct `Z` is private +39 | m::n::Z; //~ ERROR tuple struct `Z` is private | ^^^^^^^ error: tuple struct `S` is private - --> $DIR/privacy-struct-ctor.rs:43:5 + --> $DIR/privacy-struct-ctor.rs:41:5 | -43 | xcrate::m::S; //~ ERROR tuple struct `S` is private +41 | xcrate::m::S; //~ ERROR tuple struct `S` is private | ^^^^^^^^^^^^ error: tuple struct `Z` is private - --> $DIR/privacy-struct-ctor.rs:47:5 + --> $DIR/privacy-struct-ctor.rs:45:5 | -47 | xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private +45 | xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private | ^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/span/pub-struct-field.rs b/src/test/ui/span/pub-struct-field.rs index 9f8f871200ca5..54cb0b59c75c3 100644 --- a/src/test/ui/span/pub-struct-field.rs +++ b/src/test/ui/span/pub-struct-field.rs @@ -11,8 +11,6 @@ // Regression test for issue #26083 and #35435 // Test that span for public struct fields start at `pub` -#![feature(pub_restricted)] - struct Foo { bar: u8, pub bar: u8, diff --git a/src/test/ui/span/pub-struct-field.stderr b/src/test/ui/span/pub-struct-field.stderr index 2c002c34736c5..c66361c8546b8 100644 --- a/src/test/ui/span/pub-struct-field.stderr +++ b/src/test/ui/span/pub-struct-field.stderr @@ -1,18 +1,18 @@ error[E0124]: field `bar` is already declared - --> $DIR/pub-struct-field.rs:18:5 + --> $DIR/pub-struct-field.rs:16:5 | -17 | bar: u8, +15 | bar: u8, | ------- `bar` first declared here -18 | pub bar: u8, +16 | pub bar: u8, | ^^^^^^^^^^^ field already declared error[E0124]: field `bar` is already declared - --> $DIR/pub-struct-field.rs:19:5 + --> $DIR/pub-struct-field.rs:17:5 | -17 | bar: u8, +15 | bar: u8, | ------- `bar` first declared here -18 | pub bar: u8, -19 | pub(crate) bar: u8, +16 | pub bar: u8, +17 | pub(crate) bar: u8, | ^^^^^^^^^^^^^^^^^^ field already declared error: aborting due to 2 previous errors From ec829fe00e3af57aa083b83f282ad05c2cc9acc7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 16 Mar 2017 07:55:15 -0700 Subject: [PATCH 079/662] travis: Update sccache binary I've built a local copy with mozilla/sccache#79 and mozilla/sccache#78. Let's see if that helps #40240! --- .travis.yml | 4 ++-- appveyor.yml | 4 ++-- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/cross/Dockerfile | 2 +- src/ci/docker/dist-android/Dockerfile | 2 +- src/ci/docker/dist-arm-linux/Dockerfile | 2 +- src/ci/docker/dist-armv7-aarch64-linux/Dockerfile | 2 +- src/ci/docker/dist-freebsd/Dockerfile | 2 +- src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 2 +- src/ci/docker/dist-mips-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- src/ci/docker/dist-s390x-linux-netbsd/Dockerfile | 2 +- src/ci/docker/dist-x86-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-musl/Dockerfile | 2 +- src/ci/docker/emscripten/Dockerfile | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 2 +- src/ci/docker/i686-gnu/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-debug/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-distcheck/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-incremental/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-nopt/Dockerfile | 2 +- src/ci/docker/x86_64-gnu/Dockerfile | 2 +- 28 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index 988ef66f8fadd..86bb7351c39d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache - env: > RUST_CHECK_TARGET=check @@ -75,7 +75,7 @@ matrix: os: osx osx_image: xcode8.2 install: > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache - env: > RUST_CHECK_TARGET=dist diff --git a/appveyor.yml b/appveyor.yml index 94a5efb3a2ffb..8de49cc834d33 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-pc-windows-msvc - - mv 2017-02-25-sccache-x86_64-pc-windows-msvc sccache + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-pc-windows-msvc + - mv 2017-03-16-sccache-x86_64-pc-windows-msvc sccache - set PATH=%PATH%;%CD% # Install InnoSetup to get `iscc` used to produce installers diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 39b7e9df4b842..a3e74adbb3672 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 1d5be59186bdb..72675bc9a446c 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 6d433cc1509f2..031ad0ddcd4e6 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index e2ab6f636af91..ae439f5b30f29 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile index 5528b05104b8e..7f3c552258780 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-freebsd/Dockerfile index 43e0734b74aed..deee78847bbf6 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-freebsd/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index 25a47c5be1cb3..de8ed3378eb16 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index 0897be80cc22c..f19860405b02c 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index a99e9292df58a..8de9b6abddd6f 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 865d7ea5ea25f..134f475f82d6e 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index 4ca39eae53f92..1c61714adbd2a 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 2aeff7a0b90a5..4407300e20dfc 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index 79ffac73425f9..fd67f185162d9 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 3f6f71c41b520..50244280971cb 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -75,7 +75,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 5877404ece149..151552331c86c 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 0757547bd2d33..e8eb151a0784c 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index 61f8e3dd06a45..aca4bfb546d2f 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index 1dcdc5591f56f..2664307b09b30 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index ac46a35a0bcfb..fdc8221ad250d 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1f577b4e8ae4e..dae7fac3890d8 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 66cf2a5939f8b..05ff4847ecc1d 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 3919daeabaeef..176b1f0a857db 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index b01b430cc68c4..216b2d9a65624 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index 89c5a6c89d3a0..d91e05e2b2dff 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index be731e2b0d8a8..d79b07efab525 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index 02a8fb964ffd2..71ed9ab943a0a 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ From 910532ed5e2777fbce7ee6d608d6687e63110a42 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Fri, 17 Mar 2017 00:21:40 +0900 Subject: [PATCH 080/662] Add a test for issue 34571 --- src/test/run-pass/issue-34571.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/run-pass/issue-34571.rs diff --git a/src/test/run-pass/issue-34571.rs b/src/test/run-pass/issue-34571.rs new file mode 100644 index 0000000000000..7d80415657655 --- /dev/null +++ b/src/test/run-pass/issue-34571.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +#[repr(u8)] +enum Foo { + Foo(u8), +} + +fn main() { + match Foo::Foo(1) { + _ => () + } +} From e9c07cfc0e92e9370d8cbcb78ac84efe0a6c1644 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Thu, 16 Mar 2017 11:19:47 -0400 Subject: [PATCH 081/662] fix typo in mir TerminatorKind docs --- src/librustc/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index fea576f706780..659e115135ee5 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -467,7 +467,7 @@ pub enum TerminatorKind<'tcx> { values: Cow<'tcx, [ConstInt]>, /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so values.len() == targets.len() + 1 + /// for the otherwise branch, so targets.len() == values.len() + 1 /// should hold. // This invariant is quite non-obvious and also could be improved. // One way to make this invariant is to have something like this instead: From 449219ab2bf65f465b18c0841d7f8d9d3b958943 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 16 Mar 2017 21:01:05 +0100 Subject: [PATCH 082/662] isolate llvm 4.0 code path --- src/rustllvm/RustWrapper.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index e89f48b4105d3..714fd2459da10 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -606,26 +606,20 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( InitExpr = Builder->createConstantValueExpression( FPVal->getValueAPF().bitcastToAPInt().getZExtValue()); } -#endif -#if LLVM_VERSION_GE(4, 0) return wrap(Builder->createGlobalVariableExpression( -#else - return wrap(Builder->createGlobalVariable( -#endif unwrapDI(Context), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, -#if LLVM_VERSION_GE(4, 0) InitExpr, + unwrapDIPtr(Decl), + AlignInBits)); #else + return wrap(Builder->createGlobalVariable( + unwrapDI(Context), Name, LinkageName, + unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, InitVal, + unwrapDIPtr(Decl))); #endif - unwrapDIPtr(Decl) -#if LLVM_VERSION_GE(4, 0) - , - AlignInBits -#endif - )); } extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( From 222ca3c4a550e001e0b1bb957f0035d6bd753d4a Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 16 Mar 2017 21:03:22 +0100 Subject: [PATCH 083/662] clang-format --- src/rustllvm/RustWrapper.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 714fd2459da10..bb0a44cef672b 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -610,15 +610,12 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( return wrap(Builder->createGlobalVariableExpression( unwrapDI(Context), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, - InitExpr, - unwrapDIPtr(Decl), - AlignInBits)); + InitExpr, unwrapDIPtr(Decl), AlignInBits)); #else return wrap(Builder->createGlobalVariable( unwrapDI(Context), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, - InitVal, - unwrapDIPtr(Decl))); + InitVal, unwrapDIPtr(Decl))); #endif } From 95bd7f2e013ad79d857ac54b42b362b36ae8806d Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 16 Mar 2017 21:10:04 +0100 Subject: [PATCH 084/662] add missing global metadata --- src/rustllvm/RustWrapper.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index bb0a44cef672b..5ab786f40b933 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -9,6 +9,7 @@ // except according to those terms. #include "rustllvm.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Instructions.h" @@ -594,7 +595,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( const char *LinkageName, LLVMRustMetadataRef File, unsigned LineNo, LLVMRustMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, LLVMRustMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { - Constant *InitVal = cast(unwrap(V)); + llvm::GlobalVariable *InitVal = cast(unwrap(V)); #if LLVM_VERSION_GE(4, 0) llvm::DIExpression *InitExpr = nullptr; @@ -607,10 +608,14 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( FPVal->getValueAPF().bitcastToAPInt().getZExtValue()); } - return wrap(Builder->createGlobalVariableExpression( + llvm::DIGlobalVariableExpression *VarExpr = Builder->createGlobalVariableExpression( unwrapDI(Context), Name, LinkageName, unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, - InitExpr, unwrapDIPtr(Decl), AlignInBits)); + InitExpr, unwrapDIPtr(Decl), AlignInBits); + + InitVal->setMetadata("dbg", VarExpr); + + return wrap(VarExpr); #else return wrap(Builder->createGlobalVariable( unwrapDI(Context), Name, LinkageName, From 1d93a6cce0119dfb1248643c7fb701ff1f8d4a50 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 17 Mar 2017 10:23:40 +1300 Subject: [PATCH 085/662] Fix handlebars failure by using the `rustbuild` feature less indiscriminately. --- src/bootstrap/bin/rustc.rs | 8 +++++++- src/bootstrap/lib.rs | 25 +++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 5e6f3e9e6cc0f..82be4e3361eb6 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -79,7 +79,6 @@ fn main() { cmd.args(&args) .arg("--cfg") .arg(format!("stage{}", stage)) - .arg("--cfg").arg("rustbuild") .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); @@ -95,6 +94,13 @@ fn main() { cmd.arg("-Cprefer-dynamic"); } + // Pass the `rustbuild` feature flag to crates which rustbuild is + // building. See the comment in bootstrap/lib.rs where this env var is + // set for more details. + if env::var_os("RUSTBUILD_UNSTABLE").is_some() { + cmd.arg("--cfg").arg("rustbuild"); + } + // Help the libc crate compile by assisting it in finding the MUSL // native libraries. if let Some(s) = env::var_os("MUSL_ROOT") { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2d2be531e628c..fbee0cb0563aa 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -180,7 +180,7 @@ struct Crate { /// /// These entries currently correspond to the various output directories of the /// build system, with each mod generating output in a different directory. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum Mode { /// This cargo is going to build the standard library, placing output in the /// "stageN-std" directory. @@ -491,7 +491,7 @@ impl Build { // For other crates, however, we know that we've already got a standard // library up and running, so we can use the normal compiler to compile // build scripts in that situation. - if let Mode::Libstd = mode { + if mode == Mode::Libstd { cargo.env("RUSTC_SNAPSHOT", &self.rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); } else { @@ -499,6 +499,27 @@ impl Build { .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); } + // There are two invariants we try must maintain: + // * stable crates cannot depend on unstable crates (general Rust rule), + // * crates that end up in the sysroot must be unstable (rustbuild rule). + // + // In order to do enforce the latter, we pass the env var + // `RUSTBUILD_UNSTABLE` down the line for any crates which will end up + // in the sysroot. We read this in bootstrap/bin/rustc.rs and if it is + // set, then we pass the `rustbuild` feature to rustc when building the + // the crate. + // + // In turn, crates that can be used here should recognise the `rustbuild` + // feature and opt-in to `rustc_private`. + // + // We can't always pass `rustbuild` because crates which are outside of + // the comipiler, libs, and tests are stable and we don't want to make + // their deps unstable (since this would break the first invariant + // above). + if mode != Mode::Tool { + cargo.env("RUSTBUILD_UNSTABLE", "1"); + } + // Ignore incremental modes except for stage0, since we're // not guaranteeing correctness acros builds if the compiler // is changing under your feet.` From 3d01e1ada9eb3e69abdfc1b1e51222c414c46215 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 16 Mar 2017 17:47:30 -0400 Subject: [PATCH 086/662] add sort_unstable to unstable book cc #40585 --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/sort-unstable.md | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 src/doc/unstable-book/src/sort-unstable.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 5fb323d6ce909..44eda204a3d29 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -75,6 +75,7 @@ - [simd](simd.md) - [simd_ffi](simd-ffi.md) - [slice_patterns](slice-patterns.md) +- [sort_unstable](sort-unstable.md) - [specialization](specialization.md) - [staged_api](staged-api.md) - [start](start.md) diff --git a/src/doc/unstable-book/src/sort-unstable.md b/src/doc/unstable-book/src/sort-unstable.md new file mode 100644 index 0000000000000..aec39de2c9a73 --- /dev/null +++ b/src/doc/unstable-book/src/sort-unstable.md @@ -0,0 +1,9 @@ +# `sort_unstable` + +The tracking issue for this feature is: [#40585] + +[#40585]: https://github.com/rust-lang/rust/issues/40585 + +------------------------ + + From 5364acb41870eca5b7b41c7980851e6a524c4ca3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Mar 2017 22:59:55 +0100 Subject: [PATCH 087/662] Fix invalid debug display for associated consts --- src/librustdoc/clean/mod.rs | 8 ++++---- src/librustdoc/html/format.rs | 4 ++-- src/test/rustdoc/const-doc.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc/const-doc.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1294296840ebd..60245b5b39302 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2242,11 +2242,11 @@ pub enum PathParameters { AngleBracketed { lifetimes: Vec, types: Vec, - bindings: Vec + bindings: Vec, }, Parenthesized { inputs: Vec, - output: Option + output: Option, } } @@ -2261,14 +2261,14 @@ impl Clean for hir::PathParameters { data.lifetimes.clean(cx) }, types: data.types.clean(cx), - bindings: data.bindings.clean(cx) + bindings: data.bindings.clean(cx), } } hir::ParenthesizedParameters(ref data) => { PathParameters::Parenthesized { inputs: data.inputs.clean(cx), - output: data.output.clean(cx) + output: data.output.clean(cx), } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fc5507d4d5559..a255ba0ad4edf 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -481,7 +481,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, if is_not_debug { write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?; } else { - write!(w, "{:?}{:?}", HRef::new(did, &last.name), last.params)?; + write!(w, "{:?}{}", HRef::new(did, &last.name), last.params)?; } } else { if is_not_debug { @@ -507,7 +507,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, } else { format!("{:?}", HRef::new(did, &last.name)) }; - write!(w, "{}{:?}", path, last.params)?; + write!(w, "{}{}", path, last.params)?; } } Ok(()) diff --git a/src/test/rustdoc/const-doc.rs b/src/test/rustdoc/const-doc.rs new file mode 100644 index 0000000000000..9f70fe43175b9 --- /dev/null +++ b/src/test/rustdoc/const-doc.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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(associated_consts)] + +use std::marker::PhantomData; + +pub struct Foo<'a> { + f: PhantomData<&'a u32>, +} + +pub struct ContentType { + pub ttype: Foo<'static>, + pub subtype: Foo<'static>, + pub params: Option>, +} + +impl ContentType { + // @has const_doc/struct.ContentType.html + // @has - '//*[@class="docblock"]' 'Any: ContentType = ContentType{ttype: Foo{f: ' + pub const Any: ContentType = ContentType { ttype: Foo { f: PhantomData, }, + subtype: Foo { f: PhantomData, }, + params: None, }; +} From 50cede0d31e74d271d94eb6df85988bc9e05c120 Mon Sep 17 00:00:00 2001 From: z1mvader Date: Thu, 16 Mar 2017 19:59:36 -0500 Subject: [PATCH 088/662] documented order of conversion between u32 an ipv4addr --- src/libstd/net/ip.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 5d6e8d319d7b2..24e0e6f3fa659 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -636,6 +636,7 @@ impl FromInner for Ipv4Addr { #[stable(feature = "ip_u32", since = "1.1.0")] impl From for u32 { + /// It performs the conversion in network order (big-endian). fn from(ip: Ipv4Addr) -> u32 { let ip = ip.octets(); ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) @@ -644,6 +645,7 @@ impl From for u32 { #[stable(feature = "ip_u32", since = "1.1.0")] impl From for Ipv4Addr { + /// It performs the conversion in network order (big-endian). fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) } From bbfdb56910ffe84bfff7fbf0472cbb4647ee5d45 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Mar 2017 07:04:18 -0700 Subject: [PATCH 089/662] travis: Use `hide_output` in dist-powerpc64-linux Looks like we blew the 4MB cap, so let's hide some more output. --- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- .../build-powerpc64-toolchain.sh | 17 +------------ .../build-powerpc64le-toolchain.sh | 16 ++++++------ src/ci/docker/dist-powerpc64-linux/shared.sh | 25 +++++++++++++++++++ 4 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 src/ci/docker/dist-powerpc64-linux/shared.sh diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 4407300e20dfc..975ae1d3ec9c1 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -61,7 +61,7 @@ USER rustbuild WORKDIR /tmp COPY patches/ /tmp/patches/ -COPY powerpc64-linux-gnu.config build-powerpc64-toolchain.sh /tmp/ +COPY shared.sh powerpc64-linux-gnu.config build-powerpc64-toolchain.sh /tmp/ RUN ./build-powerpc64-toolchain.sh USER root diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh index d70947d2dd9d6..c477cd61f98de 100755 --- a/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh @@ -11,22 +11,7 @@ set -ex -hide_output() { - set +x - on_err=" -echo ERROR: An error was encountered with the build. -cat /tmp/build.log -exit 1 -" - trap "$on_err" ERR - bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & - PING_LOOP_PID=$! - $@ &> /tmp/build.log - rm /tmp/build.log - trap - ERR - kill $PING_LOOP_PID - set -x -} +source shared.sh mkdir build cd build diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh index 8b924ca34c47c..4d3e638916dbf 100755 --- a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh @@ -11,6 +11,8 @@ set -ex +source shared.sh + BINUTILS=2.25.1 GCC=5.3.0 TARGET=powerpc64le-linux-gnu @@ -40,9 +42,9 @@ pushd binutils-$TARGET curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - mkdir binutils-build cd binutils-build -../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT -make -j10 -make install +hide_output ../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT +hide_output make -j10 +hide_output make install popd rm -rf binutils-$TARGET @@ -51,11 +53,11 @@ mkdir gcc-$TARGET pushd gcc-$TARGET curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - cd gcc-$GCC -./contrib/download_prerequisites +hide_output ./contrib/download_prerequisites mkdir ../gcc-build cd ../gcc-build -../gcc-$GCC/configure \ +hide_output ../gcc-$GCC/configure \ --enable-languages=c,c++ \ --target=$TARGET \ --with-cpu=power8 \ @@ -72,8 +74,8 @@ cd ../gcc-build --disable-libsanitizer \ --disable-libquadmath-support \ --disable-lto -make -j10 -make install +hide_output hide_output make -j10 +hide_output make install popd rm -rf gcc-$TARGET diff --git a/src/ci/docker/dist-powerpc64-linux/shared.sh b/src/ci/docker/dist-powerpc64-linux/shared.sh new file mode 100644 index 0000000000000..97e6d2908cf8a --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 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. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} From 963d4dfddeb302326432eb089771c4aed29f7b5c Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 17 Mar 2017 10:50:30 -0500 Subject: [PATCH 090/662] minor wording tweak to slice::{as_ptr, as_mut_ptr} --- src/libcollections/slice.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 2ea953df87357..0723be828e5b7 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -437,8 +437,8 @@ impl [T] { /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. /// - /// Modifying the slice may cause its buffer to be reallocated, which - /// would also make any pointers to it invalid. + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. /// /// # Examples /// @@ -463,8 +463,8 @@ impl [T] { /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. /// - /// Modifying the slice may cause its buffer to be reallocated, which - /// would also make any pointers to it invalid. + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. /// /// # Examples /// From ec8ecf4f9d06f7e034180a6c56f33a6f800dd1e2 Mon Sep 17 00:00:00 2001 From: ScottAbbey Date: Fri, 17 Mar 2017 13:27:13 -0500 Subject: [PATCH 091/662] Fix typo in mutex.rs docs This seems to match other uses of "be accessed" in the document. --- src/libstd/sync/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 97b84d59218ac..483d0ef752ddb 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -132,7 +132,7 @@ unsafe impl Sync for Mutex { } /// 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 access through this guard via its +/// The data protected by the mutex can be accessed through this guard via its /// [`Deref`] and [`DerefMut`] implementations. /// /// This structure is created by the [`lock()`] and [`try_lock()`] methods on From 33a56659886a2afc3207de39000a9d74f3dddadc Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 20:46:56 -0700 Subject: [PATCH 092/662] Stabilize move_cell feature, closes #39264 --- src/libcore/cell.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 736797d162b1d..0186d9727828d 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -394,7 +394,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(move_cell)] /// use std::cell::Cell; /// /// let c1 = Cell::new(5i32); @@ -404,7 +403,7 @@ impl Cell { /// assert_eq!(5, c2.get()); /// ``` #[inline] - #[unstable(feature = "move_cell", issue = "39264")] + #[stable(feature = "move_cell", since = "1.17.0")] pub fn swap(&self, other: &Self) { if ptr::eq(self, other) { return; @@ -419,7 +418,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(move_cell)] /// use std::cell::Cell; /// /// let c = Cell::new(5); @@ -427,7 +425,7 @@ impl Cell { /// /// assert_eq!(5, old); /// ``` - #[unstable(feature = "move_cell", issue = "39264")] + #[stable(feature = "move_cell", since = "1.17.0")] pub fn replace(&self, val: T) -> T { mem::replace(unsafe { &mut *self.value.get() }, val) } @@ -437,7 +435,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(move_cell)] /// use std::cell::Cell; /// /// let c = Cell::new(5); @@ -445,7 +442,7 @@ impl Cell { /// /// assert_eq!(five, 5); /// ``` - #[unstable(feature = "move_cell", issue = "39264")] + #[stable(feature = "move_cell", since = "1.17.0")] pub fn into_inner(self) -> T { unsafe { self.value.into_inner() } } @@ -457,7 +454,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(move_cell)] /// use std::cell::Cell; /// /// let c = Cell::new(5); @@ -466,7 +462,7 @@ impl Cell { /// assert_eq!(five, 5); /// assert_eq!(c.into_inner(), 0); /// ``` - #[unstable(feature = "move_cell", issue = "39264")] + #[stable(feature = "move_cell", since = "1.17.0")] pub fn take(&self) -> T { self.replace(Default::default()) } From 65b7c4ed31ae8601c39deab8ca18235b0bea520b Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 20:49:18 -0700 Subject: [PATCH 093/662] Stabilize expect_err feature, closes #39041 --- src/libcore/result.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index a05db9b489ca1..00ff2fd2ce5ef 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -803,12 +803,11 @@ impl Result { /// Basic usage: /// /// ```{.should_panic} - /// # #![feature(result_expect_err)] /// let x: Result = Ok(10); /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10` /// ``` #[inline] - #[unstable(feature = "result_expect_err", issue = "39041")] + #[stable(feature = "result_expect_err", since = "1.17.0")] pub fn expect_err(self, msg: &str) -> E { match self { Ok(t) => unwrap_failed(msg, t), From d38ea8b371f781aa4b0689c46ede75b5385fedba Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 20:51:29 -0700 Subject: [PATCH 094/662] Stabilize ptr_unaligned feature, closes #37955 --- src/libcore/ptr.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 0b7aa4fa9117c..e4ad8cfd25654 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -161,8 +161,6 @@ pub unsafe fn read(src: *const T) -> T { /// Basic usage: /// /// ``` -/// #![feature(ptr_unaligned)] -/// /// let x = 12; /// let y = &x as *const i32; /// @@ -171,7 +169,7 @@ pub unsafe fn read(src: *const T) -> T { /// } /// ``` #[inline(always)] -#[unstable(feature = "ptr_unaligned", issue = "37955")] +#[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn read_unaligned(src: *const T) -> T { let mut tmp: T = mem::uninitialized(); copy_nonoverlapping(src as *const u8, @@ -243,8 +241,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Basic usage: /// /// ``` -/// #![feature(ptr_unaligned)] -/// /// let mut x = 0; /// let y = &mut x as *mut i32; /// let z = 12; @@ -255,7 +251,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// } /// ``` #[inline] -#[unstable(feature = "ptr_unaligned", issue = "37955")] +#[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, From 9511fe60ce8c7498958662c2bf2c34da0778120d Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 20:52:20 -0700 Subject: [PATCH 095/662] Stabilize process_abort feature, closes #37838 --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index f846ef3e69e09..97c48ee590341 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1032,7 +1032,7 @@ pub fn exit(code: i32) -> ! { /// will be run. If a clean shutdown is needed it is recommended to only call /// this function at a known point where there are no more destructors left /// to run. -#[unstable(feature = "process_abort", issue = "37838")] +#[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; } From 10510aefb10aaad9e9c382acf973a40938d091ad Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 21:01:18 -0700 Subject: [PATCH 096/662] Stabilize ptr_eq feature, closes #36497 --- src/liballoc/arc.rs | 6 +----- src/liballoc/rc.rs | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 38d843263ffda..b904d818feb39 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -461,17 +461,13 @@ impl Arc { } #[inline] - #[unstable(feature = "ptr_eq", - reason = "newly added", - issue = "36497")] + #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns true if the two `Arc`s point to the same value (not /// just values that compare as equal). /// /// # Examples /// /// ``` - /// #![feature(ptr_eq)] - /// /// use std::sync::Arc; /// /// let five = Arc::new(5); diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index eb449b2660679..a5d1381260bb6 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -551,17 +551,13 @@ impl Rc { } #[inline] - #[unstable(feature = "ptr_eq", - reason = "newly added", - issue = "36497")] + #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns true if the two `Rc`s point to the same value (not /// just values that compare as equal). /// /// # Examples /// /// ``` - /// #![feature(ptr_eq)] - /// /// use std::rc::Rc; /// /// let five = Rc::new(5); From 37b38a2f750c95aa653ced2a33c13c9060129800 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 21:04:54 -0700 Subject: [PATCH 097/662] Stabilize btree_range, closes #27787 --- src/libcollections/btree/map.rs | 12 ++---------- src/libcollections/lib.rs | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 7218d15ded5f8..a746175a5e982 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -724,8 +724,6 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// #![feature(btree_range, collections_bound)] - /// /// use std::collections::BTreeMap; /// use std::collections::Bound::Included; /// @@ -738,9 +736,7 @@ impl BTreeMap { /// } /// assert_eq!(Some((&5, &"b")), map.range(4..).next()); /// ``` - #[unstable(feature = "btree_range", - reason = "matches collection reform specification, waiting for dust to settle", - issue = "27787")] + #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range where T: Ord, K: Borrow, R: RangeArgument { @@ -768,8 +764,6 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// #![feature(btree_range)] - /// /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter() @@ -782,9 +776,7 @@ impl BTreeMap { /// println!("{} => {}", name, balance); /// } /// ``` - #[unstable(feature = "btree_range", - reason = "matches collection reform specification, waiting for dust to settle", - issue = "27787")] + #[stable(feature = "btree_range", since = "1.17.0")] pub fn range_mut(&mut self, range: R) -> RangeMut where T: Ord, K: Borrow, R: RangeArgument { diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index f88bdd0ecf382..a64fffab45c5a 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -129,7 +129,7 @@ mod std { } /// An endpoint of a range of keys. -#[unstable(feature = "collections_bound", issue = "27787")] +#[stable(feature = "collections_bound", since = "1.17.0")] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum Bound { /// An inclusive bound. From 48890d497163bec75d40198b365b3ca670cc3454 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 21:06:29 -0700 Subject: [PATCH 098/662] Stabilize ordering_chaining, closes #37053 --- src/libcore/cmp.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index b43fe757d8473..cb39796eecd7d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -255,8 +255,6 @@ impl Ordering { /// # Examples /// /// ``` - /// #![feature(ordering_chaining)] - /// /// use std::cmp::Ordering; /// /// let result = Ordering::Equal.then(Ordering::Less); @@ -278,7 +276,7 @@ impl Ordering { /// assert_eq!(result, Ordering::Less); /// ``` #[inline] - #[unstable(feature = "ordering_chaining", issue = "37053")] + #[stable(feature = "ordering_chaining", since = "1.17.0")] pub fn then(self, other: Ordering) -> Ordering { match self { Equal => other, @@ -294,8 +292,6 @@ impl Ordering { /// # Examples /// /// ``` - /// #![feature(ordering_chaining)] - /// /// use std::cmp::Ordering; /// /// let result = Ordering::Equal.then_with(|| Ordering::Less); @@ -317,7 +313,7 @@ impl Ordering { /// assert_eq!(result, Ordering::Less); /// ``` #[inline] - #[unstable(feature = "ordering_chaining", issue = "37053")] + #[stable(feature = "ordering_chaining", since = "1.17.0")] pub fn then_with Ordering>(self, f: F) -> Ordering { match self { Equal => f(), From a8f4a1bd984091ffb8f87f9440e2483f94b44a20 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 14 Mar 2017 21:10:02 -0700 Subject: [PATCH 099/662] Stabilize rc_raw feature, closes #37197 --- src/liballoc/arc.rs | 22 ++++++--------- src/liballoc/rc.rs | 22 ++++++--------- src/libcollections/lib.rs | 3 ++ src/libcollections/linked_list.rs | 34 +++++++++++------------ src/libcollections/vec.rs | 4 +-- src/libcollections/vec_deque.rs | 2 +- src/libcore/ptr.rs | 14 ++++++++-- src/librustc_data_structures/array_vec.rs | 3 +- src/librustc_data_structures/lib.rs | 1 - src/libstd/collections/hash/table.rs | 2 +- src/libstd/lib.rs | 1 - 11 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index b904d818feb39..b6191c4d43e8f 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -287,17 +287,15 @@ impl Arc { /// # Examples /// /// ``` - /// #![feature(rc_raw)] - /// /// use std::sync::Arc; /// /// let x = Arc::new(10); /// let x_ptr = Arc::into_raw(x); /// assert_eq!(unsafe { *x_ptr }, 10); /// ``` - #[unstable(feature = "rc_raw", issue = "37197")] - pub fn into_raw(this: Self) -> *mut T { - let ptr = unsafe { &mut (**this.ptr).data as *mut _ }; + #[stable(feature = "rc_raw", since = "1.17.0")] + pub fn into_raw(this: Self) -> *const T { + let ptr = unsafe { &(**this.ptr).data as *const _ }; mem::forget(this); ptr } @@ -315,8 +313,6 @@ impl Arc { /// # Examples /// /// ``` - /// #![feature(rc_raw)] - /// /// use std::sync::Arc; /// /// let x = Arc::new(10); @@ -332,11 +328,11 @@ impl Arc { /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! /// ``` - #[unstable(feature = "rc_raw", issue = "37197")] - pub unsafe fn from_raw(ptr: *mut T) -> Self { + #[stable(feature = "rc_raw", since = "1.17.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the // `data` field from the pointer. - Arc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(ArcInner, data)) as *mut _) } + Arc { ptr: Shared::new((ptr as *const u8).offset(-offset_of!(ArcInner, data)) as *const _) } } } @@ -448,7 +444,7 @@ impl Arc { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { - let ptr = *self.ptr; + let ptr = self.ptr.as_mut_ptr(); // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). @@ -624,7 +620,7 @@ impl Arc { // As with `get_mut()`, the unsafety is ok because our reference was // either unique to begin with, or became one upon cloning the contents. unsafe { - let inner = &mut **this.ptr; + let inner = &mut *this.ptr.as_mut_ptr(); &mut inner.data } } @@ -667,7 +663,7 @@ impl Arc { // the Arc itself to be `mut`, so we're returning the only possible // reference to the inner data. unsafe { - let inner = &mut **this.ptr; + let inner = &mut *this.ptr.as_mut_ptr(); Some(&mut inner.data) } } else { diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index a5d1381260bb6..e9b59017692eb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -364,17 +364,15 @@ impl Rc { /// # Examples /// /// ``` - /// #![feature(rc_raw)] - /// /// use std::rc::Rc; /// /// let x = Rc::new(10); /// let x_ptr = Rc::into_raw(x); /// assert_eq!(unsafe { *x_ptr }, 10); /// ``` - #[unstable(feature = "rc_raw", issue = "37197")] - pub fn into_raw(this: Self) -> *mut T { - let ptr = unsafe { &mut (**this.ptr).value as *mut _ }; + #[stable(feature = "rc_raw", since = "1.17.0")] + pub fn into_raw(this: Self) -> *const T { + let ptr = unsafe { &mut (*this.ptr.as_mut_ptr()).value as *const _ }; mem::forget(this); ptr } @@ -392,8 +390,6 @@ impl Rc { /// # Examples /// /// ``` - /// #![feature(rc_raw)] - /// /// use std::rc::Rc; /// /// let x = Rc::new(10); @@ -409,11 +405,11 @@ impl Rc { /// /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! /// ``` - #[unstable(feature = "rc_raw", issue = "37197")] - pub unsafe fn from_raw(ptr: *mut T) -> Self { + #[stable(feature = "rc_raw", since = "1.17.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { // To find the corresponding pointer to the `RcBox` we need to subtract the offset of the // `value` field from the pointer. - Rc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(RcBox, value)) as *mut _) } + Rc { ptr: Shared::new((ptr as *const u8).offset(-offset_of!(RcBox, value)) as *const _) } } } @@ -543,7 +539,7 @@ impl Rc { #[stable(feature = "rc_unique", since = "1.4.0")] pub fn get_mut(this: &mut Self) -> Option<&mut T> { if Rc::is_unique(this) { - let inner = unsafe { &mut **this.ptr }; + let inner = unsafe { &mut *this.ptr.as_mut_ptr() }; Some(&mut inner.value) } else { None @@ -627,7 +623,7 @@ impl Rc { // reference count is guaranteed to be 1 at this point, and we required // the `Rc` itself to be `mut`, so we're returning the only possible // reference to the inner value. - let inner = unsafe { &mut **this.ptr }; + let inner = unsafe { &mut *this.ptr.as_mut_ptr() }; &mut inner.value } } @@ -673,7 +669,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - let ptr = *self.ptr; + let ptr = self.ptr.as_mut_ptr(); self.dec_strong(); if self.strong() == 0 { diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index a64fffab45c5a..10650dab583c3 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -133,10 +133,13 @@ mod std { #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum Bound { /// An inclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] Included(T), /// An exclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] Excluded(T), /// An infinite endpoint. Indicates that there is no bound in this direction. + #[stable(feature = "collections_bound", since = "1.17.0")] Unbounded, } diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index d4f77d625b361..f58c87b801f55 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -142,7 +142,7 @@ impl LinkedList { match self.head { None => self.tail = node, - Some(head) => (**head).prev = node, + Some(head) => (*head.as_mut_ptr()).prev = node, } self.head = node; @@ -154,12 +154,12 @@ impl LinkedList { #[inline] fn pop_front_node(&mut self) -> Option>> { self.head.map(|node| unsafe { - let node = Box::from_raw(*node); + let node = Box::from_raw(node.as_mut_ptr()); self.head = node.next; match self.head { None => self.tail = None, - Some(head) => (**head).prev = None, + Some(head) => (*head.as_mut_ptr()).prev = None, } self.len -= 1; @@ -177,7 +177,7 @@ impl LinkedList { match self.tail { None => self.head = node, - Some(tail) => (**tail).next = node, + Some(tail) => (*tail.as_mut_ptr()).next = node, } self.tail = node; @@ -189,12 +189,12 @@ impl LinkedList { #[inline] fn pop_back_node(&mut self) -> Option>> { self.tail.map(|node| unsafe { - let node = Box::from_raw(*node); + let node = Box::from_raw(node.as_mut_ptr()); self.tail = node.prev; match self.tail { None => self.head = None, - Some(tail) => (**tail).next = None, + Some(tail) => (*tail.as_mut_ptr()).next = None, } self.len -= 1; @@ -269,8 +269,8 @@ impl LinkedList { Some(tail) => { if let Some(other_head) = other.head.take() { unsafe { - (**tail).next = Some(other_head); - (**other_head).prev = Some(tail); + (*tail.as_mut_ptr()).next = Some(other_head); + (*other_head.as_mut_ptr()).prev = Some(tail); } self.tail = other.tail.take(); @@ -484,7 +484,7 @@ impl LinkedList { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn front_mut(&mut self) -> Option<&mut T> { - self.head.map(|node| unsafe { &mut (**node).element }) + self.head.map(|node| unsafe { &mut (*node.as_mut_ptr()).element }) } /// Provides a reference to the back element, or `None` if the list is @@ -530,7 +530,7 @@ impl LinkedList { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn back_mut(&mut self) -> Option<&mut T> { - self.tail.map(|node| unsafe { &mut (**node).element }) + self.tail.map(|node| unsafe { &mut (*node.as_mut_ptr()).element }) } /// Adds an element first in the list. @@ -675,9 +675,9 @@ impl LinkedList { let second_part_head; unsafe { - second_part_head = (**split_node.unwrap()).next.take(); + second_part_head = (*split_node.unwrap().as_mut_ptr()).next.take(); if let Some(head) = second_part_head { - (**head).prev = None; + (*head.as_mut_ptr()).prev = None; } } @@ -816,7 +816,7 @@ impl<'a, T> Iterator for IterMut<'a, T> { None } else { self.head.map(|node| unsafe { - let node = &mut **node; + let node = &mut *node.as_mut_ptr(); self.len -= 1; self.head = node.next; &mut node.element @@ -838,7 +838,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { None } else { self.tail.map(|node| unsafe { - let node = &mut **node; + let node = &mut *node.as_mut_ptr(); self.len -= 1; self.tail = node.prev; &mut node.element @@ -896,8 +896,8 @@ impl<'a, T> IterMut<'a, T> { element: element, }))); - (**prev).next = node; - (**head).prev = node; + (*prev.as_mut_ptr()).next = node; + (*head.as_mut_ptr()).prev = node; self.list.len += 1; }, @@ -929,7 +929,7 @@ impl<'a, T> IterMut<'a, T> { if self.len == 0 { None } else { - self.head.map(|node| unsafe { &mut (**node).element }) + self.head.map(|node| unsafe { &mut (*node.as_mut_ptr()).element }) } } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a717163f45ef5..7b408af13aa2f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2120,7 +2120,7 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter { for _x in self.by_ref() {} // RawVec handles deallocation - let _ = unsafe { RawVec::from_raw_parts(*self.buf, self.cap) }; + let _ = unsafe { RawVec::from_raw_parts(self.buf.as_mut_ptr(), self.cap) }; } } @@ -2185,7 +2185,7 @@ impl<'a, T> Drop for Drain<'a, T> { if self.tail_len > 0 { unsafe { - let source_vec = &mut **self.vec; + let source_vec = &mut *self.vec.as_mut_ptr(); // memmove back untouched tail, update to new length let start = source_vec.len(); let tail = self.tail_start; diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 1985be7f901c6..6a04d47a345e8 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -2125,7 +2125,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { for _ in self.by_ref() {} - let source_deque = unsafe { &mut **self.deque }; + let source_deque = unsafe { &mut *self.deque.as_mut_ptr() }; // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head // diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index e4ad8cfd25654..15174e72795ac 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -968,11 +968,19 @@ impl Shared { /// # Safety /// /// `ptr` must be non-null. - pub unsafe fn new(ptr: *mut T) -> Self { + pub unsafe fn new(ptr: *const T) -> Self { Shared { pointer: NonZero::new(ptr), _marker: PhantomData } } } +#[unstable(feature = "shared", issue = "27730")] +impl Shared { + /// Acquires the underlying pointer as a `*mut` pointer. + pub unsafe fn as_mut_ptr(&self) -> *mut T { + **self as _ + } +} + #[unstable(feature = "shared", issue = "27730")] impl Clone for Shared { fn clone(&self) -> Self { @@ -988,10 +996,10 @@ impl CoerceUnsized> for Shared where T: Unsiz #[unstable(feature = "shared", issue = "27730")] impl Deref for Shared { - type Target = *mut T; + type Target = *const T; #[inline] - fn deref(&self) -> &*mut T { + fn deref(&self) -> &*const T { unsafe { mem::transmute(&*self.pointer) } } } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 51e6e09ab5003..29fbcb70756ba 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -248,7 +248,7 @@ impl<'a, A: Array> Drop for Drain<'a, A> { if self.tail_len > 0 { unsafe { - let source_array_vec = &mut **self.array_vec; + let source_array_vec = &mut *self.array_vec.as_mut_ptr(); // memmove back untouched tail, update to new length let start = source_array_vec.len(); let tail = self.tail_start; @@ -317,4 +317,3 @@ impl Default for ManuallyDrop { ManuallyDrop::new() } } - diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index f278325ebec74..8ecfd75dc95a9 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -27,7 +27,6 @@ #![feature(shared)] #![feature(collections_range)] -#![feature(collections_bound)] #![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 2c8bb433e8aef..211605bef1ee0 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1154,7 +1154,7 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { fn next(&mut self) -> Option<(SafeHash, K, V)> { self.iter.next().map(|bucket| { unsafe { - (**self.table).size -= 1; + (*self.table.as_mut_ptr()).size -= 1; let (k, v) = ptr::read(bucket.pair); (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2c83518d38880..206a37b8e5db8 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -245,7 +245,6 @@ #![feature(char_escape_debug)] #![feature(char_internals)] #![feature(collections)] -#![feature(collections_bound)] #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] From 1241a88fa9ddf5e645d1e6e93e04c435bbf15cd4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Mar 2017 07:58:27 -0700 Subject: [PATCH 100/662] Minor fixups to fix tidy errors --- src/liballoc/arc.rs | 5 ++++- src/libcollections/btree/map.rs | 2 ++ src/libcollections/btree/set.rs | 7 ++----- src/libcollections/range.rs | 2 -- src/libcollectionstest/lib.rs | 2 -- src/libcore/ptr.rs | 3 +-- src/libcoretest/lib.rs | 4 ---- 7 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index b6191c4d43e8f..1d616233881b4 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -332,7 +332,10 @@ impl Arc { pub unsafe fn from_raw(ptr: *const T) -> Self { // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the // `data` field from the pointer. - Arc { ptr: Shared::new((ptr as *const u8).offset(-offset_of!(ArcInner, data)) as *const _) } + let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner, data)); + Arc { + ptr: Shared::new(ptr as *const _), + } } } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index a746175a5e982..53fe6b4bc9f4f 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -338,6 +338,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { } /// An iterator over a sub-range of BTreeMap's entries. +#[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, back: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -351,6 +352,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> } /// A mutable iterator over a sub-range of BTreeMap's entries. +#[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, back: Handle, K, V, marker::Leaf>, marker::Edge>, diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index e3c990c80decf..72d25f87bca95 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -113,6 +113,7 @@ pub struct IntoIter { /// [`BTreeSet`]: struct.BTreeSet.html /// [`range`]: struct.BTreeSet.html#method.range #[derive(Debug)] +#[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, T: 'a> { iter: ::btree_map::Range<'a, T, ()>, } @@ -264,8 +265,6 @@ impl BTreeSet { /// # Examples /// /// ``` - /// #![feature(btree_range, collections_bound)] - /// /// use std::collections::BTreeSet; /// use std::collections::Bound::Included; /// @@ -278,9 +277,7 @@ impl BTreeSet { /// } /// assert_eq!(Some(&5), set.range(4..).next()); /// ``` - #[unstable(feature = "btree_range", - reason = "matches collection reform specification, waiting for dust to settle", - issue = "27787")] + #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range where K: Ord, T: Borrow, R: RangeArgument { diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index e4b94a1d70ee4..31e4d001397bf 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -29,7 +29,6 @@ pub trait RangeArgument { /// ``` /// #![feature(collections)] /// #![feature(collections_range)] - /// #![feature(collections_bound)] /// /// extern crate collections; /// @@ -52,7 +51,6 @@ pub trait RangeArgument { /// ``` /// #![feature(collections)] /// #![feature(collections_range)] - /// #![feature(collections_bound)] /// /// extern crate collections; /// diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 98d0b1c8e1565..618eb386c0f4c 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -13,11 +13,9 @@ #![feature(binary_heap_extras)] #![feature(binary_heap_peek_mut_pop)] #![feature(box_syntax)] -#![feature(btree_range)] #![feature(inclusive_range_syntax)] #![feature(collection_placement)] #![feature(collections)] -#![feature(collections_bound)] #![feature(const_fn)] #![feature(exact_size_is_empty)] #![feature(pattern)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 15174e72795ac..909e44df20abb 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -658,7 +658,6 @@ impl Eq for *mut T {} /// # Examples /// /// ``` -/// #![feature(ptr_eq)] /// use std::ptr; /// /// let five = 5; @@ -673,7 +672,7 @@ impl Eq for *mut T {} /// assert!(ptr::eq(five_ref, same_five_ref)); /// assert!(!ptr::eq(five_ref, other_five_ref)); /// ``` -#[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")] +#[stable(feature = "ptr_eq", since = "1.17.0")] #[inline] pub fn eq(a: *const T, b: *const T) -> bool { a == b diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index e06b757691e5a..d84a1e227560e 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -23,7 +23,6 @@ #![feature(nonzero)] #![feature(rand)] #![feature(raw)] -#![feature(result_expect_err)] #![feature(sip_hash_13)] #![feature(slice_patterns)] #![feature(step_by)] @@ -31,9 +30,6 @@ #![feature(try_from)] #![feature(unicode)] #![feature(unique)] -#![feature(ordering_chaining)] -#![feature(ptr_unaligned)] -#![feature(move_cell)] #![feature(fmt_internals)] extern crate core; From cb96adea15f15b13adca6f13b285a4fff33f5be3 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 20:39:41 +0000 Subject: [PATCH 101/662] Fix regression when `include!()`ing a `macro_rules!` containing a `$crate::` path. --- src/librustc_resolve/build_reduced_graph.rs | 5 ++++- src/test/run-pass/auxiliary/issue_40469.rs | 11 +++++++++++ src/test/run-pass/issue-40469.rs | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/auxiliary/issue_40469.rs create mode 100644 src/test/run-pass/issue-40469.rs diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 03c61067d64c2..be905a9d0f94a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -23,7 +23,7 @@ use {resolve_error, resolve_struct_error, ResolutionError}; use rustc::middle::cstore::LoadedMacro; use rustc::hir::def::*; -use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefId}; use rustc::ty; use std::cell::Cell; @@ -496,6 +496,9 @@ impl<'a> Resolver<'a> { let def_id = self.macro_defs[&expansion]; if let Some(id) = self.definitions.as_local_node_id(def_id) { self.local_macro_def_scopes[&id] + } else if def_id.krate == BUILTIN_MACROS_CRATE { + // FIXME(jseyfried): This happens when `include!()`ing a `$crate::` path, c.f, #40469. + self.graph_root } else { let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); self.get_extern_crate_root(module_def_id.krate) diff --git a/src/test/run-pass/auxiliary/issue_40469.rs b/src/test/run-pass/auxiliary/issue_40469.rs new file mode 100644 index 0000000000000..4970bba431a84 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_40469.rs @@ -0,0 +1,11 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { () => { $crate::main(); } } diff --git a/src/test/run-pass/issue-40469.rs b/src/test/run-pass/issue-40469.rs new file mode 100644 index 0000000000000..30055e532cd45 --- /dev/null +++ b/src/test/run-pass/issue-40469.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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 issue #37195 + +#![allow(dead_code)] + +include!("auxiliary/issue_40469.rs"); +fn f() { m!(); } + +fn main() {} From 2976ddbb1522397e3a9d91aa5ed9ae8e5cdbf97a Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 17 Mar 2017 17:15:01 -0700 Subject: [PATCH 102/662] Fix a spelling error in HashMap documentation, and slightly reword it to be more precise. --- src/libstd/collections/hash/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 3ca8b41347a26..5733217008146 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -222,8 +222,8 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// resistance against HashDoS attacks. The algorithm is randomly seeded, and a /// reasonable best-effort is made to generate this seed from a high quality, /// secure source of randomness provided by the host without blocking the -/// program. Because of this, the randomness of the seed is dependant on the -/// quality of the system's random number generator at the time it is created. +/// program. Because of this, the randomness of the seed depends on the output +/// quality of the system's random number generator when the seed is created. /// In particular, seeds generated when the system's entropy pool is abnormally /// low such as during system boot may be of a lower quality. /// From 0af3775dd2c93cdaf8902f83eb21037e474e058f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 7 Feb 2017 22:46:21 +0100 Subject: [PATCH 103/662] translate tuple-variant constructors using MIR --- src/librustc/ty/mod.rs | 13 +++- src/librustc_metadata/encoder.rs | 4 +- src/librustc_mir/lib.rs | 2 + src/librustc_mir/mir_map.rs | 63 ++++++++++++++++++ src/librustc_mir/shim.rs | 109 +++++++++++++++++++++++++++++++ src/librustc_trans/base.rs | 78 ++-------------------- src/librustc_trans/callee.rs | 33 ---------- src/librustc_trans/collector.rs | 19 ++---- src/librustc_trans/common.rs | 10 ++- src/librustc_trans/mir/block.rs | 6 +- src/librustc_trans/trans_item.rs | 16 +++-- 11 files changed, 215 insertions(+), 138 deletions(-) create mode 100644 src/librustc_mir/shim.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3c37c7353d683..360fa24bf3687 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1264,10 +1264,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { def_id, ROOT_CODE_EXTENT) } - _ => { + Some(hir_map::NodeStructCtor(..)) | + Some(hir_map::NodeVariant(..)) => { + let def_id = tcx.hir.local_def_id(id); + tcx.construct_parameter_environment(tcx.hir.span(id), + def_id, + ROOT_CODE_EXTENT) + } + it => { bug!("ParameterEnvironment::from_item(): \ - `{}` is not an item", - tcx.hir.node_to_string(id)) + `{}` = {:?} is unsupported", + tcx.hir.node_to_string(id), it) } } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0c31e30671dc2..044ed529ef74c 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -293,7 +293,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None, + mir: self.encode_mir(def_id), } } @@ -426,7 +426,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None, + mir: self.encode_mir(def_id), } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f21f1881c832e..19028bfa531be 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] +#![feature(box_syntax)] #![feature(i128_type)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -50,6 +51,7 @@ pub mod callgraph; pub mod def_use; pub mod graphviz; mod hair; +mod shim; pub mod mir_map; pub mod pretty; pub mod transform; diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 58f23a5c81bd7..3fa7131a2b6b0 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -22,6 +22,7 @@ use rustc::dep_graph::DepNode; use rustc::mir::Mir; use rustc::mir::transform::MirSource; use rustc::mir::visit::MutVisitor; +use shim; use pretty; use hair::cx::Cx; @@ -30,6 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::subst::Substs; use rustc::hir; +use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; @@ -44,6 +46,31 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { tcx.item_mir(body_owner_def_id); }); + + // Tuple struct/variant constructors don't have a BodyId, so we need + // to build them separately. + struct GatherCtors<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx> + } + impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> { + fn visit_variant_data(&mut self, + v: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _: ast::NodeId, + _: Span) { + if let hir::VariantData::Tuple(_, node_id) = *v { + self.tcx.item_mir(self.tcx.hir.local_def_id(node_id)); + } + intravisit::walk_struct_def(self, v) + } + fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> { + NestedVisitorMap::None + } + } + tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut GatherCtors { + tcx: tcx + }.as_deep_visitor()); } } @@ -95,6 +122,10 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) _ => hir::BodyId { node_id: expr.id } } } + hir::map::NodeVariant(variant) => + return create_constructor_shim(tcx, id, &variant.node.data), + hir::map::NodeStructCtor(ctor) => + return create_constructor_shim(tcx, id, ctor), _ => unsupported() }; @@ -180,6 +211,38 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { } } +fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ctor_id: ast::NodeId, + v: &'tcx hir::VariantData) + -> &'tcx RefCell> +{ + let span = tcx.hir.span(ctor_id); + if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { + let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id); + tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| { + let (mut mir, src) = + shim::build_adt_ctor(&infcx, ctor_id, fields, span); + + // Convert the Mir to global types. + let tcx = infcx.tcx.global_tcx(); + let mut globalizer = GlobalizeMir { + tcx: tcx, + span: mir.span + }; + globalizer.visit_mir(&mut mir); + let mir = unsafe { + mem::transmute::>(mir) + }; + + pretty::dump_mir(tcx, "mir_map", &0, src, &mir); + + tcx.alloc_mir(mir) + }) + } else { + span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v); + } +} + /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs new file mode 100644 index 0000000000000..3705a317715f4 --- /dev/null +++ b/src/librustc_mir/shim.rs @@ -0,0 +1,109 @@ +// 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. + +use rustc::hir; +use rustc::infer; +use rustc::mir::*; +use rustc::mir::transform::MirSource; +use rustc::ty; + +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; + +use syntax::ast; +use syntax_pos::Span; + +use std::iter; + +fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) + -> IndexVec> +{ + iter::once(LocalDecl { + mutability: Mutability::Mut, + ty: sig.output(), + name: None, + source_info: None + }).chain(sig.inputs().iter().map(|ity| LocalDecl { + mutability: Mutability::Not, + ty: *ity, + name: None, + source_info: None, + })).collect() +} + +pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, + ctor_id: ast::NodeId, + fields: &[hir::StructField], + span: Span) + -> (Mir<'tcx>, MirSource) +{ + let tcx = infcx.tcx; + let def_id = tcx.hir.local_def_id(ctor_id); + let sig = match tcx.item_type(def_id).sty { + ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty) + .expect("LBR in ADT constructor signature"), + _ => bug!("unexpected type for ctor {:?}", def_id) + }; + let sig = tcx.erase_regions(&sig); + + let (adt_def, substs) = match sig.output().sty { + ty::TyAdt(adt_def, substs) => (adt_def, substs), + _ => bug!("unexpected type for ADT ctor {:?}", sig.output()) + }; + + debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields); + + let local_decls = local_decls_for_sig(&sig); + + let source_info = SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }; + + let variant_no = if adt_def.is_enum() { + adt_def.variant_index_with_id(def_id) + } else { + 0 + }; + + // return = ADT(arg0, arg1, ...); return + let start_block = BasicBlockData { + statements: vec![Statement { + source_info: source_info, + kind: StatementKind::Assign( + Lvalue::Local(RETURN_POINTER), + Rvalue::Aggregate( + AggregateKind::Adt(adt_def, variant_no, substs, None), + (1..sig.inputs().len()+1).map(|i| { + Operand::Consume(Lvalue::Local(Local::new(i))) + }).collect() + ) + ) + }], + terminator: Some(Terminator { + source_info: source_info, + kind: TerminatorKind::Return, + }), + is_cleanup: false + }; + + let mir = Mir::new( + IndexVec::from_elem_n(start_block, 1), + IndexVec::from_elem_n( + VisibilityScopeData { span: span, parent_scope: None }, 1 + ), + IndexVec::new(), + sig.output(), + local_decls, + sig.inputs().len(), + vec![], + span + ); + (mir, MirSource::Fn(ctor_id)) +} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1b43491e73c8f..fe2b21895cce6 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -34,10 +34,8 @@ use back::linker::LinkerInfo; use back::symbol_export::{self, ExportedSymbols}; use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; -use rustc::ty::subst::Substs; -use rustc::mir::tcx::LvalueTy; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; @@ -47,9 +45,8 @@ use rustc::util::common::time; use session::config::{self, NoDebugInfo}; use rustc_incremental::IncrementalHashesMap; use session::{self, DataTypeKind, Session}; -use abi::{self, FnType}; +use abi; use mir::lvalue::LvalueRef; -use adt; use attributes; use builder::Builder; use callee::{Callee}; @@ -65,7 +62,7 @@ use context::{SharedCrateContext, CrateContextList}; use debuginfo; use declare; use machine; -use machine::{llalign_of_min, llsize_of}; +use machine::llsize_of; use meth; use mir; use monomorphize::{self, Instance}; @@ -76,7 +73,6 @@ use trans_item::{TransItem, DefPathBasedNames}; use type_::Type; use type_of; use value::Value; -use Disr; use util::nodemap::{NodeSet, FxHashMap, FxHashSet}; use libc::c_uint; @@ -615,72 +611,6 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance mir::trans_mir(ccx, lldecl, &mir, instance, sig); } -pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - disr: Disr, - llfn: ValueRef) { - attributes::inline(llfn, attributes::InlineAttr::Hint); - attributes::set_frame_pointer_elimination(ccx, llfn); - - let ctor_ty = common::def_ty(ccx.shared(), def_id, substs); - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig()); - let fn_ty = FnType::new(ccx, sig, &[]); - - let bcx = Builder::new_block(ccx, llfn, "entry-block"); - if !fn_ty.ret.is_ignore() { - // But if there are no nested returns, we skip the indirection - // and have a single retslot - let dest = if fn_ty.ret.is_indirect() { - get_param(llfn, 0) - } else { - // We create an alloca to hold a pointer of type `ret.original_ty` - // which will hold the pointer to the right alloca which has the - // final ret value - bcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot") - }; - // Can return unsized value - let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output(), Alignment::AbiAligned); - dest_val.ty = LvalueTy::Downcast { - adt_def: sig.output().ty_adt_def().unwrap(), - substs: substs, - variant_index: disr.0 as usize, - }; - let mut llarg_idx = fn_ty.ret.is_indirect() as usize; - let mut arg_idx = 0; - for (i, arg_ty) in sig.inputs().iter().enumerate() { - let (lldestptr, _) = dest_val.trans_field_ptr(&bcx, i); - let arg = &fn_ty.args[arg_idx]; - arg_idx += 1; - if common::type_is_fat_ptr(bcx.ccx, arg_ty) { - let meta = &fn_ty.args[arg_idx]; - arg_idx += 1; - arg.store_fn_arg(&bcx, &mut llarg_idx, get_dataptr(&bcx, lldestptr)); - meta.store_fn_arg(&bcx, &mut llarg_idx, get_meta(&bcx, lldestptr)); - } else { - arg.store_fn_arg(&bcx, &mut llarg_idx, lldestptr); - } - } - adt::trans_set_discr(&bcx, sig.output(), dest, disr); - - if fn_ty.ret.is_indirect() { - bcx.ret_void(); - return; - } - - if let Some(cast_ty) = fn_ty.ret.cast { - bcx.ret(bcx.load( - bcx.pointercast(dest, cast_ty.ptr_to()), - Some(llalign_of_min(ccx, fn_ty.ret.ty)) - )); - } else { - bcx.ret(bcx.load(dest, None)) - } - } else { - bcx.ret_void(); - } -} - pub fn llvm_linkage_by_name(name: &str) -> Option { // Use the names from src/llvm/docs/LangRef.rst here. Most types are only // applicable to variable declarations and may not really make sense for @@ -721,7 +651,7 @@ pub fn set_link_section(ccx: &CrateContext, } /// Create the `main` function which will initialise the rust runtime and call -/// users’ main function. +/// users main function. pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { let (main_def_id, span) = match *ccx.sess().entry_fn.borrow() { Some((id, span)) => { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 762aaf1ce1d1b..a5b42a973cf27 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -22,7 +22,6 @@ use rustc::ty::subst::{Substs, Subst}; use rustc::traits; use abi::{Abi, FnType}; use attributes; -use base; use builder::Builder; use common::{self, CrateContext}; use cleanup::CleanupScope; @@ -35,7 +34,6 @@ use meth; use monomorphize::Instance; use trans_item::TransItem; use type_of; -use Disr; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::hir; use std::iter; @@ -46,9 +44,6 @@ use mir::lvalue::Alignment; #[derive(Debug)] pub enum CalleeData { - /// Constructor for enum variant/tuple-like-struct. - NamedTupleConstructor(Disr), - /// Function pointer. Fn(ValueRef), @@ -92,16 +87,6 @@ impl<'tcx> Callee<'tcx> { } } - // FIXME(eddyb) Detect ADT constructors more efficiently. - if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() { - if let Some(i) = adt_def.variants.iter().position(|v| def_id == v.did) { - return Callee { - data: NamedTupleConstructor(Disr::for_variant(tcx, adt_def, i)), - ty: fn_ty - }; - } - } - let (llfn, ty) = get_fn(ccx, def_id, substs); Callee::ptr(llfn, ty) } @@ -185,24 +170,6 @@ impl<'tcx> Callee<'tcx> { match self.data { Fn(llfn) => llfn, Virtual(_) => meth::trans_object_shim(ccx, self), - NamedTupleConstructor(disr) => match self.ty.sty { - ty::TyFnDef(def_id, substs, _) => { - let instance = Instance::new(def_id, substs); - if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - return llfn; - } - - let sym = ccx.symbol_map().get_or_compute(ccx.shared(), - TransItem::Fn(instance)); - assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance))); - let lldecl = declare::define_internal_fn(ccx, &sym, self.ty); - base::trans_ctor_shim(ccx, def_id, substs, disr, lldecl); - ccx.instances().borrow_mut().insert(instance, lldecl); - - lldecl - } - _ => bug!("expected fn item type, found {}", self.ty) - }, Intrinsic => bug!("intrinsic {} getting reified", self.ty) } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 8d1db38999c6b..5e6b10f826ce0 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -630,14 +630,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { -> bool { match tcx.item_type(def_id).sty { ty::TyFnDef(def_id, _, _) => { - // Some constructors also have type TyFnDef but they are - // always instantiated inline and don't result in a - // translation item. Same for FFI functions. + // foreign items are linked from another library, not + // translated locally. if let Some(hir_map::NodeForeignItem(_)) = tcx.hir.get_if_local(def_id) { return false; } } - ty::TyClosure(..) => {} + ty::TyClosure(..) => { + // TODO: trans items for closures + } _ => return false } @@ -697,16 +698,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - if let ty::TyFnDef(_, _, sig) = tcx.item_type(def_id).sty { - if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() { - if adt_def.variants.iter().any(|v| def_id == v.did) { - // HACK: ADT constructors are translated in-place and - // do not have a trans-item. - return false; - } - } - } - if def_id.is_local() { true } else { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index a509587f80fd0..0e536d58a56fb 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -37,6 +37,7 @@ use libc::{c_uint, c_char}; use std::iter; use syntax::ast; +use syntax::attr; use syntax::symbol::InternedString; use syntax_pos::Span; @@ -601,8 +602,13 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -pub fn is_closure(tcx: TyCtxt, def_id: DefId) -> bool { - tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr +pub fn requests_inline(tcx: TyCtxt, def_id: DefId) -> bool { + match tcx.def_key(def_id).disambiguated_data.data { + DefPathData::StructCtor | + DefPathData::EnumVariant(..) | + DefPathData::ClosureExpr => true, + _ => attr::requests_inline(&tcx.get_attrs(def_id)[..]), + } } /// Given a DefId and some Substs, produces the monomorphic item type. diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 9d40419d338b8..2f1a2c9134c39 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -16,7 +16,7 @@ use rustc::ty::{self, layout, TypeFoldable}; use rustc::mir; use abi::{Abi, FnType, ArgType}; use base::{self, Lifetime}; -use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual}; +use callee::{Callee, CalleeData, Fn, Intrinsic, Virtual}; use builder::Builder; use common::{self, Funclet}; use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef}; @@ -491,10 +491,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } let fn_ptr = match callee.data { - NamedTupleConstructor(_) => { - // FIXME translate this like mir::Rvalue::Aggregate. - callee.reify(bcx.ccx) - } Intrinsic => { use intrinsic::trans_intrinsic_call; diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index d19f04b9554fb..5ec9c2a59957d 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -26,6 +26,7 @@ use monomorphize::Instance; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::hir::map::definitions::DefPathData; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; use rustc_const_eval::fatal_const_eval_err; @@ -178,9 +179,14 @@ impl<'a, 'tcx> TransItem<'tcx> { llvm::SetUniqueComdat(ccx.llmod(), lldecl); } - if let ty::TyClosure(..) = mono_ty.sty { - // set an inline hint for all closures - attributes::inline(lldecl, attributes::InlineAttr::Hint); + debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); + match ccx.tcx().def_key(instance.def).disambiguated_data.data { + DefPathData::StructCtor | + DefPathData::EnumVariant(..) | + DefPathData::ClosureExpr => { + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + _ => {} } attributes::from_fn_attrs(ccx, &attrs, lldecl); @@ -252,8 +258,8 @@ impl<'a, 'tcx> TransItem<'tcx> { match *self { TransItem::Fn(ref instance) => { if self.explicit_linkage(tcx).is_none() && - (common::is_closure(tcx, instance.def) || - attr::requests_inline(&tcx.get_attrs(instance.def)[..])) { + common::requests_inline(tcx, instance.def) + { InstantiationMode::LocalCopy } else { InstantiationMode::GloballyShared From ffee9566bbd7728e6411e6094105d6905373255d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Feb 2017 18:31:03 +0100 Subject: [PATCH 104/662] move Instance to rustc and use it in the collector --- src/librustc/dep_graph/dep_node.rs | 5 + src/librustc/ty/instance.rs | 105 ++++++++ src/librustc/ty/maps.rs | 45 +++- src/librustc/ty/mod.rs | 13 + src/librustc/ty/util.rs | 12 + src/librustc_mir/lib.rs | 1 + src/librustc_mir/shim.rs | 17 ++ src/librustc_trans/back/symbol_export.rs | 7 +- src/librustc_trans/back/symbol_names.rs | 160 ++++++------ src/librustc_trans/base.rs | 18 +- src/librustc_trans/callee.rs | 46 ++-- src/librustc_trans/collector.rs | 300 +++++++++-------------- src/librustc_trans/common.rs | 30 ++- src/librustc_trans/consts.rs | 13 +- src/librustc_trans/context.rs | 12 +- src/librustc_trans/debuginfo/mod.rs | 16 +- src/librustc_trans/meth.rs | 3 +- src/librustc_trans/mir/constant.rs | 30 ++- src/librustc_trans/mir/rvalue.rs | 4 +- src/librustc_trans/monomorphize.rs | 59 ++--- src/librustc_trans/partitioning.rs | 20 +- src/librustc_trans/symbol_map.rs | 2 +- src/librustc_trans/symbol_names_test.rs | 6 +- src/librustc_trans/trans_item.rs | 30 +-- 24 files changed, 522 insertions(+), 432 deletions(-) create mode 100644 src/librustc/ty/instance.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 254cae61152b9..399af258e9251 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -89,6 +89,7 @@ pub enum DepNode { // things read/modify that MIR. MirKrate, Mir(D), + MirShim(Vec), BorrowCheckKrate, BorrowCheck(D), @@ -258,6 +259,10 @@ impl DepNode { IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck), MatchCheck(ref d) => op(d).map(MatchCheck), Mir(ref d) => op(d).map(Mir), + MirShim(ref def_ids) => { + let def_ids: Option> = def_ids.iter().map(op).collect(); + def_ids.map(MirShim) + } BorrowCheck(ref d) => op(d).map(BorrowCheck), RvalueCheck(ref d) => op(d).map(RvalueCheck), StabilityCheck(ref d) => op(d).map(StabilityCheck), diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs new file mode 100644 index 0000000000000..fdcfb3ebd3ce5 --- /dev/null +++ b/src/librustc/ty/instance.rs @@ -0,0 +1,105 @@ +// 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. + +use dep_graph::DepNode; +use hir::def_id::DefId; +use ty::{self, Ty, TypeFoldable, Substs}; +use util::ppaux; + +use std::borrow::Cow; +use std::fmt; +use syntax::ast; + + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Instance<'tcx> { + pub def: InstanceDef<'tcx>, + pub substs: &'tcx Substs<'tcx>, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum InstanceDef<'tcx> { + Item(DefId), + // ::call_* + FnPtrShim(DefId, Ty<'tcx>), +} + +impl<'tcx> InstanceDef<'tcx> { + #[inline] + pub fn def_id(&self) -> DefId { + match *self { + InstanceDef::Item(def_id) | + InstanceDef::FnPtrShim(def_id, _) + => def_id + } + } + + #[inline] + pub fn def_ty<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + tcx.item_type(self.def_id()) + } + + #[inline] + pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> { + tcx.get_attrs(self.def_id()) + } + + pub(crate) fn dep_node(&self) -> DepNode { + // HACK: def-id binning, project-style; someone replace this with + // real on-demand. + let ty = match self { + &InstanceDef::FnPtrShim(_, ty) => Some(ty), + _ => None + }.into_iter(); + + DepNode::MirShim( + Some(self.def_id()).into_iter().chain( + ty.flat_map(|t| t.walk()).flat_map(|t| match t.sty { + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, + }) + ).collect() + ) + } +} + +impl<'tcx> fmt::Display for Instance<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.def { + InstanceDef::Item(def) => { + ppaux::parameterized(f, self.substs, def, &[]) + } + InstanceDef::FnPtrShim(def, ty) => { + ppaux::parameterized(f, self.substs, def, &[])?; + write!(f, " - shim({:?})", ty) + } + } + } +} + +impl<'a, 'b, 'tcx> Instance<'tcx> { + pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) + -> Instance<'tcx> { + assert!(substs.is_normalized_for_trans() && !substs.has_escaping_regions(), + "substs of instance {:?} not normalized for trans: {:?}", + def_id, substs); + Instance { def: InstanceDef::Item(def_id), substs: substs } + } + + pub fn mono(tcx: ty::TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> { + Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id)) + } + + #[inline] + pub fn def_id(&self) -> DefId { + self.def.def_id() + } +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index af05c0c43113b..ac8c38c7d5856 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; -use hir::def_id::{CrateNum, DefId}; +use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use middle::const_val::ConstVal; use mir; use ty::{self, Ty, TyCtxt}; @@ -24,6 +24,16 @@ trait Key { fn default_span(&self, tcx: TyCtxt) -> Span; } +impl<'tcx> Key for ty::InstanceDef<'tcx> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + impl Key for CrateNum { fn map_crate(&self) -> CrateNum { *self @@ -83,9 +93,9 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { } } -pub struct CycleError<'a> { +pub struct CycleError<'a, 'tcx: 'a> { span: Span, - cycle: RefMut<'a, [(Span, Query)]>, + cycle: RefMut<'a, [(Span, Query<'tcx>)]>, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -110,8 +120,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { err.emit(); } - fn cycle_check(self, span: Span, query: Query, compute: F) - -> Result> + fn cycle_check(self, span: Span, query: Query<'gcx>, compute: F) + -> Result> where F: FnOnce() -> R { { @@ -172,13 +182,20 @@ impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> { } } +impl<'tcx> QueryDescription for queries::mir_shims<'tcx> { + fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { + format!("generating MIR shim for `{}`", + tcx.item_path_str(def.def_id())) + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => { pub struct Maps<$tcx> { providers: IndexVec>, - query_stack: RefCell>, + query_stack: RefCell)>>, $($(#[$attr])* pub $name: RefCell>>),* } @@ -196,11 +213,11 @@ macro_rules! define_maps { #[allow(bad_style)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] - pub enum Query { + pub enum Query<$tcx> { $($(#[$attr])* $name($K)),* } - impl Query { + impl<$tcx> Query<$tcx> { pub fn describe(&self, tcx: TyCtxt) -> String { match *self { $(Query::$name(key) => queries::$name::describe(tcx, key)),* @@ -233,7 +250,7 @@ macro_rules! define_maps { mut span: Span, key: $K, f: F) - -> Result> + -> Result> where F: FnOnce(&$V) -> R { if let Some(result) = tcx.maps.$name.borrow().get(&key) { @@ -256,7 +273,7 @@ macro_rules! define_maps { } pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) - -> Result<$V, CycleError<'a>> { + -> Result<$V, CycleError<'a, $tcx>> { Self::try_get_with(tcx, span, key, Clone::clone) } @@ -387,7 +404,9 @@ define_maps! { <'tcx> /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()> + pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()>, + + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { @@ -397,3 +416,7 @@ fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } + +fn mir_shim(instance: ty::InstanceDef) -> DepNode { + instance.dep_node() +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 360fa24bf3687..c4192ffc697ce 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -73,6 +73,8 @@ pub use self::contents::TypeContents; pub use self::context::{TyCtxt, GlobalArenas, tls}; pub use self::context::{Lift, TypeckTables}; +pub use self::instance::{Instance, InstanceDef}; + pub use self::trait_def::{TraitDef, TraitFlags}; pub use self::maps::queries; @@ -98,6 +100,7 @@ pub mod util; mod contents; mod context; mod flags; +mod instance; mod structural_impls; mod sty; @@ -2309,6 +2312,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::mir::get(self, DUMMY_SP, did).borrow() } + /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. + pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>) + -> Ref<'gcx, Mir<'gcx>> + { + match instance { + ty::InstanceDef::Item(did) if true => self.item_mir(did), + _ => queries::mir_shims::get(self, DUMMY_SP, instance).borrow(), + } + } + /// Given the DefId of an item, returns its MIR, borrowed immutably. /// Returns None if there is no MIR for the DefId pub fn maybe_item_mir(self, did: DefId) -> Option>> { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd95724990941..2344305fa9a7e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -398,6 +398,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } def_id } + + /// Given the def-id of some item that has no type parameters, make + /// a suitable "empty substs" for it. + pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { + ty::Substs::for_item(self, item_def_id, + |_, _| self.mk_region(ty::ReErased), + |_, _| { + bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) + }) + } + + } pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> { diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 19028bfa531be..9e6b77dbabdef 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -60,5 +60,6 @@ use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { mir_map::provide(providers); + shim::provide(providers); transform::qualify_consts::provide(providers); } \ No newline at end of file diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 3705a317715f4..0fbd488ffa360 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -13,14 +13,31 @@ use rustc::infer; use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::ty; +use rustc::ty::maps::Providers; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use syntax::ast; use syntax_pos::Span; +use std::cell::RefCell; use std::iter; +pub fn provide(providers: &mut Providers) { + providers.mir_shims = make_shim; +} + +fn make_shim<'a, 'tcx>(_tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + instance: ty::InstanceDef<'tcx>) + -> &'tcx RefCell> +{ + match instance { + ty::InstanceDef::Item(..) => + bug!("item {:?} passed to make_shim", instance), + ty::InstanceDef::FnPtrShim(..) => unimplemented!() + } +} + fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) -> IndexVec> { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index bea3ca8df70e0..005fb3533ab0b 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -11,6 +11,7 @@ use context::SharedCrateContext; use monomorphize::Instance; use symbol_map::SymbolMap; +use back::symbol_names::symbol_name; use util::nodemap::FxHashMap; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::session::config; @@ -106,7 +107,7 @@ impl ExportedSymbols { .exported_symbols(cnum) .iter() .map(|&def_id| { - let name = Instance::mono(scx, def_id).symbol_name(scx); + let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx); let export_level = if special_runtime_crate { // We can probably do better here by just ensuring that // it has hidden visibility rather than public @@ -218,9 +219,9 @@ fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } - let instance = Instance::mono(scx, def_id); + let instance = Instance::mono(scx.tcx(), def_id); symbol_map.get(TransItem::Fn(instance)) .map(str::to_owned) - .unwrap_or_else(|| instance.symbol_name(scx)) + .unwrap_or_else(|| symbol_name(instance, scx)) } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index fe58bc8f5f28b..518995dfedcc2 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -168,105 +168,105 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, format!("h{:016x}", hasher.finish()) } -impl<'a, 'tcx> Instance<'tcx> { - pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String { - let Instance { def: def_id, substs } = self; +pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, + scx: &SharedCrateContext<'a, 'tcx>) -> String { + let def_id = instance.def_id(); + let substs = instance.substs; - debug!("symbol_name(def_id={:?}, substs={:?})", - def_id, substs); + debug!("symbol_name(def_id={:?}, substs={:?})", + def_id, substs); - let node_id = scx.tcx().hir.as_local_node_id(def_id); + let node_id = scx.tcx().hir.as_local_node_id(def_id); - if let Some(id) = node_id { - if scx.sess().plugin_registrar_fn.get() == Some(id) { - let svh = &scx.link_meta().crate_hash; - let idx = def_id.index; - return scx.sess().generate_plugin_registrar_symbol(svh, idx); - } - if scx.sess().derive_registrar_fn.get() == Some(id) { - let svh = &scx.link_meta().crate_hash; - let idx = def_id.index; - return scx.sess().generate_derive_registrar_symbol(svh, idx); - } + if let Some(id) = node_id { + if scx.sess().plugin_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = def_id.index; + return scx.sess().generate_plugin_registrar_symbol(svh, idx); } - - // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let attrs = scx.tcx().get_attrs(def_id); - let is_foreign = if let Some(id) = node_id { - match scx.tcx().hir.get(id) { - hir_map::NodeForeignItem(_) => true, - _ => false - } - } else { - scx.sess().cstore.is_foreign_item(def_id) - }; - - if let Some(name) = weak_lang_items::link_name(&attrs) { - return name.to_string(); + if scx.sess().derive_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = def_id.index; + return scx.sess().generate_derive_registrar_symbol(svh, idx); } + } - if is_foreign { - if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") { - return name.to_string(); - } - // Don't mangle foreign items. - return scx.tcx().item_name(def_id).as_str().to_string(); + // FIXME(eddyb) Precompute a custom symbol name based on attributes. + let attrs = scx.tcx().get_attrs(def_id); + let is_foreign = if let Some(id) = node_id { + match scx.tcx().hir.get(id) { + hir_map::NodeForeignItem(_) => true, + _ => false } + } else { + scx.sess().cstore.is_foreign_item(def_id) + }; - if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { - // Use provided name + if let Some(name) = weak_lang_items::link_name(&attrs) { + return name.to_string(); + } + + if is_foreign { + if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") { return name.to_string(); } + // Don't mangle foreign items. + return scx.tcx().item_name(def_id).as_str().to_string(); + } - if attr::contains_name(&attrs, "no_mangle") { - // Don't mangle - return scx.tcx().item_name(def_id).as_str().to_string(); - } + if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { + // Use provided name + return name.to_string(); + } - let def_path = scx.tcx().def_path(def_id); - - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = scx.tcx().def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | - DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().item_type(ty_def_id); - break; - } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!("finding type for {:?}, encountered def-id {:?} with no \ - parent", def_id, ty_def_id); - }); - } + if attr::contains_name(&attrs, "no_mangle") { + // Don't mangle + return scx.tcx().item_name(def_id).as_str().to_string(); + } + + let def_path = scx.tcx().def_path(def_id); + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = scx.tcx().def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | + DefPathData::ValueNs(_) => { + instance_ty = scx.tcx().item_type(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + bug!("finding type for {:?}, encountered def-id {:?} with no \ + parent", def_id, ty_def_id); + }); } } + } - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty); + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = scx.tcx().erase_regions(&instance_ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); + let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); - let mut buffer = SymbolPathBuffer { - names: Vec::with_capacity(def_path.data.len()) - }; + let mut buffer = SymbolPathBuffer { + names: Vec::with_capacity(def_path.data.len()) + }; - item_path::with_forced_absolute_paths(|| { - scx.tcx().push_item_path(&mut buffer, def_id); - }); + item_path::with_forced_absolute_paths(|| { + scx.tcx().push_item_path(&mut buffer, def_id); + }); - mangle(buffer.names.into_iter(), &hash) - } + mangle(buffer.names.into_iter(), &hash) } struct SymbolPathBuffer { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index fe2b21895cce6..ce767468c012b 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -565,11 +565,11 @@ pub fn memcpy_ty<'a, 'tcx>( } pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, - ptr: ValueRef, - fill_byte: ValueRef, - size: ValueRef, - align: ValueRef, - volatile: bool) -> ValueRef { + ptr: ValueRef, + fill_byte: ValueRef, + size: ValueRef, + align: ValueRef, + volatile: bool) -> ValueRef { let ptr_width = &b.ccx.sess().target.target.target_pointer_width[..]; let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); let llintrinsicfn = b.ccx.get_intrinsic(&intrinsic_key); @@ -581,7 +581,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let _s = if ccx.sess().trans_stats() { let mut instance_name = String::new(); DefPathBasedNames::new(ccx.tcx(), true, true) - .push_def_path(instance.def, &mut instance_name); + .push_def_path(instance.def_id(), &mut instance_name); Some(StatRecorder::new(ccx, instance_name)) } else { None @@ -592,7 +592,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance // release builds. info!("trans_instance({})", instance); - let fn_ty = common::def_ty(ccx.shared(), instance.def, instance.substs); + let fn_ty = common::instance_ty(ccx.shared(), &instance); let sig = common::ty_fn_sig(ccx, fn_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); @@ -607,7 +607,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance attributes::emit_uwtable(lldecl, true); } - let mir = ccx.tcx().item_mir(instance.def); + let mir = ccx.tcx().instance_mir(instance.def); mir::trans_mir(ccx, lldecl, &mir, instance, sig); } @@ -668,7 +668,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { ccx.tcx().sess.span_fatal(span, "compilation successful"); } - let instance = Instance::mono(ccx.shared(), main_def_id); + let instance = Instance::mono(ccx.tcx(), main_def_id); if !ccx.codegen_unit().contains_item(&TransItem::Fn(instance)) { // We want to create the wrapper in the same codegen unit as Rust's main diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index a5b42a973cf27..19fc4e013fae1 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -27,11 +27,12 @@ use common::{self, CrateContext}; use cleanup::CleanupScope; use mir::lvalue::LvalueRef; use consts; -use common::def_ty; +use common::instance_ty; use declare; use value::Value; use meth; use monomorphize::Instance; +use back::symbol_names::symbol_name; use trans_item::TransItem; use type_of; use rustc::ty::{self, Ty, TypeFoldable}; @@ -77,7 +78,8 @@ impl<'tcx> Callee<'tcx> { return Callee::trait_method(ccx, trait_id, def_id, substs); } - let fn_ty = def_ty(ccx.shared(), def_id, substs); + let instance = ty::Instance::new(def_id, substs); + let fn_ty = instance_ty(ccx.shared(), &instance); if let ty::TyFnDef(.., f) = fn_ty.sty { if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { return Callee { @@ -87,7 +89,7 @@ impl<'tcx> Callee<'tcx> { } } - let (llfn, ty) = get_fn(ccx, def_id, substs); + let (llfn, ty) = get_fn(ccx, instance); Callee::ptr(llfn, ty) } @@ -104,13 +106,13 @@ impl<'tcx> Callee<'tcx> { match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(vtable_impl) => { let name = tcx.item_name(def_id); - let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl); + let instance = common::find_method(tcx, name, substs, &vtable_impl); // Translate the function, bypassing Callee::def. // That is because default methods have the same ID as the // trait method used to look up the impl method that ended // up here, so calling Callee::def would infinitely recurse. - let (llfn, ty) = get_fn(ccx, def_id, substs); + let (llfn, ty) = get_fn(ccx, instance); Callee::ptr(llfn, ty) } traits::VtableClosure(vtable_closure) => { @@ -125,7 +127,7 @@ impl<'tcx> Callee<'tcx> { instance, trait_closure_kind); - let method_ty = def_ty(ccx.shared(), def_id, substs); + let method_ty = instance_ty(ccx.shared(), &instance); Callee::ptr(llfn, method_ty) } traits::VtableFnPointer(vtable_fn_pointer) => { @@ -135,13 +137,13 @@ impl<'tcx> Callee<'tcx> { trait_closure_kind, vtable_fn_pointer.fn_ty); - let method_ty = def_ty(ccx.shared(), def_id, substs); + let method_ty = instance_ty(ccx.shared(), &instance); Callee::ptr(llfn, method_ty) } traits::VtableObject(ref data) => { Callee { data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)), - ty: def_ty(ccx.shared(), def_id, substs) + ty: instance_ty(ccx.shared(), &Instance::new(def_id, substs)) } } vtable => { @@ -183,7 +185,7 @@ fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, -> ValueRef { // If this is a closure, redirect to it. - let (llfn, _) = get_fn(ccx, def_id, substs.substs); + let (llfn, _) = get_fn(ccx, Instance::new(def_id, substs.substs)); // If the closure is a Fn closure, but a FnOnce is needed (etc), // then adapt the self type @@ -292,7 +294,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig)); // Create the by-value helper. - let function_name = method_instance.symbol_name(ccx.shared()); + let function_name = symbol_name(method_instance, ccx.shared()); let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); attributes::set_frame_pointer_elimination(ccx, lloncefn); @@ -438,7 +440,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // - let function_name = method_instance.symbol_name(ccx.shared()); + let function_name = symbol_name(method_instance, ccx.shared()); let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty); attributes::set_frame_pointer_elimination(ccx, llfn); // @@ -489,21 +491,17 @@ fn trans_fn_pointer_shim<'a, 'tcx>( /// - `def_id`: def id of the fn or method item being referenced /// - `substs`: values for each of the fn/method's parameters fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) + instance: Instance<'tcx>) -> (ValueRef, Ty<'tcx>) { let tcx = ccx.tcx(); - debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs); + debug!("get_fn(instance={:?})", instance); - assert!(!substs.needs_infer()); - assert!(!substs.has_escaping_regions()); - assert!(!substs.has_param_types()); - - let substs = tcx.normalize_associated_type(&substs); - let instance = Instance::new(def_id, substs); - let fn_ty = common::def_ty(ccx.shared(), def_id, substs); + assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_escaping_regions()); + assert!(!instance.substs.has_param_types()); + let fn_ty = common::instance_ty(ccx.shared(), &instance); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { return (llfn, fn_ty); } @@ -553,7 +551,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert_eq!(common::val_ty(llfn), llptrty); debug!("get_fn: not casting pointer!"); - let attrs = ccx.tcx().get_attrs(def_id); + let attrs = instance.def.attrs(ccx.tcx()); attributes::from_fn_attrs(ccx, &attrs, llfn); let is_local_def = ccx.shared().translation_items().borrow() @@ -565,7 +563,9 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); } } - if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(def_id) { + if ccx.use_dll_storage_attrs() && + ccx.sess().cstore.is_dllimport_foreign_item(instance.def_id()) + { unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5e6b10f826ce0..271f91f9adbdb 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -207,7 +207,7 @@ use syntax_pos::DUMMY_SP; use base::custom_coerce_unsize_info; use callee::needs_fn_once_adapter_shim; use context::SharedCrateContext; -use common::{def_ty, fulfill_obligation}; +use common::{def_ty, find_method, instance_ty, fulfill_obligation}; use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -337,21 +337,22 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, } TransItem::Static(node_id) => { let def_id = scx.tcx().hir.local_def_id(node_id); + let instance = Instance::mono(scx.tcx(), def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_trans_locally(scx.tcx(), def_id)); + debug_assert!(should_trans_locally(scx.tcx(), &instance)); - let ty = def_ty(scx, def_id, Substs::empty()); + let ty = instance_ty(scx, &instance); let ty = glue::get_drop_glue_type(scx, ty); neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); recursion_depth_reset = None; - collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors); + collect_neighbours(scx, instance, &mut neighbors); } TransItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_trans_locally(scx.tcx(), instance.def)); + debug_assert!(should_trans_locally(scx.tcx(), &instance)); // Keep track of the monomorphization recursion depth recursion_depth_reset = Some(check_recursion_limit(scx.tcx(), @@ -395,9 +396,8 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, recursion_depths: &mut DefIdMap) -> (DefId, usize) { - let recursion_depth = recursion_depths.get(&instance.def) - .map(|x| *x) - .unwrap_or(0); + let def_id = instance.def_id(); + let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); debug!(" => recursion depth={}", recursion_depth); // Code that needs to instantiate the same function recursively @@ -406,16 +406,16 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if recursion_depth > tcx.sess.recursion_limit.get() { let error = format!("reached the recursion limit while instantiating `{}`", instance); - if let Some(node_id) = tcx.hir.as_local_node_id(instance.def) { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { tcx.sess.span_fatal(tcx.hir.span(node_id), &error); } else { tcx.sess.fatal(&error); } } - recursion_depths.insert(instance.def, recursion_depth + 1); + recursion_depths.insert(def_id, recursion_depth + 1); - (instance.def, recursion_depth) + (def_id, recursion_depth) } fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -438,7 +438,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let instance_name = instance.to_string(); let msg = format!("reached the type-length limit while instantiating `{:.64}...`", instance_name); - let mut diag = if let Some(node_id) = tcx.hir.as_local_node_id(instance.def) { + let mut diag = if let Some(node_id) = tcx.hir.as_local_node_id(instance.def_id()) { tcx.sess.struct_span_fatal(tcx.hir.span(node_id), &msg) } else { tcx.sess.struct_fatal(&msg) @@ -493,33 +493,24 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let source_ty = operand.ty(self.mir, self.scx.tcx()); match source_ty.sty { ty::TyClosure(def_id, substs) => { - let closure_trans_item = - create_fn_trans_item(self.scx, - def_id, - substs.substs, - self.param_substs); - self.output.push(closure_trans_item); + let substs = monomorphize::apply_param_substs( + self.scx, self.param_substs, &substs.substs); + self.output.push(create_fn_trans_item( + Instance::new(def_id, substs) + )); } _ => bug!(), } } mir::Rvalue::Box(..) => { - let exchange_malloc_fn_def_id = - self.scx - .tcx() - .lang_items - .require(ExchangeMallocFnLangItem) - .unwrap_or_else(|e| self.scx.sess().fatal(&e)); - - if should_trans_locally(self.scx.tcx(), exchange_malloc_fn_def_id) { - let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id); - let exchange_malloc_fn_trans_item = - create_fn_trans_item(self.scx, - exchange_malloc_fn_def_id, - empty_substs, - self.param_substs); - - self.output.push(exchange_malloc_fn_trans_item); + let tcx = self.scx.tcx(); + let exchange_malloc_fn_def_id = tcx + .lang_items + .require(ExchangeMallocFnLangItem) + .unwrap_or_else(|e| self.scx.sess().fatal(&e)); + let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); + if should_trans_locally(tcx, &instance) { + self.output.push(create_fn_trans_item(instance)); } } _ => { /* not interesting */ } @@ -564,8 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs); - - let instance = Instance::new(def_id, substs).resolve_const(self.scx); + let instance = monomorphize::resolve_const(self.scx, def_id, substs); collect_neighbours(self.scx, instance, self.output); } @@ -586,28 +576,24 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // // Calling do_static_dispatch() here will map the def_id of // `std::cmp::partial_cmp` to the def_id of `i32::partial_cmp` + + let callee_substs = monomorphize::apply_param_substs(self.scx, + self.param_substs, + &callee_substs); let dispatched = do_static_dispatch(self.scx, callee_def_id, - callee_substs, - self.param_substs); + callee_substs); if let StaticDispatchResult::Dispatched { - def_id: callee_def_id, - substs: callee_substs, - fn_once_adjustment, - } = dispatched { + instance, fn_once_adjustment + } = dispatched { // if we have a concrete impl (which we might not have // in the case of something compiler generated like an // object shim or a closure that is handled differently), // we check if the callee is something that will actually // result in a translation item ... - if can_result_in_trans_item(self.scx.tcx(), callee_def_id) { - // ... and create one if it does. - let trans_item = create_fn_trans_item(self.scx, - callee_def_id, - callee_substs, - self.param_substs); - self.output.push(trans_item); + if should_trans_locally(self.scx.tcx(), &instance) { + self.output.push(create_fn_trans_item(instance)); // This call will instantiate an FnOnce adapter, which drops // the closure environment. Therefore we need to make sure @@ -624,26 +610,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } self.super_operand(operand, location); - - fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { - match tcx.item_type(def_id).sty { - ty::TyFnDef(def_id, _, _) => { - // foreign items are linked from another library, not - // translated locally. - if let Some(hir_map::NodeForeignItem(_)) = tcx.hir.get_if_local(def_id) { - return false; - } - } - ty::TyClosure(..) => { - // TODO: trans items for closures - } - _ => return false - } - - should_trans_locally(tcx, def_id) - } } // This takes care of the "drop_in_place" intrinsic for which we otherwise @@ -695,22 +661,30 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // Returns true if we should translate an instance in the local crate. // Returns false if we can just link to the upstream crate and therefore don't // need a translation item. -fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) +fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) -> bool { - if def_id.is_local() { - true - } else { - if tcx.sess.cstore.is_exported_symbol(def_id) || - tcx.sess.cstore.is_foreign_item(def_id) { - // We can link to the item in question, no instance needed in this - // crate - false - } else { - if !tcx.sess.cstore.is_item_mir_available(def_id) { - bug!("Cannot create local trans-item for {:?}", def_id) + let def_id = match instance.def { + ty::InstanceDef::Item(def_id) => def_id, + ty::InstanceDef::FnPtrShim(..) => return true + }; + match tcx.hir.get_if_local(def_id) { + Some(hir_map::NodeForeignItem(..)) => { + false // foreign items are linked against, not translated. + } + Some(_) => true, + None => { + if tcx.sess.cstore.is_exported_symbol(def_id) || + tcx.sess.cstore.is_foreign_item(def_id) + { + // We can link to the item in question, no instance needed + // in this crate + false + } else { + if !tcx.sess.cstore.is_item_mir_available(def_id) { + bug!("Cannot create local trans-item for {:?}", def_id) + } + true } - true } } } @@ -731,14 +705,14 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value. if ty.is_box() { - let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem); - if should_trans_locally(scx.tcx(), def_id) { - let box_free_fn_trans_item = - create_fn_trans_item(scx, - def_id, - scx.tcx().mk_substs(iter::once(Kind::from(ty.boxed_ty()))), - scx.tcx().intern_substs(&[])); - output.push(box_free_fn_trans_item); + let tcx = scx.tcx(); + let def_id = tcx.require_lang_item(BoxFreeFnLangItem); + let box_free_instance = Instance::new( + def_id, + tcx.mk_substs(iter::once(Kind::from(ty.boxed_ty()))) + ); + if should_trans_locally(tcx, &box_free_instance) { + output.push(create_fn_trans_item(box_free_instance)); } } @@ -768,13 +742,9 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, traits::VtableImpl(data) => data.substs, _ => bug!() }; - - if should_trans_locally(scx.tcx(), destructor.did) { - let trans_item = create_fn_trans_item(scx, - destructor.did, - substs, - scx.tcx().intern_substs(&[])); - output.push(trans_item); + let instance = Instance::new(destructor.did, substs); + if should_trans_locally(scx.tcx(), &instance) { + output.push(create_fn_trans_item(instance)); } // This type has a Drop implementation, we'll need the contents-only @@ -847,72 +817,59 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } +enum StaticDispatchResult<'tcx> { + // The call could be resolved statically as going to the method with + // `instance`. + Dispatched { + instance: Instance<'tcx>, + // If this is a call to a closure that needs an FnOnce adjustment, + // this contains the new self type of the call (= type of the closure + // environment) + fn_once_adjustment: Option>, + }, + // This goes to somewhere that we don't know at compile-time + Unknown +} + fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn_def_id: DefId, - fn_substs: &'tcx Substs<'tcx>, - param_substs: &'tcx Substs<'tcx>) + fn_substs: &'tcx Substs<'tcx>) -> StaticDispatchResult<'tcx> { - debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})", + debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?})", def_id_to_string(scx.tcx(), fn_def_id), - fn_substs, - param_substs); - + fn_substs); if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { debug!(" => trait method, attempting to find impl"); do_static_trait_method_dispatch(scx, &scx.tcx().associated_item(fn_def_id), trait_def_id, - fn_substs, - param_substs) + fn_substs) } else { debug!(" => regular function"); // The function is not part of an impl or trait, no dispatching // to be done StaticDispatchResult::Dispatched { - def_id: fn_def_id, - substs: fn_substs, + instance: Instance::new(fn_def_id, fn_substs), fn_once_adjustment: None, } } } -enum StaticDispatchResult<'tcx> { - // The call could be resolved statically as going to the method with - // `def_id` and `substs`. - Dispatched { - def_id: DefId, - substs: &'tcx Substs<'tcx>, - - // If this is a call to a closure that needs an FnOnce adjustment, - // this contains the new self type of the call (= type of the closure - // environment) - fn_once_adjustment: Option>, - }, - // This goes to somewhere that we don't know at compile-time - Unknown -} - // Given a trait-method and substitution information, find out the actual // implementation of the trait method. fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, trait_method: &ty::AssociatedItem, trait_id: DefId, - callee_substs: &'tcx Substs<'tcx>, - param_substs: &'tcx Substs<'tcx>) + rcvr_substs: &'tcx Substs<'tcx>) -> StaticDispatchResult<'tcx> { let tcx = scx.tcx(); debug!("do_static_trait_method_dispatch(trait_method={}, \ trait_id={}, \ - callee_substs={:?}, \ - param_substs={:?}", + rcvr_substs={:?})", def_id_to_string(scx.tcx(), trait_method.def_id), def_id_to_string(scx.tcx(), trait_id), - callee_substs, - param_substs); + rcvr_substs); - let rcvr_substs = monomorphize::apply_param_substs(scx, - param_substs, - &callee_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); @@ -920,13 +877,8 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // the actual function: match vtbl { traits::VtableImpl(impl_data) => { - let (def_id, substs) = traits::find_method(tcx, - trait_method.name, - rcvr_substs, - &impl_data); StaticDispatchResult::Dispatched { - def_id: def_id, - substs: substs, + instance: find_method(tcx, trait_method.name, rcvr_substs, &impl_data), fn_once_adjustment: None, } } @@ -950,8 +902,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, }; StaticDispatchResult::Dispatched { - def_id: closure_def_id, - substs: closure_data.substs.substs, + instance: Instance::new(closure_def_id, closure_data.substs.substs), fn_once_adjustment: fn_once_adjustment, } } @@ -961,7 +912,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, if let ty::TyFnDef(def_id, substs, _) = data.fn_ty.sty { // The destination of the pointer might be something that needs // further dispatching, such as a trait method, so we do that. - do_static_dispatch(scx, def_id, substs, param_substs) + do_static_dispatch(scx, def_id, substs) } else { StaticDispatchResult::Unknown } @@ -1066,28 +1017,9 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } -fn create_fn_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - def_id: DefId, - fn_substs: &'tcx Substs<'tcx>, - param_substs: &'tcx Substs<'tcx>) - -> TransItem<'tcx> { - let tcx = scx.tcx(); - - debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})", - def_id_to_string(tcx, def_id), - fn_substs, - param_substs); - - // We only get here, if fn_def_id either designates a local item or - // an inlineable external item. Non-inlineable external items are - // ignored because we don't want to generate any code for them. - let concrete_substs = monomorphize::apply_param_substs(scx, - param_substs, - &fn_substs); - assert!(concrete_substs.is_normalized_for_trans(), - "concrete_substs not normalized for trans: {:?}", - concrete_substs); - TransItem::Fn(Instance::new(def_id, concrete_substs)) +fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { + debug!("create_fn_trans_item(instance={})", instance); + TransItem::Fn(instance) } /// Creates a `TransItem` for each method that is referenced by the vtable for @@ -1102,8 +1034,6 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty { if let Some(principal) = trait_ty.principal() { let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty); - let param_substs = scx.tcx().intern_substs(&[]); - assert!(!poly_trait_ref.has_escaping_regions()); // Walk all methods of the trait, including those of its supertraits @@ -1111,19 +1041,18 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, let methods = methods.filter_map(|method| method) .filter_map(|(def_id, substs)| { if let StaticDispatchResult::Dispatched { - def_id, - substs, + instance, // We already add the drop-glue for the closure env // unconditionally below. fn_once_adjustment: _ , - } = do_static_dispatch(scx, def_id, substs, param_substs) { - Some((def_id, substs)) + } = do_static_dispatch(scx, def_id, substs) { + Some(instance) } else { None } }) - .filter(|&(def_id, _)| should_trans_locally(scx.tcx(), def_id)) - .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs)); + .filter(|&instance| should_trans_locally(scx.tcx(), &instance)) + .map(|instance| create_fn_trans_item(instance)); output.extend(methods); } // Also add the destructor @@ -1195,7 +1124,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { debug!("RootCollector: ItemFn({})", def_id_to_string(self.scx.tcx(), def_id)); - let instance = Instance::mono(self.scx, def_id); + let instance = Instance::mono(self.scx.tcx(), def_id); self.output.push(TransItem::Fn(instance)); } } @@ -1233,7 +1162,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { debug!("RootCollector: MethodImplItem({})", def_id_to_string(self.scx.tcx(), def_id)); - let instance = Instance::mono(self.scx, def_id); + let instance = Instance::mono(self.scx.tcx(), def_id); self.output.push(TransItem::Fn(instance)); } } @@ -1278,31 +1207,22 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. - let impl_substs = Substs::for_item(tcx, impl_def_id, - |_, _| tcx.mk_region(ty::ReErased), - |_, _| tcx.types.err); + let impl_substs = tcx.empty_substs_for_def_id(impl_def_id); let impl_data = traits::VtableImplData { impl_def_id: impl_def_id, substs: impl_substs, nested: vec![] }; - let (def_id, substs) = traits::find_method(tcx, - method.name, - callee_substs, - &impl_data); + let instance = find_method(tcx, method.name, callee_substs, &impl_data); - let predicates = tcx.item_predicates(def_id).predicates - .subst(tcx, substs); + let predicates = tcx.item_predicates(instance.def_id()).predicates + .subst(tcx, impl_substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; } - if should_trans_locally(tcx, method.def_id) { - let item = create_fn_trans_item(scx, - method.def_id, - callee_substs, - tcx.erase_regions(&substs)); - output.push(item); + if should_trans_locally(tcx, &instance) { + output.push(create_fn_trans_item(instance)); } } } @@ -1318,7 +1238,7 @@ fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, instance: Instance<'tcx>, output: &mut Vec>) { - let mir = scx.tcx().item_mir(instance.def); + let mir = scx.tcx().instance_mir(instance.def); let mut visitor = MirNeighborCollector { scx: scx, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 0e536d58a56fb..4389207cdf294 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -602,7 +602,14 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -pub fn requests_inline(tcx: TyCtxt, def_id: DefId) -> bool { +pub fn requests_inline<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: &ty::Instance<'tcx> +) -> bool { + let def_id = match instance.def { + ty::InstanceDef::Item(def_id) => def_id, + _ => return true + }; match tcx.def_key(def_id).disambiguated_data.data { DefPathData::StructCtor | DefPathData::EnumVariant(..) | @@ -610,7 +617,6 @@ pub fn requests_inline(tcx: TyCtxt, def_id: DefId) -> bool { _ => attr::requests_inline(&tcx.get_attrs(def_id)[..]), } } - /// Given a DefId and some Substs, produces the monomorphic item type. pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, @@ -620,3 +626,23 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, let ty = shared.tcx().item_type(def_id); monomorphize::apply_param_substs(shared, substs, &ty) } + +/// Return the substituted type of an instance. +pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, + instance: &ty::Instance<'tcx>) + -> Ty<'tcx> +{ + let ty = instance.def.def_ty(shared.tcx()); + monomorphize::apply_param_substs(shared, instance.substs, &ty) +} + +pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + name: ast::Name, + substs: &'tcx Substs<'tcx>, + impl_data: &traits::VtableImplData<'tcx, ()>) + -> ty::Instance<'tcx> +{ + let (def_id, substs) = traits::find_method(tcx, name, substs, impl_data); + let substs = tcx.erase_regions(&substs); + ty::Instance::new(def_id, substs) +} diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index bf1d9886ae7f0..0c3d211912add 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -9,6 +9,7 @@ // except according to those terms. +use back::symbol_names; use llvm; use llvm::{SetUnnamedAddr}; use llvm::{ValueRef, True}; @@ -24,7 +25,6 @@ use monomorphize::Instance; use type_::Type; use type_of; use rustc::ty; -use rustc::ty::subst::Substs; use rustc::hir; @@ -80,12 +80,12 @@ pub fn addr_of(ccx: &CrateContext, } pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { - let instance = Instance::mono(ccx.shared(), def_id); + let instance = Instance::mono(ccx.tcx(), def_id); if let Some(&g) = ccx.instances().borrow().get(&instance) { return g; } - let ty = common::def_ty(ccx.shared(), def_id, Substs::empty()); + let ty = common::instance_ty(ccx.shared(), &instance); let g = if let Some(id) = ccx.tcx().hir.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); @@ -114,7 +114,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let sym = instance.symbol_name(ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.shared()); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -174,7 +174,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g } else { - let sym = instance.symbol_name(ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.shared()); // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global @@ -235,7 +235,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, v }; - let ty = common::def_ty(ccx.shared(), def_id, Substs::empty()); + let instance = Instance::mono(ccx.tcx(), def_id); + let ty = common::instance_ty(ccx.shared(), &instance); let llty = type_of::type_of(ccx, ty); let g = if val_llty == llty { g diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 52851ea995d4b..b7381dd07dcfa 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -546,16 +546,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.translation_items } - /// Given the def-id of some item that has no type parameters, make - /// a suitable "empty substs" for it. - pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { - Substs::for_item(self.tcx(), item_def_id, - |_, _| self.tcx().mk_region(ty::ReErased), - |_, _| { - bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) - }) - } - pub fn metadata_symbol_name(&self) -> String { format!("rust_metadata_{}_{}", self.link_meta().crate_name, @@ -886,7 +876,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { - self.shared().empty_substs_for_def_id(item_def_id) + self.tcx().empty_substs_for_def_id(item_def_id) } /// Generate a new symbol name with the given prefix. This symbol name must diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 1d4aebf135b9e..8e86b50b3f7dd 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -205,7 +205,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return FunctionDebugContext::DebugInfoDisabled; } - for attr in cx.tcx().get_attrs(instance.def).iter() { + for attr in instance.def.attrs(cx.tcx()).iter() { if attr.check_name("no_debug") { return FunctionDebugContext::FunctionWithoutDebugInfo; } @@ -229,11 +229,11 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; // Find the enclosing function, in case this is a closure. - let def_key = cx.tcx().def_key(instance.def); + let def_key = cx.tcx().def_key(instance.def_id()); let mut name = def_key.disambiguated_data.data.to_string(); let name_len = name.len(); - let fn_def_id = cx.tcx().closure_base_def_id(instance.def); + let fn_def_id = cx.tcx().closure_base_def_id(instance.def_id()); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. @@ -246,11 +246,11 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &mut name); // Build the linkage_name out of the item path and "template" parameters. - let linkage_name = mangled_name_of_item(cx, instance.def, &name[name_len..]); + let linkage_name = mangled_name_of_item(cx, instance.def_id(), &name[name_len..]); let scope_line = span_start(cx, span).line; - let local_id = cx.tcx().hir.as_local_node_id(instance.def); + let local_id = cx.tcx().hir.as_local_node_id(instance.def_id()); let is_local_to_unit = local_id.map_or(false, |id| is_node_local_to_unit(cx, id)); let function_name = CString::new(name).unwrap(); @@ -394,7 +394,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // First, let's see if this is a method within an inherent impl. Because // if yes, we want to make the result subroutine DIE a child of the // subroutine's self-type. - let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| { + let self_type = cx.tcx().impl_of_method(instance.def_id()).and_then(|impl_def_id| { // If the method does *not* belong to a trait, proceed if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { let impl_self_ty = @@ -417,9 +417,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, self_type.unwrap_or_else(|| { namespace::item_namespace(cx, DefId { - krate: instance.def.krate, + krate: instance.def_id().krate, index: cx.tcx() - .def_key(instance.def) + .def_key(instance.def_id()) .parent .expect("get_containing_scope: missing parent?") }) diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index a3f4168e96f2a..bfd9f69a92218 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -21,6 +21,7 @@ use machine; use monomorphize::Instance; use type_::Type; use type_of::*; +use back::symbol_names; use value::Value; use rustc::ty; @@ -70,7 +71,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, let function_name = match callee.ty.sty { ty::TyFnDef(def_id, substs, _) => { let instance = Instance::new(def_id, substs); - instance.symbol_name(ccx.shared()) + symbol_names::symbol_name(instance, ccx.shared()) } _ => bug!() }; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b6fcc990344ce..deb1073cf9aed 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -30,7 +30,7 @@ use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integra use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef}; use common::const_to_opt_u128; use consts; -use monomorphize::{self, Instance}; +use monomorphize; use type_of; use type_::Type; use value::Value; @@ -245,11 +245,12 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, args: IndexVec>) -> Result, ConstEvalErr<'tcx>> { - let instance = instance.resolve_const(ccx.shared()); - let mir = ccx.tcx().item_mir(instance.def); + let instance = monomorphize::resolve_const(ccx.shared(), def_id, substs); + let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } @@ -332,10 +333,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => { let fn_ty = func.ty(self.mir, tcx); let fn_ty = self.monomorphize(&fn_ty); - let instance = match fn_ty.sty { - ty::TyFnDef(def_id, substs, _) => { - Instance::new(def_id, substs) - } + let (def_id, substs) = match fn_ty.sty { + ty::TyFnDef(def_id, substs, _) => (def_id, substs), _ => span_bug!(span, "calling {:?} (of type {}) in constant", func, fn_ty) }; @@ -348,7 +347,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } if let Some((ref dest, target)) = *destination { - match MirConstContext::trans_def(self.ccx, instance, const_args) { + match MirConstContext::trans_def(self.ccx, def_id, substs, const_args) { Ok(value) => self.store(dest, value, span), Err(err) => if failure.is_ok() { failure = Err(err); } } @@ -485,8 +484,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } let substs = self.monomorphize(&substs); - let instance = Instance::new(def_id, substs); - MirConstContext::trans_def(self.ccx, instance, IndexVec::new()) + MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new()) } mir::Literal::Promoted { index } => { let mir = &self.mir.promoted[index]; @@ -588,7 +586,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { // Now create its substs [Closure, Tuple] let input = tcx.closure_type(def_id) .subst(tcx, substs.substs).input(0); - let substs = tcx.mk_substs([operand.ty, input.skip_binder()] + let input = tcx.erase_late_bound_regions_and_normalize(&input); + let substs = tcx.mk_substs([operand.ty, input] .iter().cloned().map(Kind::from)); Callee::def(self.ccx, call_once, substs) .reify(self.ccx) @@ -935,8 +934,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } let substs = self.monomorphize(&substs); - let instance = Instance::new(def_id, substs); - MirConstContext::trans_def(bcx.ccx, instance, IndexVec::new()) + MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new()) } mir::Literal::Promoted { index } => { let mir = &self.mir.promoted[index]; @@ -964,8 +962,8 @@ pub fn trans_static_initializer<'a, 'tcx>( def_id: DefId) -> Result> { - let instance = Instance::mono(ccx.shared(), def_id); - MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval) + MirConstContext::trans_def(ccx, def_id, Substs::empty(), IndexVec::new()) + .map(|c| c.llval) } /// Construct a constant value, suitable for initializing a diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b6af4e52e820b..bbaf0f9d35fa6 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -203,7 +203,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Now create its substs [Closure, Tuple] let input = bcx.tcx().closure_type(def_id) .subst(bcx.tcx(), substs.substs).input(0); - let substs = bcx.tcx().mk_substs([operand.ty, input.skip_binder()] + let input = + bcx.tcx().erase_late_bound_regions_and_normalize(&input); + let substs = bcx.tcx().mk_substs([operand.ty, input] .iter().cloned().map(Kind::from)); OperandValue::Immediate( Callee::def(bcx.ccx, call_once, substs) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 4b31d5b7f88de..3b746af275a2a 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -15,54 +15,31 @@ use rustc::traits; use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::ppaux; use rustc::util::common::MemoizationMap; use syntax::codemap::DUMMY_SP; -use std::fmt; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Instance<'tcx> { - pub def: DefId, - pub substs: &'tcx Substs<'tcx>, -} - -impl<'tcx> fmt::Display for Instance<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, &self.substs, self.def, &[]) - } -} - -impl<'a, 'tcx> Instance<'tcx> { - pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) - -> Instance<'tcx> { - assert!(substs.regions().all(|&r| r == ty::ReErased)); - Instance { def: def_id, substs: substs } - } - - pub fn mono(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, scx.empty_substs_for_def_id(def_id)) - } - - /// For associated constants from traits, return the impl definition. - pub fn resolve_const(&self, scx: &SharedCrateContext<'a, 'tcx>) -> Self { - if let Some(trait_id) = scx.tcx().trait_of_item(self.def) { - let trait_ref = ty::TraitRef::new(trait_id, self.substs); - let trait_ref = ty::Binder(trait_ref); - let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref); - if let traits::VtableImpl(vtable_impl) = vtable { - let name = scx.tcx().item_name(self.def); - let ac = scx.tcx().associated_items(vtable_impl.impl_def_id) - .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); - if let Some(ac) = ac { - return Instance::new(ac.def_id, vtable_impl.substs); - } +pub use rustc::ty::Instance; + +/// For associated constants from traits, return the impl definition. +pub fn resolve_const<'a, 'tcx>( + scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx> +) -> Instance<'tcx> { + if let Some(trait_id) = scx.tcx().trait_of_item(def_id) { + let trait_ref = ty::TraitRef::new(trait_id, substs); + let trait_ref = ty::Binder(trait_ref); + let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref); + if let traits::VtableImpl(vtable_impl) = vtable { + let name = scx.tcx().item_name(def_id); + let ac = scx.tcx().associated_items(vtable_impl.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); + if let Some(ac) = ac { + return Instance::new(ac.def_id, vtable_impl.substs); } } - - *self } + + Instance::new(def_id, substs) } /// Monomorphizes a type from the AST by first applying the in-scope diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index cc9fd8f46f6f0..1232c6cd28e52 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -110,7 +110,7 @@ use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt}; use rustc::ty::item_path::characteristic_def_id_of_type; use rustc_incremental::IchHasher; use std::cmp::Ordering; @@ -186,7 +186,8 @@ impl<'tcx> CodegenUnit<'tcx> { symbol_name.hash(&mut state); let exported = match item { TransItem::Fn(ref instance) => { - let node_id = scx.tcx().hir.as_local_node_id(instance.def); + let node_id = + scx.tcx().hir.as_local_node_id(instance.def_id()); node_id.map(|node_id| exported_symbols.contains(&node_id)) .unwrap_or(false) } @@ -241,7 +242,7 @@ impl<'tcx> CodegenUnit<'tcx> { fn local_node_id(tcx: TyCtxt, trans_item: TransItem) -> Option { match trans_item { TransItem::Fn(instance) => { - tcx.hir.as_local_node_id(instance.def) + tcx.hir.as_local_node_id(instance.def_id()) } TransItem::Static(node_id) => Some(node_id), TransItem::DropGlue(_) => None, @@ -455,17 +456,22 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't let tcx = scx.tcx(); match trans_item { TransItem::Fn(instance) => { + let def_id = match instance.def { + ty::InstanceDef::Item(def_id) => def_id, + ty::InstanceDef::FnPtrShim(..) => return None + }; + // If this is a method, we want to put it into the same module as // its self-type. If the self-type does not provide a characteristic // DefId, we use the location of the impl after all. - if tcx.trait_of_item(instance.def).is_some() { + if tcx.trait_of_item(def_id).is_some() { let self_ty = instance.substs.type_at(0); // This is an implementation of a trait method. - return characteristic_def_id_of_type(self_ty).or(Some(instance.def)); + return characteristic_def_id_of_type(self_ty).or(Some(def_id)); } - if let Some(impl_def_id) = tcx.impl_of_method(instance.def) { + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { // This is a method within an inherent impl, find out what the // self-type is: let impl_self_ty = common::def_ty(scx, impl_def_id, instance.substs); @@ -474,7 +480,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't } } - Some(instance.def) + Some(def_id) } TransItem::DropGlue(dg) => characteristic_def_id_of_type(dg.ty()), TransItem::Static(node_id) => Some(tcx.hir.local_def_id(node_id)), diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 880c65937e308..cd285bfaa6010 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -97,7 +97,7 @@ impl<'tcx> SymbolMap<'tcx> { trans_item: TransItem<'tcx>) -> Option { match trans_item { TransItem::Fn(Instance { def, .. }) => { - tcx.hir.as_local_node_id(def) + tcx.hir.as_local_node_id(def.def_id()) } TransItem::Static(node_id) => Some(node_id), TransItem::DropGlue(_) => None, diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 02e1290b57783..fe551b06b3d95 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -14,6 +14,7 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. +use back::symbol_names; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use syntax::ast; @@ -51,8 +52,8 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { for attr in tcx.get_attrs(def_id).iter() { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names - let instance = Instance::mono(self.scx, def_id); - let name = instance.symbol_name(self.scx); + let instance = Instance::mono(tcx, def_id); + let name = symbol_names::symbol_name(instance, self.scx); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = tcx.item_path_str(def_id); @@ -86,4 +87,3 @@ impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> { intravisit::walk_impl_item(self, ii) } } - diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5ec9c2a59957d..13af081e0b698 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx> TransItem<'tcx> { } TransItem::Fn(instance) => { let _task = ccx.tcx().dep_graph.in_task( - DepNode::TransCrateItem(instance.def)); // (*) + DepNode::TransCrateItem(instance.def_id())); // (*) base::trans_instance(&ccx, instance); } @@ -147,7 +147,8 @@ impl<'a, 'tcx> TransItem<'tcx> { linkage: llvm::Linkage, symbol_name: &str) { let def_id = ccx.tcx().hir.local_def_id(node_id); - let ty = common::def_ty(ccx.shared(), def_id, Substs::empty()); + let instance = Instance::mono(ccx.tcx(), def_id); + let ty = common::instance_ty(ccx.shared(), &instance); let llty = type_of::type_of(ccx, ty); let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { @@ -157,7 +158,6 @@ impl<'a, 'tcx> TransItem<'tcx> { unsafe { llvm::LLVMRustSetLinkage(g, linkage) }; - let instance = Instance::mono(ccx.shared(), def_id); ccx.instances().borrow_mut().insert(instance, g); ccx.statics().borrow_mut().insert(g, def_id); } @@ -169,8 +169,8 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); - let mono_ty = common::def_ty(ccx.shared(), instance.def, instance.substs); - let attrs = ccx.tcx().get_attrs(instance.def); + let mono_ty = common::instance_ty(ccx.shared(), &instance); + let attrs = instance.def.attrs(ccx.tcx()); let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) }; base::set_link_section(ccx, lldecl, &attrs); @@ -180,7 +180,7 @@ impl<'a, 'tcx> TransItem<'tcx> { } debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); - match ccx.tcx().def_key(instance.def).disambiguated_data.data { + match ccx.tcx().def_key(instance.def_id()).disambiguated_data.data { DefPathData::StructCtor | DefPathData::EnumVariant(..) | DefPathData::ClosureExpr => { @@ -229,10 +229,10 @@ impl<'a, 'tcx> TransItem<'tcx> { pub fn compute_symbol_name(&self, scx: &SharedCrateContext<'a, 'tcx>) -> String { match *self { - TransItem::Fn(instance) => instance.symbol_name(scx), + TransItem::Fn(instance) => symbol_names::symbol_name(instance, scx), TransItem::Static(node_id) => { let def_id = scx.tcx().hir.local_def_id(node_id); - Instance::mono(scx, def_id).symbol_name(scx) + symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) } TransItem::DropGlue(dg) => { let prefix = match dg { @@ -244,21 +244,13 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn is_from_extern_crate(&self) -> bool { - match *self { - TransItem::Fn(ref instance) => !instance.def.is_local(), - TransItem::DropGlue(..) | - TransItem::Static(..) => false, - } - } - pub fn instantiation_mode(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> InstantiationMode { match *self { TransItem::Fn(ref instance) => { if self.explicit_linkage(tcx).is_none() && - common::requests_inline(tcx, instance.def) + common::requests_inline(tcx, instance) { InstantiationMode::LocalCopy } else { @@ -282,7 +274,7 @@ impl<'a, 'tcx> TransItem<'tcx> { pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { let def_id = match *self { - TransItem::Fn(ref instance) => instance.def, + TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), TransItem::DropGlue(..) => return None, }; @@ -587,7 +579,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { pub fn push_instance_as_string(&self, instance: Instance<'tcx>, output: &mut String) { - self.push_def_path(instance.def, output); + self.push_def_path(instance.def_id(), output); self.push_type_params(instance.substs, iter::empty(), output); } } From bf80fec326d0fa7b58882d6f2102808a3f220651 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 6 Mar 2017 12:58:51 +0200 Subject: [PATCH 105/662] translate function shims using MIR --- src/librustc_mir/shim.rs | 127 ++++++++++++++++- src/librustc_trans/callee.rs | 134 +----------------- src/librustc_trans/collector.rs | 14 +- .../item-collection/function-as-argument.rs | 2 + .../trait-method-as-argument.rs | 6 + src/test/run-pass/mir_calls_to_shims.rs | 56 ++++++++ 6 files changed, 199 insertions(+), 140 deletions(-) create mode 100644 src/test/run-pass/mir_calls_to_shims.rs diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 0fbd488ffa360..bf0b1796dffaf 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -12,30 +12,42 @@ use rustc::hir; use rustc::infer; use rustc::mir::*; use rustc::mir::transform::MirSource; -use rustc::ty; +use rustc::ty::{self, Ty}; use rustc::ty::maps::Providers; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use syntax::abi::Abi; use syntax::ast; +use syntax::codemap::DUMMY_SP; use syntax_pos::Span; use std::cell::RefCell; use std::iter; +use std::mem; pub fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } -fn make_shim<'a, 'tcx>(_tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, +fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx RefCell> { - match instance { + debug!("make_shim({:?})", instance); + let result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::FnPtrShim(..) => unimplemented!() - } + ty::InstanceDef::FnPtrShim(_, ty) => { + build_fn_ptr_shim(tcx, ty, instance.def_ty(tcx)) + } + }; + debug!("make_shim({:?}) = {:?}", instance, result); + + let result = tcx.alloc_mir(result); + // Perma-borrow MIR from shims to prevent mutation. + mem::forget(result.borrow()); + result } fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) @@ -54,6 +66,111 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) })).collect() } + +fn build_fn_ptr_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + fn_ty: Ty<'tcx>, + sig_ty: Ty<'tcx>) + -> Mir<'tcx> +{ + debug!("build_fn_ptr_shim(fn_ty={:?}, sig_ty={:?})", fn_ty, sig_ty); + let trait_sig = match sig_ty.sty { + ty::TyFnDef(_, _, fty) => tcx.erase_late_bound_regions(&fty), + _ => bug!("unexpected type for shim {:?}", sig_ty) + }; + + let self_ty = match trait_sig.inputs()[0].sty { + ty::TyParam(..) => fn_ty, + ty::TyRef(r, mt) => tcx.mk_ref(r, ty::TypeAndMut { + ty: fn_ty, + mutbl: mt.mutbl + }), + _ => bug!("unexpected self_ty {:?}", trait_sig), + }; + + let fn_ptr_sig = match fn_ty.sty { + ty::TyFnPtr(fty) | + ty::TyFnDef(_, _, fty) => + tcx.erase_late_bound_regions_and_normalize(&fty), + _ => bug!("non-fn-ptr {:?} in build_fn_ptr_shim", fn_ty) + }; + + let sig = tcx.mk_fn_sig( + [ + self_ty, + tcx.intern_tup(fn_ptr_sig.inputs(), false) + ].iter().cloned(), + fn_ptr_sig.output(), + false, + hir::Unsafety::Normal, + Abi::RustCall, + ); + + let local_decls = local_decls_for_sig(&sig); + let source_info = SourceInfo { + span: DUMMY_SP, + scope: ARGUMENT_VISIBILITY_SCOPE + }; + + let fn_ptr = Lvalue::Local(Local::new(1+0)); + let fn_ptr = match trait_sig.inputs()[0].sty { + ty::TyParam(..) => fn_ptr, + ty::TyRef(..) => Lvalue::Projection(box Projection { + base: fn_ptr, elem: ProjectionElem::Deref + }), + _ => bug!("unexpected self_ty {:?}", trait_sig), + }; + let fn_args = Local::new(1+1); + + let return_block_id = BasicBlock::new(1); + + // return = ADT(arg0, arg1, ...); return + let start_block = BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: source_info, + kind: TerminatorKind::Call { + func: Operand::Consume(fn_ptr), + args: fn_ptr_sig.inputs().iter().enumerate().map(|(i, ity)| { + Operand::Consume(Lvalue::Projection(box Projection { + base: Lvalue::Local(fn_args), + elem: ProjectionElem::Field( + Field::new(i), *ity + ) + })) + }).collect(), + // FIXME: can we pass a Some destination for an uninhabited ty? + destination: Some((Lvalue::Local(RETURN_POINTER), + return_block_id)), + cleanup: None + } + }), + is_cleanup: false + }; + let return_block = BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: source_info, + kind: TerminatorKind::Return + }), + is_cleanup: false + }; + + let mut mir = Mir::new( + vec![start_block, return_block].into_iter().collect(), + IndexVec::from_elem_n( + VisibilityScopeData { span: DUMMY_SP, parent_scope: None }, 1 + ), + IndexVec::new(), + sig.output(), + local_decls, + sig.inputs().len(), + vec![], + DUMMY_SP + ); + mir.spread_arg = Some(fn_args); + mir +} + pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, ctor_id: ast::NodeId, fields: &[hir::StructField], diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 19fc4e013fae1..2294e8a0002e0 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -36,7 +36,6 @@ use back::symbol_names::symbol_name; use trans_item::TransItem; use type_of; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::hir; use std::iter; use syntax_pos::DUMMY_SP; @@ -130,15 +129,14 @@ impl<'tcx> Callee<'tcx> { let method_ty = instance_ty(ccx.shared(), &instance); Callee::ptr(llfn, method_ty) } - traits::VtableFnPointer(vtable_fn_pointer) => { - let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let instance = Instance::new(def_id, substs); - let llfn = trans_fn_pointer_shim(ccx, instance, - trait_closure_kind, - vtable_fn_pointer.fn_ty); + traits::VtableFnPointer(data) => { + let instance = ty::Instance { + def: ty::InstanceDef::FnPtrShim(def_id, data.fn_ty), + substs: substs, + }; - let method_ty = instance_ty(ccx.shared(), &instance); - Callee::ptr(llfn, method_ty) + let (llfn, ty) = get_fn(ccx, instance); + Callee::ptr(llfn, ty) } traits::VtableObject(ref data) => { Callee { @@ -363,124 +361,6 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( lloncefn } -/// Translates an adapter that implements the `Fn` trait for a fn -/// pointer. This is basically the equivalent of something like: -/// -/// ``` -/// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int { -/// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int { -/// (*self)(args.0) -/// } -/// } -/// ``` -/// -/// but for the bare function type given. -fn trans_fn_pointer_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - method_instance: Instance<'tcx>, - closure_kind: ty::ClosureKind, - bare_fn_ty: Ty<'tcx>) - -> ValueRef -{ - let tcx = ccx.tcx(); - - // Normalize the type for better caching. - let bare_fn_ty = tcx.normalize_associated_type(&bare_fn_ty); - - // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`. - let is_by_ref = match closure_kind { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true, - ty::ClosureKind::FnOnce => false, - }; - - let llfnpointer = match bare_fn_ty.sty { - ty::TyFnDef(def_id, substs, _) => { - // Function definitions have to be turned into a pointer. - let llfn = Callee::def(ccx, def_id, substs).reify(ccx); - if !is_by_ref { - // A by-value fn item is ignored, so the shim has - // the same signature as the original function. - return llfn; - } - Some(llfn) - } - _ => None - }; - - let bare_fn_ty_maybe_ref = if is_by_ref { - tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), bare_fn_ty) - } else { - bare_fn_ty - }; - - // Check if we already trans'd this shim. - if let Some(&llval) = ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) { - return llval; - } - - debug!("trans_fn_pointer_shim(bare_fn_ty={:?})", - bare_fn_ty); - - // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`, - // which is the fn pointer, and `args`, which is the arguments tuple. - let sig = bare_fn_ty.fn_sig(); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - assert_eq!(sig.unsafety, hir::Unsafety::Normal); - assert_eq!(sig.abi, Abi::Rust); - let tuple_input_ty = tcx.intern_tup(sig.inputs(), false); - let sig = tcx.mk_fn_sig( - [bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(), - sig.output(), - false, - hir::Unsafety::Normal, - Abi::RustCall - ); - let fn_ty = FnType::new(ccx, sig, &[]); - let tuple_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig)); - debug!("tuple_fn_ty: {:?}", tuple_fn_ty); - - // - let function_name = symbol_name(method_instance, ccx.shared()); - let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty); - attributes::set_frame_pointer_elimination(ccx, llfn); - // - let bcx = Builder::new_block(ccx, llfn, "entry-block"); - - let mut llargs = get_params(llfn); - - let self_arg = llargs.remove(fn_ty.ret.is_indirect() as usize); - let llfnpointer = llfnpointer.unwrap_or_else(|| { - // the first argument (`self`) will be ptr to the fn pointer - if is_by_ref { - bcx.load(self_arg, None) - } else { - self_arg - } - }); - - let callee = Callee { - data: Fn(llfnpointer), - ty: bare_fn_ty - }; - let fn_ret = callee.ty.fn_ret(); - let fn_ty = callee.direct_fn_type(ccx, &[]); - let llret = bcx.call(llfnpointer, &llargs, None); - fn_ty.apply_attrs_callsite(llret); - - if fn_ret.0.is_never() { - bcx.unreachable(); - } else { - if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() { - bcx.ret_void(); - } else { - bcx.ret(llret); - } - } - - ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn); - - llfn -} /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 271f91f9adbdb..c4239fa2ae65f 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -907,14 +907,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } traits::VtableFnPointer(ref data) => { - // If we know the destination of this fn-pointer, we'll have to make - // sure that this destination actually gets instantiated. - if let ty::TyFnDef(def_id, substs, _) = data.fn_ty.sty { - // The destination of the pointer might be something that needs - // further dispatching, such as a trait method, so we do that. - do_static_dispatch(scx, def_id, substs) - } else { - StaticDispatchResult::Unknown + StaticDispatchResult::Dispatched { + instance: Instance { + def: ty::InstanceDef::FnPtrShim(trait_method.def_id, data.fn_ty), + substs: trait_ref.substs + }, + fn_once_adjustment: None, } } // Trait object shims are always instantiated in-place, and as they are diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs index 3a9d56c2a8bf7..51df38cabef30 100644 --- a/src/test/codegen-units/item-collection/function-as-argument.rs +++ b/src/test/codegen-units/item-collection/function-as-argument.rs @@ -28,10 +28,12 @@ fn main() { //~ TRANS_ITEM fn function_as_argument::take_fn_once[0] //~ TRANS_ITEM fn function_as_argument::function[0] + //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] take_fn_once(function, 0u32, "abc"); //~ TRANS_ITEM fn function_as_argument::take_fn_once[0] //~ TRANS_ITEM fn function_as_argument::function[0] + //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] take_fn_once(function, 'c', 0f64); //~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0] diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs index e7006d73ef166..f7afd3f0891e3 100644 --- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs +++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs @@ -40,22 +40,28 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { fn main() { //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] u32> //~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] + //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] u32, (u32)> take_foo_once(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] char> //~ TRANS_ITEM fn trait_method_as_argument::Trait[0]::foo[0] + //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] char, (char)> take_foo_once(Trait::foo, 'c'); //~ TRANS_ITEM fn trait_method_as_argument::take_foo[0] u32> + //~ TRANS_ITEM fn core::ops[0]::Fn[0]::call[0] u32, (u32)> take_foo(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo[0] char> + //~ TRANS_ITEM fn core::ops[0]::Fn[0]::call[0] char, (char)> take_foo(Trait::foo, 'c'); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0] u32> + //~ TRANS_ITEM fn core::ops[0]::FnMut[0]::call_mut[0] char, (char)> take_foo_mut(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0] char> + //~ TRANS_ITEM fn core::ops[0]::FnMut[0]::call_mut[0] u32, (u32)> take_foo_mut(Trait::foo, 'c'); } diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs new file mode 100644 index 0000000000000..7300a322ec4b7 --- /dev/null +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -0,0 +1,56 @@ +// 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. + +#![feature(fn_traits)] +#![feature(never_type)] + +use std::panic; + +fn foo(x: u32, y: u32) -> u32 { x/y } +fn foo_diverges() -> ! { panic!() } + +fn test_fn_ptr(mut t: T) + where T: Fn(u32, u32) -> u32, +{ + let as_fn = >::call; + assert_eq!(as_fn(&t, (9, 3)), 3); + let as_fn_mut = >::call_mut; + assert_eq!(as_fn_mut(&mut t, (18, 3)), 6); + let as_fn_once = >::call_once; + assert_eq!(as_fn_once(t, (24, 3)), 8); +} + +fn assert_panics(f: F) where F: FnOnce() { + let f = panic::AssertUnwindSafe(f); + let result = panic::catch_unwind(move || { + f.0() + }); + if let Ok(..) = result { + panic!("diverging function returned"); + } +} + +fn test_fn_ptr_panic(mut t: T) + where T: Fn() -> ! +{ + let as_fn = >::call; + assert_panics(|| as_fn(&t, ())); + let as_fn_mut = >::call_mut; + assert_panics(|| as_fn_mut(&mut t, ())); + let as_fn_once = >::call_once; + assert_panics(|| as_fn_once(t, ())); +} + +fn main() { + test_fn_ptr(foo); + test_fn_ptr(foo as fn(u32, u32) -> u32); + test_fn_ptr_panic(foo_diverges); + test_fn_ptr_panic(foo_diverges as fn() -> !); +} From aac5ba5dab758803b06add74457eba03bbbd9930 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Mar 2017 01:41:26 +0200 Subject: [PATCH 106/662] resolve instances to ty::Instance directly This removes the duplication between collector, callee, and (eventually) MIRI. --- src/librustc/traits/mod.rs | 2 +- src/librustc/traits/specialize/mod.rs | 25 ++- src/librustc/ty/context.rs | 9 + src/librustc/ty/instance.rs | 34 +++- src/librustc/ty/util.rs | 2 - src/librustc_mir/shim.rs | 1 + src/librustc_trans/base.rs | 24 +-- src/librustc_trans/callee.rs | 186 ++++--------------- src/librustc_trans/collector.rs | 235 ++++++----------------- src/librustc_trans/common.rs | 82 +-------- src/librustc_trans/glue.rs | 20 +- src/librustc_trans/lib.rs | 1 + src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/monomorphize.rs | 256 ++++++++++++++++++++++++-- src/librustc_trans/partitioning.rs | 5 +- 15 files changed, 389 insertions(+), 495 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 7e7d06e4b814e..c71fc28b4d6b3 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs}; -pub use self::specialize::{SpecializesCache, find_method}; +pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::util::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 2c99ee21b0f73..50a4d982832ac 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -29,8 +29,6 @@ use traits::{self, Reveal, ObligationCause}; use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; -use syntax::ast; - pub mod specialization_graph; /// Information pertinent to an overlapping impl error. @@ -106,22 +104,23 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } /// Given a selected impl described by `impl_data`, returns the -/// definition and substitions for the method with the name `name`, -/// and trait method substitutions `substs`, in that impl, a less -/// specialized impl, or the trait default, whichever applies. -pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - name: ast::Name, - substs: &'tcx Substs<'tcx>, - impl_data: &super::VtableImplData<'tcx, ()>) - -> (DefId, &'tcx Substs<'tcx>) -{ +/// definition and substitions for the method with the name `name` +/// the kind `kind`, and trait method substitutions `substs`, in +/// that impl, a less specialized impl, or the trait default, +/// whichever applies. +pub fn find_associated_item<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item: &ty::AssociatedItem, + substs: &'tcx Substs<'tcx>, + impl_data: &super::VtableImplData<'tcx, ()>, +) -> (DefId, &'tcx Substs<'tcx>) { assert!(!substs.needs_infer()); let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); let trait_def = tcx.lookup_trait_def(trait_def_id); let ancestors = trait_def.ancestors(impl_data.impl_def_id); - match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() { + match ancestors.defs(tcx, item.name, item.kind).next() { Some(node_item) => { let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); @@ -137,7 +136,7 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (node_item.item.def_id, substs) } None => { - bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id) + bug!("{:?} not found in {:?}", item, impl_data.impl_def_id) } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a0aeb4107c156..5543223105b44 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1469,6 +1469,15 @@ impl InternIteratorElement for T { } } +impl<'a, T, R> InternIteratorElement for &'a T + where T: Clone + 'a +{ + type Output = R; + fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { + f(&iter.cloned().collect::>()) + } +} + impl InternIteratorElement for Result { type Output = Result; fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index fdcfb3ebd3ce5..d93482acbcb57 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -27,8 +27,17 @@ pub struct Instance<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum InstanceDef<'tcx> { Item(DefId), + Intrinsic(DefId), // ::call_* + // def-id is FnTrait::call_* FnPtrShim(DefId, Ty<'tcx>), + // ::fn + Virtual(DefId, usize), + // <[mut closure] as FnOnce>::call_once + ClosureOnceShim { + call_once: DefId, + closure_did: DefId + }, } impl<'tcx> InstanceDef<'tcx> { @@ -36,8 +45,12 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id(&self) -> DefId { match *self { InstanceDef::Item(def_id) | - InstanceDef::FnPtrShim(def_id, _) - => def_id + InstanceDef::FnPtrShim(def_id, _) | + InstanceDef::Virtual(def_id, _) | + InstanceDef::Intrinsic(def_id, ) | + InstanceDef::ClosureOnceShim { + call_once: def_id, closure_did: _ + } => def_id } } @@ -73,14 +86,23 @@ impl<'tcx> InstanceDef<'tcx> { impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ppaux::parameterized(f, self.substs, self.def_id(), &[])?; match self.def { - InstanceDef::Item(def) => { - ppaux::parameterized(f, self.substs, def, &[]) + InstanceDef::Item(_) => Ok(()), + InstanceDef::Intrinsic(_) => { + write!(f, " - intrinsic") } - InstanceDef::FnPtrShim(def, ty) => { - ppaux::parameterized(f, self.substs, def, &[])?; + InstanceDef::Virtual(_, num) => { + write!(f, " - shim(#{})", num) + } + InstanceDef::FnPtrShim(_, ty) => { write!(f, " - shim({:?})", ty) } + InstanceDef::ClosureOnceShim { + call_once: _, closure_did + } => { + write!(f, " - shim({:?})", closure_did) + } } } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2344305fa9a7e..1d816d342c4fd 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -408,8 +408,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) } - - } pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index bf0b1796dffaf..2a053535e7e10 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -41,6 +41,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ty::InstanceDef::FnPtrShim(_, ty) => { build_fn_ptr_shim(tcx, ty, instance.def_ty(tcx)) } + _ => bug!("unknown shim kind") }; debug!("make_shim({:?}) = {:?}", instance, result); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ce767468c012b..10ab199671f64 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -36,9 +36,7 @@ use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; -use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; @@ -54,7 +52,6 @@ use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; use common::{C_struct_in_context, C_u64, C_undef}; use common::CrateContext; -use common::{fulfill_obligation}; use common::{type_is_zero_size, val_ty}; use common; use consts; @@ -80,7 +77,7 @@ use std::ffi::{CStr, CString}; use std::rc::Rc; use std::str; use std::i32; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use syntax::attr; use rustc::hir; use rustc::ty::layout::{self, Layout}; @@ -313,25 +310,6 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } } -pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>) - -> CustomCoerceUnsized { - let trait_ref = ty::Binder(ty::TraitRef { - def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), - substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) - }); - - match fulfill_obligation(scx, DUMMY_SP, trait_ref) { - traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - scx.tcx().custom_coerce_unsized_kind(impl_def_id) - } - vtable => { - bug!("invalid CoerceUnsized vtable: {:?}", vtable); - } - } -} - pub fn cast_shift_expr_rhs( cx: &Builder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef ) -> ValueRef { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 2294e8a0002e0..70da2a69ef425 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -19,13 +19,13 @@ pub use self::CalleeData::*; use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use rustc::ty::subst::{Substs, Subst}; -use rustc::traits; use abi::{Abi, FnType}; use attributes; use builder::Builder; use common::{self, CrateContext}; use cleanup::CleanupScope; use mir::lvalue::LvalueRef; +use monomorphize; use consts; use common::instance_ty; use declare; @@ -38,8 +38,6 @@ use type_of; use rustc::ty::{self, Ty, TypeFoldable}; use std::iter; -use syntax_pos::DUMMY_SP; - use mir::lvalue::Alignment; #[derive(Debug)] @@ -60,94 +58,39 @@ pub struct Callee<'tcx> { } impl<'tcx> Callee<'tcx> { - /// Function pointer. - pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> { - Callee { - data: Fn(llfn), - ty: ty - } - } - /// Function or method definition. pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Callee<'tcx> { - let tcx = ccx.tcx(); - - if let Some(trait_id) = tcx.trait_of_item(def_id) { - return Callee::trait_method(ccx, trait_id, def_id, substs); - } - - let instance = ty::Instance::new(def_id, substs); - let fn_ty = instance_ty(ccx.shared(), &instance); - if let ty::TyFnDef(.., f) = fn_ty.sty { - if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - return Callee { - data: Intrinsic, - ty: fn_ty + let instance = monomorphize::resolve(ccx.shared(), def_id, substs); + let ty = instance_ty(ccx.shared(), &instance); + let data = match instance.def { + ty::InstanceDef::Intrinsic(_) => Intrinsic, + ty::InstanceDef::ClosureOnceShim { .. } => { + let closure_ty = instance.substs.type_at(0); + let (closure_def_id, closure_substs) = match closure_ty.sty { + ty::TyClosure(def_id, substs) => (def_id, substs), + _ => bug!("bad closure instance {:?}", instance) }; - } - } - - let (llfn, ty) = get_fn(ccx, instance); - Callee::ptr(llfn, ty) - } - /// Trait method, which has to be resolved to an impl method. - pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>, - trait_id: DefId, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Callee<'tcx> { - let tcx = ccx.tcx(); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, substs); - let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref)); - match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { - traits::VtableImpl(vtable_impl) => { - let name = tcx.item_name(def_id); - let instance = common::find_method(tcx, name, substs, &vtable_impl); - - // Translate the function, bypassing Callee::def. - // That is because default methods have the same ID as the - // trait method used to look up the impl method that ended - // up here, so calling Callee::def would infinitely recurse. - let (llfn, ty) = get_fn(ccx, instance); - Callee::ptr(llfn, ty) - } - traits::VtableClosure(vtable_closure) => { - // The substitutions should have no type parameters remaining - // after passing through fulfill_obligation - let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let instance = Instance::new(def_id, substs); - let llfn = trans_closure_method( + Fn(trans_fn_once_adapter_shim( ccx, - vtable_closure.closure_def_id, - vtable_closure.substs, + closure_def_id, + closure_substs, instance, - trait_closure_kind); - - let method_ty = instance_ty(ccx.shared(), &instance); - Callee::ptr(llfn, method_ty) - } - traits::VtableFnPointer(data) => { - let instance = ty::Instance { - def: ty::InstanceDef::FnPtrShim(def_id, data.fn_ty), - substs: substs, - }; - - let (llfn, ty) = get_fn(ccx, instance); - Callee::ptr(llfn, ty) + get_fn( + ccx, + Instance::new(closure_def_id, closure_substs.substs) + ) + )) } - traits::VtableObject(ref data) => { - Callee { - data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)), - ty: instance_ty(ccx.shared(), &Instance::new(def_id, substs)) - } + ty::InstanceDef::Virtual(_, n) => Virtual(n), + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Item(..) => { + Fn(get_fn(ccx, instance)) } - vtable => { - bug!("resolved vtable bad vtable {:?} in trans", vtable); - } - } + }; + + Callee { data, ty } } /// Get the abi::FnType for a direct call. Mainly deals with the fact @@ -155,7 +98,8 @@ impl<'tcx> Callee<'tcx> { /// The extra argument types are for variadic (extern "C") functions. pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>, extra_args: &[Ty<'tcx>]) -> FnType { - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&self.ty.fn_sig()); + let sig = common::ty_fn_sig(ccx, self.ty); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); if let Virtual(_) = self.data { // Don't pass the vtable, it's not an argument of the virtual fn. @@ -175,72 +119,6 @@ impl<'tcx> Callee<'tcx> { } } -fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - trait_closure_kind: ty::ClosureKind) - -> ValueRef -{ - // If this is a closure, redirect to it. - let (llfn, _) = get_fn(ccx, Instance::new(def_id, substs.substs)); - - // If the closure is a Fn closure, but a FnOnce is needed (etc), - // then adapt the self type - let llfn_closure_kind = ccx.tcx().closure_kind(def_id); - - debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ - trait_closure_kind={:?}, llfn={:?})", - llfn_closure_kind, trait_closure_kind, Value(llfn)); - - match needs_fn_once_adapter_shim(llfn_closure_kind, trait_closure_kind) { - Ok(true) => trans_fn_once_adapter_shim(ccx, - def_id, - substs, - method_instance, - llfn), - Ok(false) => llfn, - Err(()) => { - bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", - llfn_closure_kind, - trait_closure_kind); - } - } -} - -pub fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind) - -> Result -{ - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - Ok(true) - } - _ => Err(()), - } -} - fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, def_id: DefId, @@ -307,7 +185,6 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // the first argument (`self`) will be the (by value) closure env. let mut llargs = get_params(lloncefn); - let fn_ret = callee.ty.fn_ret(); let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); let self_idx = fn_ty.ret.is_indirect() as usize; let env_arg = &orig_fn_ty.args[0]; @@ -344,7 +221,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( } fn_ty.apply_attrs_callsite(llret); - if fn_ret.0.is_never() { + if sig.output().is_never() { bcx.unreachable(); } else { self_scope.trans(&bcx); @@ -372,7 +249,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( /// - `substs`: values for each of the fn/method's parameters fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) - -> (ValueRef, Ty<'tcx>) { + -> ValueRef +{ let tcx = ccx.tcx(); debug!("get_fn(instance={:?})", instance); @@ -383,7 +261,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let fn_ty = common::instance_ty(ccx.shared(), &instance); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - return (llfn, fn_ty); + return llfn; } let sym = ccx.symbol_map().get_or_compute(ccx.shared(), @@ -455,5 +333,5 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, llfn); - (llfn, fn_ty) + llfn } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index c4239fa2ae65f..9476ffc944485 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -203,11 +203,8 @@ use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; use syntax::abi::Abi; -use syntax_pos::DUMMY_SP; -use base::custom_coerce_unsize_info; -use callee::needs_fn_once_adapter_shim; use context::SharedCrateContext; -use common::{def_ty, find_method, instance_ty, fulfill_obligation}; +use common::{def_ty, instance_ty}; use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -555,7 +552,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs); - let instance = monomorphize::resolve_const(self.scx, def_id, substs); + let instance = monomorphize::resolve(self.scx, def_id, substs); collect_neighbours(self.scx, instance, self.output); } @@ -580,32 +577,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let callee_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &callee_substs); - let dispatched = do_static_dispatch(self.scx, - callee_def_id, - callee_substs); - - if let StaticDispatchResult::Dispatched { - instance, fn_once_adjustment - } = dispatched { - // if we have a concrete impl (which we might not have - // in the case of something compiler generated like an - // object shim or a closure that is handled differently), - // we check if the callee is something that will actually - // result in a translation item ... - if should_trans_locally(self.scx.tcx(), &instance) { - self.output.push(create_fn_trans_item(instance)); - - // This call will instantiate an FnOnce adapter, which drops - // the closure environment. Therefore we need to make sure - // that we collect the drop-glue for the environment type. - if let Some(env_ty) = fn_once_adjustment { - let env_ty = glue::get_drop_glue_type(self.scx, env_ty); - if self.scx.type_needs_drop(env_ty) { - let dg = DropGlueKind::Ty(env_ty); - self.output.push(TransItem::DropGlue(dg)); - } + let instance = + monomorphize::resolve(self.scx, callee_def_id, callee_substs); + if should_trans_locally(self.scx.tcx(), &instance) { + if let ty::InstanceDef::ClosureOnceShim { .. } = instance.def { + // This call will instantiate an FnOnce adapter, which + // drops the closure environment. Therefore we need to + // make sure that we collect the drop-glue for the + // environment type. + + let env_ty = instance.substs.type_at(0); + let env_ty = glue::get_drop_glue_type(self.scx, env_ty); + if self.scx.type_needs_drop(env_ty) { + let dg = DropGlueKind::Ty(env_ty); + self.output.push(TransItem::DropGlue(dg)); } } + self.output.push(create_fn_trans_item(instance)); } } @@ -664,8 +652,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) -> bool { let def_id = match instance.def { - ty::InstanceDef::Item(def_id) => def_id, - ty::InstanceDef::FnPtrShim(..) => return true + ty::InstanceDef::Item(def_id) | + ty::InstanceDef::ClosureOnceShim { + call_once: _, closure_did: def_id + } => def_id, + ty::InstanceDef::FnPtrShim(..) => return true, + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::Intrinsic(_) => return false }; match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { @@ -718,31 +711,21 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // If the type implements Drop, also add a translation item for the // monomorphized Drop::drop() implementation. - let destructor = match ty.sty { - ty::TyAdt(def, _) => def.destructor(scx.tcx()), - _ => None + let has_dtor = match ty.sty { + ty::TyAdt(def, _) => def.has_dtor(scx.tcx()), + _ => false }; - if let (Some(destructor), false) = (destructor, ty.is_box()) { - use rustc::ty::ToPolyTraitRef; - + if has_dtor && !ty.is_box() { let drop_trait_def_id = scx.tcx() .lang_items .drop_trait() .unwrap(); - - let self_type_substs = scx.tcx().mk_substs_trait(ty, &[]); - - let trait_ref = ty::TraitRef { - def_id: drop_trait_def_id, - substs: self_type_substs, - }.to_poly_trait_ref(); - - let substs = match fulfill_obligation(scx, DUMMY_SP, trait_ref) { - traits::VtableImpl(data) => data.substs, - _ => bug!() - }; - let instance = Instance::new(destructor.did, substs); + let drop_method = scx.tcx().associated_items(drop_trait_def_id) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let substs = scx.tcx().mk_substs_trait(ty, &[]); + let instance = monomorphize::resolve(scx, drop_method, substs); if should_trans_locally(scx.tcx(), &instance) { output.push(create_fn_trans_item(instance)); } @@ -817,115 +800,6 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } -enum StaticDispatchResult<'tcx> { - // The call could be resolved statically as going to the method with - // `instance`. - Dispatched { - instance: Instance<'tcx>, - // If this is a call to a closure that needs an FnOnce adjustment, - // this contains the new self type of the call (= type of the closure - // environment) - fn_once_adjustment: Option>, - }, - // This goes to somewhere that we don't know at compile-time - Unknown -} - -fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - fn_def_id: DefId, - fn_substs: &'tcx Substs<'tcx>) - -> StaticDispatchResult<'tcx> { - debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?})", - def_id_to_string(scx.tcx(), fn_def_id), - fn_substs); - if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { - debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(scx, - &scx.tcx().associated_item(fn_def_id), - trait_def_id, - fn_substs) - } else { - debug!(" => regular function"); - // The function is not part of an impl or trait, no dispatching - // to be done - StaticDispatchResult::Dispatched { - instance: Instance::new(fn_def_id, fn_substs), - fn_once_adjustment: None, - } - } -} - -// Given a trait-method and substitution information, find out the actual -// implementation of the trait method. -fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - trait_method: &ty::AssociatedItem, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx>) - -> StaticDispatchResult<'tcx> { - let tcx = scx.tcx(); - debug!("do_static_trait_method_dispatch(trait_method={}, \ - trait_id={}, \ - rcvr_substs={:?})", - def_id_to_string(scx.tcx(), trait_method.def_id), - def_id_to_string(scx.tcx(), trait_id), - rcvr_substs); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - traits::VtableImpl(impl_data) => { - StaticDispatchResult::Dispatched { - instance: find_method(tcx, trait_method.name, rcvr_substs, &impl_data), - fn_once_adjustment: None, - } - } - traits::VtableClosure(closure_data) => { - let closure_def_id = closure_data.closure_def_id; - let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let actual_closure_kind = tcx.closure_kind(closure_def_id); - - let needs_fn_once_adapter_shim = - match needs_fn_once_adapter_shim(actual_closure_kind, - trait_closure_kind) { - Ok(true) => true, - _ => false, - }; - - let fn_once_adjustment = if needs_fn_once_adapter_shim { - Some(tcx.mk_closure_from_closure_substs(closure_def_id, - closure_data.substs)) - } else { - None - }; - - StaticDispatchResult::Dispatched { - instance: Instance::new(closure_def_id, closure_data.substs.substs), - fn_once_adjustment: fn_once_adjustment, - } - } - traits::VtableFnPointer(ref data) => { - StaticDispatchResult::Dispatched { - instance: Instance { - def: ty::InstanceDef::FnPtrShim(trait_method.def_id, data.fn_ty), - substs: trait_ref.substs - }, - fn_once_adjustment: None, - } - } - // Trait object shims are always instantiated in-place, and as they are - // just an ABI-adjusting indirect call they do not have any dependencies. - traits::VtableObject(..) => { - StaticDispatchResult::Unknown - } - _ => { - bug!("static call to invalid vtable: {:?}", vtbl) - } - } -} - /// For given pair of source and target type that occur in an unsizing coercion, /// this function finds the pair of types that determines the vtable linking /// them. @@ -991,7 +865,8 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, &ty::TyAdt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); - let kind = custom_coerce_unsize_info(scx, source_ty, target_ty); + let kind = + monomorphize::custom_coerce_unsize_info(scx, source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i @@ -1017,6 +892,20 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { debug!("create_fn_trans_item(instance={})", instance); + let instance = match instance.def { + ty::InstanceDef::ClosureOnceShim { .. } => { + // HACK: don't create ClosureOnce trans items for now + // have someone else generate the drop glue + let closure_ty = instance.substs.type_at(0); + match closure_ty.sty { + ty::TyClosure(def_id, substs) => { + Instance::new(def_id, substs.substs) + } + _ => bug!("bad closure instance {:?}", instance) + } + } + _ => instance + }; TransItem::Fn(instance) } @@ -1037,18 +926,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, // Walk all methods of the trait, including those of its supertraits let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); let methods = methods.filter_map(|method| method) - .filter_map(|(def_id, substs)| { - if let StaticDispatchResult::Dispatched { - instance, - // We already add the drop-glue for the closure env - // unconditionally below. - fn_once_adjustment: _ , - } = do_static_dispatch(scx, def_id, substs) { - Some(instance) - } else { - None - } - }) + .map(|(def_id, substs)| monomorphize::resolve(scx, def_id, substs)) .filter(|&instance| should_trans_locally(scx.tcx(), &instance)) .map(|instance| create_fn_trans_item(instance)); output.extend(methods); @@ -1203,18 +1081,11 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - // The substitutions we have are on the impl, so we grab - // the method type from the impl to substitute into. - let impl_substs = tcx.empty_substs_for_def_id(impl_def_id); - let impl_data = traits::VtableImplData { - impl_def_id: impl_def_id, - substs: impl_substs, - nested: vec![] - }; - let instance = find_method(tcx, method.name, callee_substs, &impl_data); + let instance = + monomorphize::resolve(scx, method.def_id, callee_substs); let predicates = tcx.item_predicates(instance.def_id()).predicates - .subst(tcx, impl_substs); + .subst(tcx, instance.substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 4389207cdf294..431325c5ec74e 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -17,7 +17,6 @@ use llvm::{ValueRef, ContextRef, TypeKind}; use llvm::{True, False, Bool, OperandBundleDef}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; -use rustc::util::common::MemoizationMap; use middle::lang_items::LangItem; use base; use builder::Builder; @@ -30,13 +29,11 @@ use value::Value; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::Layout; use rustc::ty::subst::{Subst, Substs}; -use rustc::traits::{self, SelectionContext, Reveal}; use rustc::hir; use libc::{c_uint, c_char}; use std::iter; -use syntax::ast; use syntax::attr; use syntax::symbol::InternedString; use syntax_pos::Span; @@ -427,73 +424,6 @@ pub fn is_null(val: ValueRef) -> bool { } } -/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we -/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should -/// guarantee to us that all nested obligations *could be* resolved if we wanted to. -pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>) - -> traits::Vtable<'tcx, ()> -{ - let tcx = scx.tcx(); - - // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); - - scx.trait_cache().memoize(trait_ref, || { - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - trait_ref, trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = traits::ObligationCause::misc(span, - ast::DUMMY_NODE_ID); - let obligation = traits::Obligation::new(obligation_cause, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - tcx.sess.span_fatal(span, - "reached the recursion limit during monomorphization \ - (selection ambiguity)"); - } - Err(e) => { - span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) - }) -} - pub fn langcall(tcx: TyCtxt, span: Option, msg: &str, @@ -617,6 +547,7 @@ pub fn requests_inline<'a, 'tcx>( _ => attr::requests_inline(&tcx.get_attrs(def_id)[..]), } } + /// Given a DefId and some Substs, produces the monomorphic item type. pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, @@ -635,14 +566,3 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, let ty = instance.def.def_ty(shared.tcx()); monomorphize::apply_param_substs(shared, instance.substs, &ty) } - -pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - name: ast::Name, - substs: &'tcx Substs<'tcx>, - impl_data: &traits::VtableImplData<'tcx, ()>) - -> ty::Instance<'tcx> -{ - let (def_id, substs) = traits::find_method(tcx, name, substs, impl_data); - let substs = tcx.erase_regions(&substs); - ty::Instance::new(def_id, substs) -} diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 35ebd67b5f8c1..2eb94aa56ab50 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -39,7 +39,6 @@ use value::Value; use Disr; use builder::Builder; -use syntax_pos::DUMMY_SP; use mir::lvalue::Alignment; pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef<'tcx>) { @@ -241,8 +240,6 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi let shallow_drop = def.is_union(); let tcx = bcx.tcx(); - let def = t.ty_adt_def().unwrap(); - // Be sure to put the contents into a scope so we can use an invoke // instruction to call the user destructor but still call the field // destructors if the user destructor panics. @@ -256,17 +253,12 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi } else { CleanupScope::noop() }; - - let trait_ref = ty::Binder(ty::TraitRef { - def_id: tcx.lang_items.drop_trait().unwrap(), - substs: tcx.mk_substs_trait(t, &[]) - }); - let vtbl = match fulfill_obligation(bcx.ccx.shared(), DUMMY_SP, trait_ref) { - traits::VtableImpl(data) => data, - _ => bug!("dtor for {:?} is not an impl???", t) - }; - let dtor_did = def.destructor(tcx).unwrap().did; - let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs); + let drop_trait_def_id = tcx.lang_items.drop_trait().unwrap(); + let drop_method = tcx.associated_items(drop_trait_def_id) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let self_type_substs = tcx.mk_substs_trait(t, &[]); + let callee = Callee::def(bcx.ccx, drop_method, self_type_substs); let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); let llret; let args = &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize]; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 1530fcda3d3ea..49cc0b5fad401 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -28,6 +28,7 @@ #![feature(box_syntax)] #![feature(const_fn)] #![feature(custom_attribute)] +#![cfg_attr(stage0, feature(field_init_shorthand))] #![allow(unused_attributes)] #![feature(i128_type)] #![feature(libc)] diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index deb1073cf9aed..69009ab356044 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -249,7 +249,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { substs: &'tcx Substs<'tcx>, args: IndexVec>) -> Result, ConstEvalErr<'tcx>> { - let instance = monomorphize::resolve_const(ccx.shared(), def_id, substs); + let instance = monomorphize::resolve(ccx.shared(), def_id, substs); let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 3b746af275a2a..bf073d8b97844 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,38 +8,260 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use abi::Abi; use common::*; + use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; -use rustc::traits; +use rustc::traits::{self, SelectionContext, Reveal}; +use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::ty::fold::{TypeFolder, TypeFoldable}; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::common::MemoizationMap; -use syntax::codemap::DUMMY_SP; +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; pub use rustc::ty::Instance; -/// For associated constants from traits, return the impl definition. -pub fn resolve_const<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx> +fn fn_once_adapter_instance<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + closure_did: DefId, + substs: ty::ClosureSubsts<'tcx>, + ) -> Instance<'tcx> { + debug!("fn_once_adapter_shim({:?}, {:?})", + closure_did, + substs); + let fn_once = tcx.lang_items.fn_once_trait().unwrap(); + let call_once = tcx.associated_items(fn_once) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let def = ty::InstanceDef::ClosureOnceShim { call_once, closure_did }; + + let self_ty = tcx.mk_closure_from_closure_substs( + closure_did, substs); + + let sig = tcx.closure_type(closure_did).subst(tcx, substs.substs); + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + assert_eq!(sig.inputs().len(), 1); + let substs = tcx.mk_substs([ + Kind::from(self_ty), + Kind::from(sig.inputs()[0]), + ].iter().cloned()); + + debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); + Instance { def, substs } +} + +/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we +/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should +/// guarantee to us that all nested obligations *could be* resolved if we wanted to. +fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>) + -> traits::Vtable<'tcx, ()> +{ + let tcx = scx.tcx(); + + // Remove any references to regions; this helps improve caching. + let trait_ref = tcx.erase_regions(&trait_ref); + + scx.trait_cache().memoize(trait_ref, || { + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + trait_ref, trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + tcx.infer_ctxt((), Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = traits::ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = traits::Obligation::new(obligation_cause, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + tcx.sess.span_fatal(span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = traits::FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) + }) +} + +fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind) + -> Result +{ + match (actual_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + Ok(true) + } + _ => Err(()), + } +} + +fn resolve_associated_item<'a, 'tcx>( + scx: &SharedCrateContext<'a, 'tcx>, + trait_item: &ty::AssociatedItem, + trait_id: DefId, + rcvr_substs: &'tcx Substs<'tcx> ) -> Instance<'tcx> { - if let Some(trait_id) = scx.tcx().trait_of_item(def_id) { - let trait_ref = ty::TraitRef::new(trait_id, substs); - let trait_ref = ty::Binder(trait_ref); - let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref); - if let traits::VtableImpl(vtable_impl) = vtable { - let name = scx.tcx().item_name(def_id); - let ac = scx.tcx().associated_items(vtable_impl.impl_def_id) - .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); - if let Some(ac) = ac { - return Instance::new(ac.def_id, vtable_impl.substs); + let tcx = scx.tcx(); + let def_id = trait_item.def_id; + debug!("resolve_associated_item(trait_item={:?}, \ + trait_id={:?}, \ + rcvr_substs={:?})", + def_id, trait_id, rcvr_substs); + + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); + let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); + + // Now that we know which impl is being used, we can dispatch to + // the actual function: + match vtbl { + traits::VtableImpl(impl_data) => { + let (def_id, substs) = traits::find_associated_item( + tcx, trait_item, rcvr_substs, &impl_data); + let substs = tcx.erase_regions(&substs); + ty::Instance::new(def_id, substs) + } + traits::VtableClosure(closure_data) => { + let closure_def_id = closure_data.closure_def_id; + let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); + let actual_closure_kind = tcx.closure_kind(closure_def_id); + + match needs_fn_once_adapter_shim(actual_closure_kind, + trait_closure_kind) { + Ok(true) => fn_once_adapter_instance( + tcx, closure_def_id, closure_data.substs), + _ => Instance::new(closure_def_id, closure_data.substs.substs), + } + } + traits::VtableFnPointer(ref data) => { + Instance { + def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), + substs: rcvr_substs + } + } + traits::VtableObject(ref data) => { + let index = tcx.get_vtable_index_of_object_method(data, def_id); + Instance { + def: ty::InstanceDef::Virtual(def_id, index), + substs: rcvr_substs } } + _ => { + bug!("static call to invalid vtable: {:?}", vtbl) + } } +} - Instance::new(def_id, substs) +/// The point where linking happens. Resolve a (def_id, substs) +/// pair to an instance. +pub fn resolve<'a, 'tcx>( + scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx> +) -> Instance<'tcx> { + debug!("resolve(def_id={:?}, substs={:?})", + def_id, substs); + let result = if let Some(trait_def_id) = scx.tcx().trait_of_item(def_id) { + debug!(" => associated item, attempting to find impl"); + let item = scx.tcx().associated_item(def_id); + resolve_associated_item(scx, &item, trait_def_id, substs) + } else { + let item_type = def_ty(scx, def_id, substs); + let def = match item_type.sty { + ty::TyFnDef(_, _, f) if + f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic => + { + debug!(" => intrinsic"); + ty::InstanceDef::Intrinsic(def_id) + } + _ => { + debug!(" => free item"); + ty::InstanceDef::Item(def_id) + } + }; + Instance { def, substs } + }; + debug!("resolve(def_id={:?}, substs={:?}) = {}", + def_id, substs, result); + result +} + +pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>) + -> CustomCoerceUnsized { + let trait_ref = ty::Binder(ty::TraitRef { + def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), + substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) + }); + + match fulfill_obligation(scx, DUMMY_SP, trait_ref) { + traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { + scx.tcx().custom_coerce_unsized_kind(impl_def_id) + } + vtable => { + bug!("invalid CoerceUnsized vtable: {:?}", vtable); + } + } } /// Monomorphizes a type from the AST by first applying the in-scope diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 1232c6cd28e52..d0cf32508d44c 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -458,7 +458,10 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't TransItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, - ty::InstanceDef::FnPtrShim(..) => return None + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::ClosureOnceShim { .. } | + ty::InstanceDef::Intrinsic(..) | + ty::InstanceDef::Virtual(..) => return None }; // If this is a method, we want to put it into the same module as From 65a4266f1f4ce9dac5a6ef588443b7cac911d265 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Mar 2017 18:33:21 +0200 Subject: [PATCH 107/662] refactor away callee::Callee and translate virtual calls through a MIR shim These changes are in the same commit to avoid needing to adapt meth::trans_object_shim to the new scheme. One codegen-units test is broken because we instantiate the shims even when they are not needed. This will be fixed in the next PR. --- src/librustc_mir/lib.rs | 1 + src/librustc_mir/mir_map.rs | 5 +- src/librustc_mir/shim.rs | 213 ++++++++++++++++++----------- src/librustc_trans/abi.rs | 31 ++++- src/librustc_trans/base.rs | 8 +- src/librustc_trans/callee.rs | 150 +++++++------------- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/context.rs | 6 +- src/librustc_trans/glue.rs | 20 +-- src/librustc_trans/meth.rs | 78 +---------- src/librustc_trans/mir/block.rs | 156 +++++++++++---------- src/librustc_trans/mir/constant.rs | 8 +- src/librustc_trans/mir/rvalue.rs | 13 +- 13 files changed, 324 insertions(+), 367 deletions(-) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 9e6b77dbabdef..2718a0204a1ed 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] #![feature(box_syntax)] +#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(i128_type)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 3fa7131a2b6b0..2d2b90235ca3b 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -252,12 +252,9 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> Ty<'tcx> { let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id); - // We're just hard-coding the idea that the signature will be - // &self or &mut self and hence will have a bound region with - // number 0, hokey. let region = ty::Region::ReFree(ty::FreeRegion { scope: tcx.region_maps.item_extent(body_id.node_id), - bound_region: ty::BoundRegion::BrAnon(0), + bound_region: ty::BoundRegion::BrEnv, }); let region = tcx.mk_region(region); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 2a053535e7e10..97c83c7a42e28 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -9,17 +9,19 @@ // except according to those terms. use rustc::hir; +use rustc::hir::def_id::DefId; use rustc::infer; +use rustc::middle::region::ROOT_CODE_EXTENT; use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::ty::{self, Ty}; +use rustc::ty::subst::Subst; use rustc::ty::maps::Providers; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use syntax::abi::Abi; use syntax::ast; -use syntax::codemap::DUMMY_SP; use syntax_pos::Span; use std::cell::RefCell; @@ -35,11 +37,51 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, -> &'tcx RefCell> { debug!("make_shim({:?})", instance); + let did = instance.def_id(); + let span = tcx.def_span(did); + let param_env = + tcx.construct_parameter_environment(span, did, ROOT_CODE_EXTENT); + let result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::FnPtrShim(_, ty) => { - build_fn_ptr_shim(tcx, ty, instance.def_ty(tcx)) + ty::InstanceDef::FnPtrShim(def_id, ty) => { + let trait_ = tcx.trait_of_item(def_id).unwrap(); + let adjustment = match tcx.lang_items.fn_trait_kind(trait_) { + Some(ty::ClosureKind::FnOnce) => Adjustment::Identity, + Some(ty::ClosureKind::FnMut) | + Some(ty::ClosureKind::Fn) => Adjustment::Deref, + None => bug!("fn pointer {:?} is not an fn", ty) + }; + // HACK: we need the "real" argument types for the MIR, + // but because our substs are (Self, Args), where Args + // is a tuple, we must include the *concrete* argument + // types in the MIR. They will be substituted again with + // the param-substs, but because they are concrete, this + // will not do any harm. + let sig = tcx.erase_late_bound_regions(&ty.fn_sig()); + let arg_tys = sig.inputs(); + + build_call_shim( + tcx, + ¶m_env, + def_id, + adjustment, + CallKind::Indirect, + Some(arg_tys) + ) + } + ty::InstanceDef::Virtual(def_id, _) => { + // We are translating a call back to our def-id, which + // trans::mir knows to turn to an actual virtual call. + build_call_shim( + tcx, + ¶m_env, + def_id, + Adjustment::Identity, + CallKind::Direct(def_id), + None + ) } _ => bug!("unknown shim kind") }; @@ -51,124 +93,135 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, result } +#[derive(Copy, Clone, Debug, PartialEq)] +enum Adjustment { + Identity, + Deref, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum CallKind { + Indirect, + Direct(DefId), +} + +fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl { + LocalDecl { mutability, ty, name: None, source_info: None } +} + fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) -> IndexVec> { - iter::once(LocalDecl { - mutability: Mutability::Mut, - ty: sig.output(), - name: None, - source_info: None - }).chain(sig.inputs().iter().map(|ity| LocalDecl { - mutability: Mutability::Not, - ty: *ity, - name: None, - source_info: None, - })).collect() + iter::once(temp_decl(Mutability::Mut, sig.output())) + .chain(sig.inputs().iter().map( + |ity| temp_decl(Mutability::Not, ity))) + .collect() } - -fn build_fn_ptr_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - fn_ty: Ty<'tcx>, - sig_ty: Ty<'tcx>) - -> Mir<'tcx> +/// Build a "call" shim for `def_id`. The shim calls the +/// function specified by `call_kind`, first adjusting its first +/// argument according to `rcvr_adjustment`. +/// +/// If `untuple_args` is a vec of types, the second argument of the +/// function will be untupled as these types. +fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + def_id: DefId, + rcvr_adjustment: Adjustment, + call_kind: CallKind, + untuple_args: Option<&[Ty<'tcx>]>) + -> Mir<'tcx> { - debug!("build_fn_ptr_shim(fn_ty={:?}, sig_ty={:?})", fn_ty, sig_ty); - let trait_sig = match sig_ty.sty { - ty::TyFnDef(_, _, fty) => tcx.erase_late_bound_regions(&fty), - _ => bug!("unexpected type for shim {:?}", sig_ty) - }; + debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \ + call_kind={:?}, untuple_args={:?})", + def_id, rcvr_adjustment, call_kind, untuple_args); - let self_ty = match trait_sig.inputs()[0].sty { - ty::TyParam(..) => fn_ty, - ty::TyRef(r, mt) => tcx.mk_ref(r, ty::TypeAndMut { - ty: fn_ty, - mutbl: mt.mutbl - }), - _ => bug!("unexpected self_ty {:?}", trait_sig), - }; + let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs); + // Not normalizing here without a param env. + let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); + let span = tcx.def_span(def_id); - let fn_ptr_sig = match fn_ty.sty { - ty::TyFnPtr(fty) | - ty::TyFnDef(_, _, fty) => - tcx.erase_late_bound_regions_and_normalize(&fty), - _ => bug!("non-fn-ptr {:?} in build_fn_ptr_shim", fn_ty) - }; - - let sig = tcx.mk_fn_sig( - [ - self_ty, - tcx.intern_tup(fn_ptr_sig.inputs(), false) - ].iter().cloned(), - fn_ptr_sig.output(), - false, - hir::Unsafety::Normal, - Abi::RustCall, - ); + debug!("build_call_shim: sig={:?}", sig); let local_decls = local_decls_for_sig(&sig); - let source_info = SourceInfo { - span: DUMMY_SP, - scope: ARGUMENT_VISIBILITY_SCOPE + let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; + + let rcvr_l = Lvalue::Local(Local::new(1+0)); + + let return_block_id = BasicBlock::new(1); + + let rcvr = match rcvr_adjustment { + Adjustment::Identity => Operand::Consume(rcvr_l), + Adjustment::Deref => Operand::Consume(Lvalue::Projection( + box Projection { base: rcvr_l, elem: ProjectionElem::Deref } + )) }; - let fn_ptr = Lvalue::Local(Local::new(1+0)); - let fn_ptr = match trait_sig.inputs()[0].sty { - ty::TyParam(..) => fn_ptr, - ty::TyRef(..) => Lvalue::Projection(box Projection { - base: fn_ptr, elem: ProjectionElem::Deref - }), - _ => bug!("unexpected self_ty {:?}", trait_sig), + let (callee, mut args) = match call_kind { + CallKind::Indirect => (rcvr, vec![]), + CallKind::Direct(def_id) => ( + Operand::Constant(Constant { + span: span, + ty: tcx.item_type(def_id).subst(tcx, param_env.free_substs), + literal: Literal::Item { def_id, substs: param_env.free_substs }, + }), + vec![rcvr] + ) }; - let fn_args = Local::new(1+1); - let return_block_id = BasicBlock::new(1); + if let Some(untuple_args) = untuple_args { + args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { + let arg_lv = Lvalue::Local(Local::new(1+1)); + Operand::Consume(Lvalue::Projection(box Projection { + base: arg_lv, + elem: ProjectionElem::Field(Field::new(i), *ity) + })) + })); + } else { + args.extend((1..sig.inputs().len()).map(|i| { + Operand::Consume(Lvalue::Local(Local::new(1+i))) + })); + } - // return = ADT(arg0, arg1, ...); return - let start_block = BasicBlockData { + let mut blocks = IndexVec::new(); + blocks.push(BasicBlockData { statements: vec![], terminator: Some(Terminator { source_info: source_info, kind: TerminatorKind::Call { - func: Operand::Consume(fn_ptr), - args: fn_ptr_sig.inputs().iter().enumerate().map(|(i, ity)| { - Operand::Consume(Lvalue::Projection(box Projection { - base: Lvalue::Local(fn_args), - elem: ProjectionElem::Field( - Field::new(i), *ity - ) - })) - }).collect(), - // FIXME: can we pass a Some destination for an uninhabited ty? + func: callee, + args: args, destination: Some((Lvalue::Local(RETURN_POINTER), return_block_id)), cleanup: None } }), is_cleanup: false - }; - let return_block = BasicBlockData { + }); + blocks.push(BasicBlockData { statements: vec![], terminator: Some(Terminator { source_info: source_info, kind: TerminatorKind::Return }), is_cleanup: false - }; + }); let mut mir = Mir::new( - vec![start_block, return_block].into_iter().collect(), + blocks, IndexVec::from_elem_n( - VisibilityScopeData { span: DUMMY_SP, parent_scope: None }, 1 + VisibilityScopeData { span: span, parent_scope: None }, 1 ), IndexVec::new(), sig.output(), local_decls, sig.inputs().len(), vec![], - DUMMY_SP + span ); - mir.spread_arg = Some(fn_args); + if let Abi::RustCall = sig.abi { + mir.spread_arg = Some(Local::new(sig.inputs().len())); + } mir } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 0bbe981f2f72c..710aa1fbbc6d9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace}; use base; use builder::Builder; -use common::{type_is_fat_ptr, C_uint}; +use common::{self, type_is_fat_ptr, C_uint}; use context::CrateContext; use cabi_x86; use cabi_x86_64; @@ -334,9 +334,30 @@ impl FnType { fn_ty } - pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType { + let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); + // Don't pass the vtable, it's not an argument of the virtual fn. + fn_ty.args[1].ignore(); + fn_ty.adjust_for_abi(ccx, sig); + fn_ty + } + + pub fn from_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: &ty::Instance<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType + { + let ity = common::instance_ty(ccx.shared(), instance); + let sig = common::ty_fn_sig(ccx, ity); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); + + Self::new(ccx, sig, extra_args) + } + + fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType { use self::Abi::*; let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | @@ -532,9 +553,9 @@ impl FnType { } } - pub fn adjust_for_abi<'a, 'tcx>(&mut self, - ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>) { + fn adjust_for_abi<'a, 'tcx>(&mut self, + ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>) { let abi = sig.abi; if abi == Abi::Unadjusted { return } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 10ab199671f64..a58764878a318 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -47,7 +47,7 @@ use abi; use mir::lvalue::LvalueRef; use attributes; use builder::Builder; -use callee::{Callee}; +use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; use common::{C_struct_in_context, C_u64, C_undef}; @@ -654,7 +654,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { return; } - let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx); + let main_llfn = callee::get_fn(ccx, instance); let et = ccx.sess().entry_type.get().unwrap(); match et { @@ -688,8 +688,8 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { let (start_fn, args) = if use_start_lang_item { let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem); - let empty_substs = ccx.tcx().intern_substs(&[]); - let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx); + let start_instance = Instance::mono(ccx.tcx(), start_def_id); + let start_fn = callee::get_fn(ccx, start_instance); (start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()), get_param(llfn, 0), get_param(llfn, 1)]) } else { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 70da2a69ef425..5c7be56b56dad 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -14,8 +14,6 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -pub use self::CalleeData::*; - use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use rustc::ty::subst::{Substs, Subst}; @@ -27,98 +25,17 @@ use cleanup::CleanupScope; use mir::lvalue::LvalueRef; use monomorphize; use consts; -use common::instance_ty; use declare; use value::Value; -use meth; use monomorphize::Instance; use back::symbol_names::symbol_name; use trans_item::TransItem; use type_of; -use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, TypeFoldable}; use std::iter; use mir::lvalue::Alignment; -#[derive(Debug)] -pub enum CalleeData { - /// Function pointer. - Fn(ValueRef), - - Intrinsic, - - /// Trait object found in the vtable at that index. - Virtual(usize) -} - -#[derive(Debug)] -pub struct Callee<'tcx> { - pub data: CalleeData, - pub ty: Ty<'tcx> -} - -impl<'tcx> Callee<'tcx> { - /// Function or method definition. - pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) - -> Callee<'tcx> { - let instance = monomorphize::resolve(ccx.shared(), def_id, substs); - let ty = instance_ty(ccx.shared(), &instance); - let data = match instance.def { - ty::InstanceDef::Intrinsic(_) => Intrinsic, - ty::InstanceDef::ClosureOnceShim { .. } => { - let closure_ty = instance.substs.type_at(0); - let (closure_def_id, closure_substs) = match closure_ty.sty { - ty::TyClosure(def_id, substs) => (def_id, substs), - _ => bug!("bad closure instance {:?}", instance) - }; - - Fn(trans_fn_once_adapter_shim( - ccx, - closure_def_id, - closure_substs, - instance, - get_fn( - ccx, - Instance::new(closure_def_id, closure_substs.substs) - ) - )) - } - ty::InstanceDef::Virtual(_, n) => Virtual(n), - ty::InstanceDef::FnPtrShim(..) | - ty::InstanceDef::Item(..) => { - Fn(get_fn(ccx, instance)) - } - }; - - Callee { data, ty } - } - - /// Get the abi::FnType for a direct call. Mainly deals with the fact - /// that a Virtual call doesn't take the vtable, like its shim does. - /// The extra argument types are for variadic (extern "C") functions. - pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { - let sig = common::ty_fn_sig(ccx, self.ty); - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); - let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); - if let Virtual(_) = self.data { - // Don't pass the vtable, it's not an argument of the virtual fn. - fn_ty.args[1].ignore(); - } - fn_ty.adjust_for_abi(ccx, sig); - fn_ty - } - - /// Turn the callee into a function pointer. - pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { - match self.data { - Fn(llfn) => llfn, - Virtual(_) => meth::trans_object_shim(ccx, self), - Intrinsic => bug!("intrinsic {} getting reified", self.ty) - } - } -} - fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, def_id: DefId, @@ -145,13 +62,14 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let sig = tcx.closure_type(def_id).subst(tcx, substs.substs); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); assert_eq!(sig.abi, Abi::RustCall); - let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig( + let llref_fn_sig = tcx.mk_fn_sig( iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()), sig.output(), sig.variadic, sig.unsafety, Abi::RustCall - ))); + ); + let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(llref_fn_sig)); debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", llref_fn_ty); @@ -177,15 +95,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let orig_fn_ty = fn_ty; let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block"); - let callee = Callee { - data: Fn(llreffn), - ty: llref_fn_ty - }; - // the first argument (`self`) will be the (by value) closure env. let mut llargs = get_params(lloncefn); - let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); + let fn_ty = FnType::new(ccx, llref_fn_sig, &[]); let self_idx = fn_ty.ret.is_indirect() as usize; let env_arg = &orig_fn_ty.args[0]; let env = if env_arg.is_indirect() { @@ -210,14 +123,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // to drop `self` when the body returns, or in case it unwinds. let self_scope = CleanupScope::schedule_drop_mem(&bcx, env); - let llfn = callee.reify(bcx.ccx); let llret; if let Some(landing_pad) = self_scope.landing_pad { let normal_bcx = bcx.build_sibling_block("normal-return"); - llret = bcx.invoke(llfn, &llargs[..], normal_bcx.llbb(), landing_pad, None); + llret = bcx.invoke(llreffn, &llargs[..], normal_bcx.llbb(), landing_pad, None); bcx = normal_bcx; } else { - llret = bcx.call(llfn, &llargs[..], None); + llret = bcx.call(llreffn, &llargs[..], None); } fn_ty.apply_attrs_callsite(llret); @@ -247,9 +159,9 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( /// - `ccx`: the crate context /// - `def_id`: def id of the fn or method item being referenced /// - `substs`: values for each of the fn/method's parameters -fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>) - -> ValueRef +fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: Instance<'tcx>) + -> ValueRef { let tcx = ccx.tcx(); @@ -335,3 +247,45 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } + +pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: Instance<'tcx>) + -> ValueRef +{ + match instance.def { + ty::InstanceDef::Intrinsic(_) => { + bug!("intrinsic {} getting reified", instance) + } + ty::InstanceDef::ClosureOnceShim { .. } => { + let closure_ty = instance.substs.type_at(0); + let (closure_def_id, closure_substs) = match closure_ty.sty { + ty::TyClosure(def_id, substs) => (def_id, substs), + _ => bug!("bad closure instance {:?}", instance) + }; + + trans_fn_once_adapter_shim( + ccx, + closure_def_id, + closure_substs, + instance, + do_get_fn( + ccx, + Instance::new(closure_def_id, closure_substs.substs) + ) + ) + } + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Item(..) | + ty::InstanceDef::Virtual(..) => { + do_get_fn(ccx, instance) + } + } +} + +pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> ValueRef +{ + get_fn(ccx, monomorphize::resolve(ccx.shared(), def_id, substs)) +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 9476ffc944485..2113b9b203ced 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -656,8 +656,8 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan ty::InstanceDef::ClosureOnceShim { call_once: _, closure_did: def_id } => def_id, - ty::InstanceDef::FnPtrShim(..) => return true, ty::InstanceDef::Virtual(..) | + ty::InstanceDef::FnPtrShim(..) => return true, ty::InstanceDef::Intrinsic(_) => return false }; match tcx.hir.get_if_local(def_id) { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b7381dd07dcfa..9297c0108468a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -18,7 +18,7 @@ use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; use rustc::traits; use debuginfo; -use callee::Callee; +use callee; use base; use declare; use glue::DropGlueKind; @@ -920,7 +920,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { let tcx = self.tcx(); let llfn = match tcx.lang_items.eh_personality() { Some(def_id) if !base::wants_msvc_seh(self.sess()) => { - Callee::def(self, def_id, tcx.intern_substs(&[])).reify(self) + callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])) } _ => { let name = if base::wants_msvc_seh(self.sess()) { @@ -948,7 +948,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { let tcx = self.tcx(); assert!(self.sess().target.target.options.custom_unwind_resume); if let Some(def_id) = tcx.lang_items.eh_unwind_resume() { - let llfn = Callee::def(self, def_id, tcx.intern_substs(&[])).reify(self); + let llfn = callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])); unwresume.set(Some(llfn)); return llfn; } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 2eb94aa56ab50..9a639ed21f1ac 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -24,9 +24,10 @@ use rustc::ty::{self, layout, AdtDef, AdtKind, Ty, TypeFoldable}; use rustc::ty::subst::Kind; use rustc::mir::tcx::LvalueTy; use mir::lvalue::LvalueRef; +use abi::FnType; use adt; use base::*; -use callee::Callee; +use callee::get_fn; use cleanup::CleanupScope; use common::*; use machine::*; @@ -45,11 +46,10 @@ pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef< let content_ty = ptr.ty.to_ty(bcx.tcx()); let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem); let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty))); - let callee = Callee::def(bcx.ccx, def_id, substs); + let instance = monomorphize::resolve(bcx.ccx.shared(), def_id, substs); - let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); - - let llret = bcx.call(callee.reify(bcx.ccx), + let fn_ty = FnType::from_instance(bcx.ccx, &instance, &[]); + let llret = bcx.call(get_fn(bcx.ccx, instance), &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize], None); fn_ty.apply_attrs_callsite(llret); } @@ -258,16 +258,18 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi .find(|it| it.kind == ty::AssociatedKind::Method) .unwrap().def_id; let self_type_substs = tcx.mk_substs_trait(t, &[]); - let callee = Callee::def(bcx.ccx, drop_method, self_type_substs); - let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); + let drop_instance = monomorphize::resolve( + bcx.ccx.shared(), drop_method, self_type_substs); + let fn_ty = FnType::from_instance(bcx.ccx, &drop_instance, &[]); + let llfn = get_fn(bcx.ccx, drop_instance); let llret; let args = &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize]; if let Some(landing_pad) = contents_scope.landing_pad { let normal_bcx = bcx.build_sibling_block("normal-return"); - llret = bcx.invoke(callee.reify(ccx), args, normal_bcx.llbb(), landing_pad, None); + llret = bcx.invoke(llfn, args, normal_bcx.llbb(), landing_pad, None); bcx = normal_bcx; } else { - llret = bcx.call(callee.reify(bcx.ccx), args, None); + llret = bcx.call(llfn, args, None); } fn_ty.apply_attrs_callsite(llret); contents_scope.trans(&bcx); diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index bfd9f69a92218..6b823756c8eab 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -8,20 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use attributes; -use llvm::{ValueRef, get_params}; +use llvm::ValueRef; use rustc::traits; -use callee::{Callee, CalleeData}; +use callee; use common::*; use builder::Builder; use consts; -use declare; use glue; use machine; -use monomorphize::Instance; use type_::Type; use type_of::*; -use back::symbol_names; use value::Value; use rustc::ty; @@ -42,74 +38,6 @@ pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr } -/// Generate a shim function that allows an object type like `SomeTrait` to -/// implement the type `SomeTrait`. Imagine a trait definition: -/// -/// trait SomeTrait { fn get(&self) -> i32; ... } -/// -/// And a generic bit of code: -/// -/// fn foo(t: &T) { -/// let x = SomeTrait::get; -/// x(t) -/// } -/// -/// What is the value of `x` when `foo` is invoked with `T=SomeTrait`? -/// The answer is that it is a shim function generated by this routine: -/// -/// fn shim(t: &SomeTrait) -> i32 { -/// // ... call t.get() virtually ... -/// } -/// -/// In fact, all virtual calls can be thought of as normal trait calls -/// that go through this shim function. -pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - callee: Callee<'tcx>) - -> ValueRef { - debug!("trans_object_shim({:?})", callee); - - let function_name = match callee.ty.sty { - ty::TyFnDef(def_id, substs, _) => { - let instance = Instance::new(def_id, substs); - symbol_names::symbol_name(instance, ccx.shared()) - } - _ => bug!() - }; - - let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty); - attributes::set_frame_pointer_elimination(ccx, llfn); - - let bcx = Builder::new_block(ccx, llfn, "entry-block"); - - let mut llargs = get_params(llfn); - let fn_ret = callee.ty.fn_ret(); - let fn_ty = callee.direct_fn_type(ccx, &[]); - - let fn_ptr = match callee.data { - CalleeData::Virtual(idx) => { - let fn_ptr = get_virtual_method(&bcx, - llargs.remove(fn_ty.ret.is_indirect() as usize + 1), idx); - let llty = fn_ty.llvm_type(bcx.ccx).ptr_to(); - bcx.pointercast(fn_ptr, llty) - }, - _ => bug!("trans_object_shim called with non-virtual callee"), - }; - let llret = bcx.call(fn_ptr, &llargs, None); - fn_ty.apply_attrs_callsite(llret); - - if fn_ret.0.is_never() { - bcx.unreachable(); - } else { - if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() { - bcx.ret_void(); - } else { - bcx.ret(llret); - } - } - - llfn -} - /// Creates a dynamic vtable for the given type and vtable origin. /// This is used only for objects. /// @@ -150,7 +78,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let trait_ref = trait_ref.with_self_ty(tcx, ty); let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| { opt_mth.map_or(nullptr, |(def_id, substs)| { - Callee::def(ccx, def_id, substs).reify(ccx) + callee::resolve_and_get_fn(ccx, def_id, substs) }) }); components.extend(methods); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 2f1a2c9134c39..761f6b208e747 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -16,13 +16,14 @@ use rustc::ty::{self, layout, TypeFoldable}; use rustc::mir; use abi::{Abi, FnType, ArgType}; use base::{self, Lifetime}; -use callee::{Callee, CalleeData, Fn, Intrinsic, Virtual}; +use callee; use builder::Builder; use common::{self, Funclet}; use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef}; use consts; use machine::llalign_of_min; use meth; +use monomorphize; use type_of::{self, align_of}; use glue; use type_::Type; @@ -340,9 +341,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Obtain the panic entry point. let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item); - let callee = Callee::def(bcx.ccx, def_id, - bcx.ccx.empty_substs_for_def_id(def_id)); - let llfn = callee.reify(bcx.ccx); + let instance = ty::Instance::mono(bcx.tcx(), def_id); + let llfn = callee::get_fn(bcx.ccx, instance); // Translate the actual panic invoke/call. if let Some(unwind) = cleanup { @@ -365,30 +365,30 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.trans_operand(&bcx, func); - let (mut callee, sig) = match callee.ty.sty { + let (instance, mut llfn, sig) = match callee.ty.sty { ty::TyFnDef(def_id, substs, sig) => { - (Callee::def(bcx.ccx, def_id, substs), sig) + (Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)), + None, + sig) } ty::TyFnPtr(sig) => { - (Callee { - data: Fn(callee.immediate()), - ty: callee.ty - }, sig) + (None, + Some(callee.immediate()), + sig) } _ => bug!("{} is not callable", callee.ty) }; - + let def = instance.map(|i| i.def); let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig); let abi = sig.abi; // Handle intrinsics old trans wants Expr's for, ourselves. - let intrinsic = match (&callee.ty.sty, &callee.data) { - (&ty::TyFnDef(def_id, ..), &Intrinsic) => { - Some(bcx.tcx().item_name(def_id).as_str()) - } + let intrinsic = match def { + Some(ty::InstanceDef::Intrinsic(def_id)) + => Some(bcx.tcx().item_name(def_id).as_str()), _ => None }; - let mut intrinsic = intrinsic.as_ref().map(|s| &s[..]); + let intrinsic = intrinsic.as_ref().map(|s| &s[..]); if intrinsic == Some("move_val_init") { let &(_, target) = destination.as_ref().unwrap(); @@ -412,15 +412,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let op_ty = op_arg.ty(&self.mir, bcx.tcx()); self.monomorphize(&op_ty) }).collect::>(); - let fn_ty = callee.direct_fn_type(bcx.ccx, &extra_args); + + let fn_ty = match def { + Some(ty::InstanceDef::Virtual(..)) => { + FnType::new_vtable(bcx.ccx, sig, &extra_args) + } + _ => FnType::new(bcx.ccx, sig, &extra_args) + }; if intrinsic == Some("drop_in_place") { let &(_, target) = destination.as_ref().unwrap(); - let ty = if let ty::TyFnDef(_, substs, _) = callee.ty.sty { - substs.type_at(0) - } else { - bug!("Unexpected ty: {}", callee.ty); - }; + let ty = instance.unwrap().substs.type_at(0); // Double check for necessity to drop if !bcx.ccx.shared().type_needs_drop(ty) { @@ -430,8 +432,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let drop_fn = glue::get_drop_glue(bcx.ccx, ty); let llty = fn_ty.llvm_type(bcx.ccx).ptr_to(); - callee.data = Fn(bcx.pointercast(drop_fn, llty)); - intrinsic = None; + llfn = Some(bcx.pointercast(drop_fn, llty)); } // The arguments we'll be passing. Plus one to account for outptr, if used. @@ -440,12 +441,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Prepare the return value destination let ret_dest = if let Some((ref dest, _)) = *destination { - let is_intrinsic = if let Intrinsic = callee.data { - true - } else { - false - }; - self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, is_intrinsic) + let is_intrinsic = intrinsic.is_some(); + self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, + is_intrinsic) } else { ReturnDest::Nothing }; @@ -483,52 +481,56 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let op = self.trans_operand(&bcx, arg); self.trans_argument(&bcx, op, &mut llargs, &fn_ty, - &mut idx, &mut callee.data); + &mut idx, &mut llfn, &def); } if let Some(tup) = untuple { self.trans_arguments_untupled(&bcx, tup, &mut llargs, &fn_ty, - &mut idx, &mut callee.data) + &mut idx, &mut llfn, &def) } - let fn_ptr = match callee.data { - Intrinsic => { - use intrinsic::trans_intrinsic_call; - - let (dest, llargs) = match ret_dest { - _ if fn_ty.ret.is_indirect() => { - (llargs[0], &llargs[1..]) - } - ReturnDest::Nothing => { - (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..]) - } - ReturnDest::IndirectOperand(dst, _) | - ReturnDest::Store(dst) => (dst, &llargs[..]), - ReturnDest::DirectOperand(_) => - bug!("Cannot use direct operand with an intrinsic call") - }; - - trans_intrinsic_call(&bcx, callee.ty, &fn_ty, &llargs, dest, - terminator.source_info.span); + if intrinsic.is_some() && intrinsic != Some("drop_in_place") { + use intrinsic::trans_intrinsic_call; - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - // Make a fake operand for store_return - let op = OperandRef { - val: Ref(dst, Alignment::AbiAligned), - ty: sig.output(), - }; - self.store_return(&bcx, ret_dest, fn_ty.ret, op); + let (dest, llargs) = match ret_dest { + _ if fn_ty.ret.is_indirect() => { + (llargs[0], &llargs[1..]) } - - if let Some((_, target)) = *destination { - funclet_br(self, bcx, target); - } else { - bcx.unreachable(); + ReturnDest::Nothing => { + (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..]) } + ReturnDest::IndirectOperand(dst, _) | + ReturnDest::Store(dst) => (dst, &llargs[..]), + ReturnDest::DirectOperand(_) => + bug!("Cannot use direct operand with an intrinsic call") + }; - return; + let callee_ty = common::instance_ty( + bcx.ccx.shared(), instance.as_ref().unwrap()); + trans_intrinsic_call(&bcx, callee_ty, &fn_ty, &llargs, dest, + terminator.source_info.span); + + if let ReturnDest::IndirectOperand(dst, _) = ret_dest { + // Make a fake operand for store_return + let op = OperandRef { + val: Ref(dst, Alignment::AbiAligned), + ty: sig.output(), + }; + self.store_return(&bcx, ret_dest, fn_ty.ret, op); + } + + if let Some((_, target)) = *destination { + funclet_br(self, bcx, target); + } else { + bcx.unreachable(); } - Fn(f) => f, - Virtual(_) => bug!("Virtual fn ptr not extracted") + + return; + } + + let fn_ptr = match (llfn, instance) { + (Some(llfn), _) => llfn, + (None, Some(instance)) => callee::get_fn(bcx.ccx, instance), + _ => span_bug!(span, "no llfn for call"), }; // Many different ways to call a function handled here @@ -578,16 +580,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { llargs: &mut Vec, fn_ty: &FnType, next_idx: &mut usize, - callee: &mut CalleeData) { + llfn: &mut Option, + def: &Option>) { if let Pair(a, b) = op.val { // Treat the values in a fat pointer separately. if common::type_is_fat_ptr(bcx.ccx, op.ty) { let (ptr, meta) = (a, b); if *next_idx == 0 { - if let Virtual(idx) = *callee { - let llfn = meth::get_virtual_method(bcx, meta, idx); + if let Some(ty::InstanceDef::Virtual(_, idx)) = *def { + let llmeth = meth::get_virtual_method(bcx, meta, idx); let llty = fn_ty.llvm_type(bcx.ccx).ptr_to(); - *callee = Fn(bcx.pointercast(llfn, llty)); + *llfn = Some(bcx.pointercast(llmeth, llty)); } } @@ -596,8 +599,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // We won't be checking the type again. ty: bcx.tcx().types.err }; - self.trans_argument(bcx, imm_op(ptr), llargs, fn_ty, next_idx, callee); - self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, callee); + self.trans_argument(bcx, imm_op(ptr), llargs, fn_ty, next_idx, llfn, def); + self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, llfn, def); return; } } @@ -660,7 +663,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { llargs: &mut Vec, fn_ty: &FnType, next_idx: &mut usize, - callee: &mut CalleeData) { + llfn: &mut Option, + def: &Option>) { let tuple = self.trans_operand(bcx, operand); let arg_types = match tuple.ty.sty { @@ -686,7 +690,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: val, ty: ty }; - self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee); + self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def); } } @@ -708,7 +712,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Immediate(elem), ty: ty }; - self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee); + self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def); } } Pair(a, b) => { @@ -724,7 +728,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Immediate(elem), ty: ty }; - self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee); + self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def); } } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 69009ab356044..107b0982af982 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -23,7 +23,7 @@ use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::{Kind, Substs, Subst}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use {abi, adt, base, Disr, machine}; -use callee::Callee; +use callee; use builder::Builder; use common::{self, CrateContext, const_get_elt, val_ty}; use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral}; @@ -565,8 +565,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::CastKind::ReifyFnPointer => { match operand.ty.sty { ty::TyFnDef(def_id, substs, _) => { - Callee::def(self.ccx, def_id, substs) - .reify(self.ccx) + callee::resolve_and_get_fn(self.ccx, def_id, substs) } _ => { span_bug!(span, "{} cannot be reified to a fn ptr", @@ -589,8 +588,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let input = tcx.erase_late_bound_regions_and_normalize(&input); let substs = tcx.mk_substs([operand.ty, input] .iter().cloned().map(Kind::from)); - Callee::def(self.ccx, call_once, substs) - .reify(self.ccx) + callee::resolve_and_get_fn(self.ccx, call_once, substs) } _ => { bug!("{} cannot be cast to a fn ptr", operand.ty) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index bbaf0f9d35fa6..3832c21d10a49 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -19,7 +19,7 @@ use middle::lang_items::ExchangeMallocFnLangItem; use base; use builder::Builder; -use callee::Callee; +use callee; use common::{self, val_ty, C_bool, C_null, C_uint}; use common::{C_integral}; use adt; @@ -183,8 +183,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { match operand.ty.sty { ty::TyFnDef(def_id, substs, _) => { OperandValue::Immediate( - Callee::def(bcx.ccx, def_id, substs) - .reify(bcx.ccx)) + callee::resolve_and_get_fn(bcx.ccx, def_id, substs)) } _ => { bug!("{} cannot be reified to a fn ptr", operand.ty) @@ -208,8 +207,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let substs = bcx.tcx().mk_substs([operand.ty, input] .iter().cloned().map(Kind::from)); OperandValue::Immediate( - Callee::def(bcx.ccx, call_once, substs) - .reify(bcx.ccx)) + callee::resolve_and_get_fn(bcx.ccx, call_once, substs) + ) } _ => { bug!("{} cannot be cast to a fn ptr", operand.ty) @@ -463,8 +462,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx.sess().fatal(&format!("allocation of `{}` {}", box_ty, s)); } }; - let r = Callee::def(bcx.ccx, def_id, bcx.tcx().intern_substs(&[])) - .reify(bcx.ccx); + let instance = ty::Instance::mono(bcx.tcx(), def_id); + let r = callee::get_fn(bcx.ccx, instance); let val = bcx.pointercast(bcx.call(r, &[llsize, llalign], None), llty_ptr); let operand = OperandRef { From a5e3c3d5b85e415ad2094f476d9f1ac29a48e413 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Mar 2017 21:21:27 +0200 Subject: [PATCH 108/662] collector: collect functions when they are called/reified This avoids the creation of unneeded vtable shims. --- src/librustc_trans/collector.rs | 179 +++++++++++++++----------------- 1 file changed, 86 insertions(+), 93 deletions(-) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2113b9b203ced..40a89783d91cf 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -202,7 +202,6 @@ use rustc::mir::{self, Location}; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; -use syntax::abi::Abi; use context::SharedCrateContext; use common::{def_ty, instance_ty}; use glue::{self, DropGlueKind}; @@ -486,6 +485,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } } + mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { + let fn_ty = operand.ty(self.mir, self.scx.tcx()); + let fn_ty = monomorphize::apply_param_substs( + self.scx, + self.param_substs, + &fn_ty); + visit_fn_use(self.scx, fn_ty, false, &mut self.output); + } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { let source_ty = operand.ty(self.mir, self.scx.tcx()); match source_ty.sty { @@ -537,111 +544,97 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_lvalue(lvalue, context, location); } - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - debug!("visiting operand {:?}", *operand); - - let callee = match *operand { - mir::Operand::Constant(ref constant) => { - if let ty::TyFnDef(def_id, substs, _) = constant.ty.sty { - // This is something that can act as a callee, proceed - Some((def_id, substs)) - } else { - // This is not a callee, but we still have to look for - // references to `const` items - if let mir::Literal::Item { def_id, substs } = constant.literal { - let substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs); - let instance = monomorphize::resolve(self.scx, def_id, substs); - collect_neighbours(self.scx, instance, self.output); - } + fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { + debug!("visiting constant {:?} @ {:?}", *constant, location); - None - } - } - _ => None - }; - - if let Some((callee_def_id, callee_substs)) = callee { - debug!(" => operand is callable"); - - // `callee_def_id` might refer to a trait method instead of a - // concrete implementation, so we have to find the actual - // implementation. For example, the call might look like - // - // std::cmp::partial_cmp(0i32, 1i32) - // - // Calling do_static_dispatch() here will map the def_id of - // `std::cmp::partial_cmp` to the def_id of `i32::partial_cmp` + if let ty::TyFnDef(..) = constant.ty.sty { + // function definitions are zero-sized, and only generate + // IR when they are called/reified. + self.super_constant(constant, location); + return + } - let callee_substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &callee_substs); - let instance = - monomorphize::resolve(self.scx, callee_def_id, callee_substs); - if should_trans_locally(self.scx.tcx(), &instance) { - if let ty::InstanceDef::ClosureOnceShim { .. } = instance.def { - // This call will instantiate an FnOnce adapter, which - // drops the closure environment. Therefore we need to - // make sure that we collect the drop-glue for the - // environment type. - - let env_ty = instance.substs.type_at(0); - let env_ty = glue::get_drop_glue_type(self.scx, env_ty); - if self.scx.type_needs_drop(env_ty) { - let dg = DropGlueKind::Ty(env_ty); - self.output.push(TransItem::DropGlue(dg)); - } - } - self.output.push(create_fn_trans_item(instance)); - } + if let mir::Literal::Item { def_id, substs } = constant.literal { + let substs = monomorphize::apply_param_substs(self.scx, + self.param_substs, + &substs); + let instance = monomorphize::resolve(self.scx, def_id, substs); + collect_neighbours(self.scx, instance, self.output); } - self.super_operand(operand, location); + self.super_constant(constant, location); } - // This takes care of the "drop_in_place" intrinsic for which we otherwise - // we would not register drop-glues. fn visit_terminator_kind(&mut self, block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { let tcx = self.scx.tcx(); - match *kind { - mir::TerminatorKind::Call { - func: mir::Operand::Constant(ref constant), - ref args, - .. - } => { - match constant.ty.sty { - ty::TyFnDef(def_id, _, bare_fn_ty) - if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => { - let operand_ty = args[0].ty(self.mir, tcx); - if let ty::TyRawPtr(mt) = operand_ty.sty { - let operand_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &mt.ty); - let ty = glue::get_drop_glue_type(self.scx, operand_ty); - self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); - } else { - bug!("Has the drop_in_place() intrinsic's signature changed?") - } - } - _ => { /* Nothing to do. */ } - } - } - _ => { /* Nothing to do. */ } + if let mir::TerminatorKind::Call { + ref func, + .. + } = *kind { + let callee_ty = func.ty(self.mir, tcx); + let callee_ty = monomorphize::apply_param_substs( + self.scx, self.param_substs, &callee_ty); + visit_fn_use(self.scx, callee_ty, true, &mut self.output); } self.super_terminator_kind(block, kind, location); + } +} + +fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + ty: ty::Ty<'tcx>, + is_direct_call: bool, + output: &mut Vec>) +{ + debug!("visit_fn_use({:?}, is_direct_call={:?})", ty, is_direct_call); + let (def_id, substs) = match ty.sty { + ty::TyFnDef(def_id, substs, _) => (def_id, substs), + _ => return + }; - fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - bare_fn_ty: ty::PolyFnSig<'tcx>) - -> bool { - (bare_fn_ty.abi() == Abi::RustIntrinsic || - bare_fn_ty.abi() == Abi::PlatformIntrinsic) && - tcx.item_name(def_id) == "drop_in_place" + let instance = monomorphize::resolve(scx, def_id, substs); + if !should_trans_locally(scx.tcx(), &instance) { + return + } + + match instance.def { + ty::InstanceDef::ClosureOnceShim { .. } => { + // This call will instantiate an FnOnce adapter, which + // drops the closure environment. Therefore we need to + // make sure that we collect the drop-glue for the + // environment type along with the instance. + + let env_ty = instance.substs.type_at(0); + let env_ty = glue::get_drop_glue_type(scx, env_ty); + if scx.type_needs_drop(env_ty) { + let dg = DropGlueKind::Ty(env_ty); + output.push(TransItem::DropGlue(dg)); + } + output.push(create_fn_trans_item(instance)); + } + ty::InstanceDef::Intrinsic(..) => { + if !is_direct_call { + bug!("intrinsic {:?} being reified", ty); + } + if scx.tcx().item_name(def_id) == "drop_in_place" { + // drop_in_place is a call to drop glue, need to instantiate + // that. + let ty = glue::get_drop_glue_type(scx, substs.type_at(0)); + output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); + } + } + ty::InstanceDef::Virtual(..) => { + // don't need to emit shim if we are calling directly. + if !is_direct_call { + output.push(create_fn_trans_item(instance)); + } + } + ty::InstanceDef::Item(..) | + ty::InstanceDef::FnPtrShim(..) => { + output.push(create_fn_trans_item(instance)); } } } @@ -657,8 +650,8 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan call_once: _, closure_did: def_id } => def_id, ty::InstanceDef::Virtual(..) | - ty::InstanceDef::FnPtrShim(..) => return true, - ty::InstanceDef::Intrinsic(_) => return false + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Intrinsic(_) => return true }; match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { From e1f3c67cb4e2eb1595040888e897e48c64afb4be Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Mar 2017 23:19:09 +0200 Subject: [PATCH 109/662] translate closure shims using MIR --- src/librustc/ty/instance.rs | 16 +-- src/librustc_mir/shim.rs | 121 +++++++++++++++----- src/librustc_trans/callee.rs | 173 ++--------------------------- src/librustc_trans/cleanup.rs | 18 --- src/librustc_trans/collector.rs | 43 +------ src/librustc_trans/mir/rvalue.rs | 21 +--- src/librustc_trans/monomorphize.rs | 95 ++++++++-------- src/test/run-pass/issue-29948.rs | 17 ++- 8 files changed, 183 insertions(+), 321 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index d93482acbcb57..aeb1fe079ff25 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -34,10 +34,7 @@ pub enum InstanceDef<'tcx> { // ::fn Virtual(DefId, usize), // <[mut closure] as FnOnce>::call_once - ClosureOnceShim { - call_once: DefId, - closure_did: DefId - }, + ClosureOnceShim { call_once: DefId }, } impl<'tcx> InstanceDef<'tcx> { @@ -48,9 +45,8 @@ impl<'tcx> InstanceDef<'tcx> { InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id, ) | - InstanceDef::ClosureOnceShim { - call_once: def_id, closure_did: _ - } => def_id + InstanceDef::ClosureOnceShim { call_once: def_id } + => def_id } } @@ -98,10 +94,8 @@ impl<'tcx> fmt::Display for Instance<'tcx> { InstanceDef::FnPtrShim(_, ty) => { write!(f, " - shim({:?})", ty) } - InstanceDef::ClosureOnceShim { - call_once: _, closure_did - } => { - write!(f, " - shim({:?})", closure_did) + InstanceDef::ClosureOnceShim { .. } => { + write!(f, " - shim") } } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 97c83c7a42e28..35ad296006dad 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -83,7 +83,25 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, None ) } - _ => bug!("unknown shim kind") + ty::InstanceDef::ClosureOnceShim { call_once } => { + let fn_mut = tcx.lang_items.fn_mut_trait().unwrap(); + let call_mut = tcx.global_tcx() + .associated_items(fn_mut) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + + build_call_shim( + tcx, + ¶m_env, + call_once, + Adjustment::RefMut, + CallKind::Direct(call_mut), + None + ) + } + ty::InstanceDef::Intrinsic(_) => { + bug!("creating shims from intrinsics ({:?}) is unsupported", instance) + } }; debug!("make_shim({:?}) = {:?}", instance, result); @@ -97,6 +115,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, enum Adjustment { Identity, Deref, + RefMut, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -143,18 +162,37 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, debug!("build_call_shim: sig={:?}", sig); - let local_decls = local_decls_for_sig(&sig); + let mut local_decls = local_decls_for_sig(&sig); let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; - let rcvr_l = Lvalue::Local(Local::new(1+0)); - - let return_block_id = BasicBlock::new(1); + let rcvr_arg = Local::new(1+0); + let rcvr_l = Lvalue::Local(rcvr_arg); + let mut statements = vec![]; let rcvr = match rcvr_adjustment { Adjustment::Identity => Operand::Consume(rcvr_l), Adjustment::Deref => Operand::Consume(Lvalue::Projection( box Projection { base: rcvr_l, elem: ProjectionElem::Deref } - )) + )), + Adjustment::RefMut => { + // let rcvr = &mut rcvr; + let re_erased = tcx.mk_region(ty::ReErased); + let ref_rcvr = local_decls.push(temp_decl( + Mutability::Not, + tcx.mk_ref(re_erased, ty::TypeAndMut { + ty: sig.inputs()[0], + mutbl: hir::Mutability::MutMutable + }) + )); + statements.push(Statement { + source_info: source_info, + kind: StatementKind::Assign( + Lvalue::Local(ref_rcvr), + Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l) + ) + }); + Operand::Consume(Lvalue::Local(ref_rcvr)) + } }; let (callee, mut args) = match call_kind { @@ -184,28 +222,57 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, } let mut blocks = IndexVec::new(); - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: source_info, - kind: TerminatorKind::Call { - func: callee, - args: args, - destination: Some((Lvalue::Local(RETURN_POINTER), - return_block_id)), - cleanup: None + let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { + blocks.push(BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind }), + is_cleanup + }) + }; + + let have_unwind = match (rcvr_adjustment, tcx.sess.no_landing_pads()) { + (Adjustment::RefMut, false) => true, + _ => false + }; + + // BB #0 + block(&mut blocks, statements, TerminatorKind::Call { + func: callee, + args: args, + destination: Some((Lvalue::Local(RETURN_POINTER), + BasicBlock::new(1))), + cleanup: if have_unwind { + Some(BasicBlock::new(3)) + } else { + None + } + }, false); + + if let Adjustment::RefMut = rcvr_adjustment { + // BB #1 - drop for Self + block(&mut blocks, vec![], TerminatorKind::Drop { + location: Lvalue::Local(rcvr_arg), + target: BasicBlock::new(2), + unwind: if have_unwind { + Some(BasicBlock::new(4)) + } else { + None } - }), - is_cleanup: false - }); - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: source_info, - kind: TerminatorKind::Return - }), - is_cleanup: false - }); + }, false); + } + // BB #1/#2 - return + block(&mut blocks, vec![], TerminatorKind::Return, false); + if have_unwind { + // BB #3 - drop if closure panics + block(&mut blocks, vec![], TerminatorKind::Drop { + location: Lvalue::Local(rcvr_arg), + target: BasicBlock::new(4), + unwind: None + }, true); + + // BB #4 - resume + block(&mut blocks, vec![], TerminatorKind::Resume, true); + } let mut mir = Mir::new( blocks, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 5c7be56b56dad..4d0bd9fa201d8 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -14,142 +14,18 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -use llvm::{self, ValueRef, get_params}; +use llvm::{self, ValueRef}; use rustc::hir::def_id::DefId; -use rustc::ty::subst::{Substs, Subst}; -use abi::{Abi, FnType}; +use rustc::ty::subst::Substs; use attributes; -use builder::Builder; use common::{self, CrateContext}; -use cleanup::CleanupScope; -use mir::lvalue::LvalueRef; use monomorphize; use consts; use declare; -use value::Value; use monomorphize::Instance; -use back::symbol_names::symbol_name; use trans_item::TransItem; use type_of; -use rustc::ty::{self, TypeFoldable}; -use std::iter; - -use mir::lvalue::Alignment; - -fn trans_fn_once_adapter_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - llreffn: ValueRef) - -> ValueRef -{ - if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) { - return llfn; - } - - debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})", - def_id, substs, Value(llreffn)); - - let tcx = ccx.tcx(); - - // Find a version of the closure type. Substitute static for the - // region since it doesn't really matter. - let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs); - let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty); - - // Make a version with the type of by-ref closure. - let sig = tcx.closure_type(def_id).subst(tcx, substs.substs); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - assert_eq!(sig.abi, Abi::RustCall); - let llref_fn_sig = tcx.mk_fn_sig( - iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.variadic, - sig.unsafety, - Abi::RustCall - ); - let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(llref_fn_sig)); - debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", - llref_fn_ty); - - - // Make a version of the closure type with the same arguments, but - // with argument #0 being by value. - let sig = tcx.mk_fn_sig( - iter::once(closure_ty).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.variadic, - sig.unsafety, - Abi::RustCall - ); - - let fn_ty = FnType::new(ccx, sig, &[]); - let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig)); - - // Create the by-value helper. - let function_name = symbol_name(method_instance, ccx.shared()); - let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); - attributes::set_frame_pointer_elimination(ccx, lloncefn); - - let orig_fn_ty = fn_ty; - let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block"); - - // the first argument (`self`) will be the (by value) closure env. - - let mut llargs = get_params(lloncefn); - let fn_ty = FnType::new(ccx, llref_fn_sig, &[]); - let self_idx = fn_ty.ret.is_indirect() as usize; - let env_arg = &orig_fn_ty.args[0]; - let env = if env_arg.is_indirect() { - LvalueRef::new_sized_ty(llargs[self_idx], closure_ty, Alignment::AbiAligned) - } else { - let scratch = LvalueRef::alloca(&bcx, closure_ty, "self"); - let mut llarg_idx = self_idx; - env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch.llval); - scratch - }; - - debug!("trans_fn_once_adapter_shim: env={:?}", env); - // Adjust llargs such that llargs[self_idx..] has the call arguments. - // For zero-sized closures that means sneaking in a new argument. - if env_arg.is_ignore() { - llargs.insert(self_idx, env.llval); - } else { - llargs[self_idx] = env.llval; - } - - // Call the by-ref closure body with `self` in a cleanup scope, - // to drop `self` when the body returns, or in case it unwinds. - let self_scope = CleanupScope::schedule_drop_mem(&bcx, env); - - let llret; - if let Some(landing_pad) = self_scope.landing_pad { - let normal_bcx = bcx.build_sibling_block("normal-return"); - llret = bcx.invoke(llreffn, &llargs[..], normal_bcx.llbb(), landing_pad, None); - bcx = normal_bcx; - } else { - llret = bcx.call(llreffn, &llargs[..], None); - } - fn_ty.apply_attrs_callsite(llret); - - if sig.output().is_never() { - bcx.unreachable(); - } else { - self_scope.trans(&bcx); - - if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() { - bcx.ret_void(); - } else { - bcx.ret(llret); - } - } - - ccx.instances().borrow_mut().insert(method_instance, lloncefn); - - lloncefn -} - +use rustc::ty::TypeFoldable; /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -157,11 +33,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( /// # Parameters /// /// - `ccx`: the crate context -/// - `def_id`: def id of the fn or method item being referenced -/// - `substs`: values for each of the fn/method's parameters -fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>) - -> ValueRef +/// - `instance`: the instance to be instantiated +pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: Instance<'tcx>) + -> ValueRef { let tcx = ccx.tcx(); @@ -248,40 +123,6 @@ fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } -pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>) - -> ValueRef -{ - match instance.def { - ty::InstanceDef::Intrinsic(_) => { - bug!("intrinsic {} getting reified", instance) - } - ty::InstanceDef::ClosureOnceShim { .. } => { - let closure_ty = instance.substs.type_at(0); - let (closure_def_id, closure_substs) = match closure_ty.sty { - ty::TyClosure(def_id, substs) => (def_id, substs), - _ => bug!("bad closure instance {:?}", instance) - }; - - trans_fn_once_adapter_shim( - ccx, - closure_def_id, - closure_substs, - instance, - do_get_fn( - ccx, - Instance::new(closure_def_id, closure_substs.substs) - ) - ) - } - ty::InstanceDef::FnPtrShim(..) | - ty::InstanceDef::Item(..) | - ty::InstanceDef::Virtual(..) => { - do_get_fn(ccx, instance) - } - } -} - pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) diff --git a/src/librustc_trans/cleanup.rs b/src/librustc_trans/cleanup.rs index 5d89a67d3fd80..2b2e5e85ea50d 100644 --- a/src/librustc_trans/cleanup.rs +++ b/src/librustc_trans/cleanup.rs @@ -93,24 +93,6 @@ impl<'tcx> DropValue<'tcx> { } impl<'a, 'tcx> CleanupScope<'tcx> { - /// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty` - pub fn schedule_drop_mem( - bcx: &Builder<'a, 'tcx>, val: LvalueRef<'tcx> - ) -> CleanupScope<'tcx> { - if let LvalueTy::Downcast { .. } = val.ty { - bug!("Cannot drop downcast ty yet"); - } - if !bcx.ccx.shared().type_needs_drop(val.ty.to_ty(bcx.tcx())) { - return CleanupScope::noop(); - } - let drop = DropValue { - val: val, - skip_dtor: false, - }; - - CleanupScope::new(bcx, drop) - } - /// Issue #23611: Schedules a (deep) drop of the contents of /// `val`, which is a pointer to an instance of struct/enum type /// `ty`. The scheduled code handles extracting the discriminant diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 40a89783d91cf..f076fc4710222 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -497,11 +497,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let source_ty = operand.ty(self.mir, self.scx.tcx()); match source_ty.sty { ty::TyClosure(def_id, substs) => { - let substs = monomorphize::apply_param_substs( - self.scx, self.param_substs, &substs.substs); - self.output.push(create_fn_trans_item( - Instance::new(def_id, substs) - )); + let instance = monomorphize::resolve_closure( + self.scx, def_id, substs, ty::ClosureKind::FnOnce); + self.output.push(create_fn_trans_item(instance)); } _ => bug!(), } @@ -601,20 +599,6 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } match instance.def { - ty::InstanceDef::ClosureOnceShim { .. } => { - // This call will instantiate an FnOnce adapter, which - // drops the closure environment. Therefore we need to - // make sure that we collect the drop-glue for the - // environment type along with the instance. - - let env_ty = instance.substs.type_at(0); - let env_ty = glue::get_drop_glue_type(scx, env_ty); - if scx.type_needs_drop(env_ty) { - let dg = DropGlueKind::Ty(env_ty); - output.push(TransItem::DropGlue(dg)); - } - output.push(create_fn_trans_item(instance)); - } ty::InstanceDef::Intrinsic(..) => { if !is_direct_call { bug!("intrinsic {:?} being reified", ty); @@ -632,6 +616,7 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, output.push(create_fn_trans_item(instance)); } } + ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) => { output.push(create_fn_trans_item(instance)); @@ -645,10 +630,8 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) -> bool { let def_id = match instance.def { - ty::InstanceDef::Item(def_id) | - ty::InstanceDef::ClosureOnceShim { - call_once: _, closure_did: def_id - } => def_id, + ty::InstanceDef::Item(def_id) => def_id, + ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Virtual(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::Intrinsic(_) => return true @@ -885,20 +868,6 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { debug!("create_fn_trans_item(instance={})", instance); - let instance = match instance.def { - ty::InstanceDef::ClosureOnceShim { .. } => { - // HACK: don't create ClosureOnce trans items for now - // have someone else generate the drop glue - let closure_ty = instance.substs.type_at(0); - match closure_ty.sty { - ty::TyClosure(def_id, substs) => { - Instance::new(def_id, substs.substs) - } - _ => bug!("bad closure instance {:?}", instance) - } - } - _ => instance - }; TransItem::Fn(instance) } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 3832c21d10a49..178347369c915 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -12,7 +12,6 @@ use llvm::{self, ValueRef}; use rustc::ty::{self, Ty}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::layout::Layout; -use rustc::ty::subst::{Kind, Subst}; use rustc::mir::tcx::LvalueTy; use rustc::mir; use middle::lang_items::ExchangeMallocFnLangItem; @@ -24,6 +23,7 @@ use common::{self, val_ty, C_bool, C_null, C_uint}; use common::{C_integral}; use adt; use machine; +use monomorphize; use type_::Type; use type_of; use tvec; @@ -193,22 +193,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::CastKind::ClosureFnPointer => { match operand.ty.sty { ty::TyClosure(def_id, substs) => { - // Get the def_id for FnOnce::call_once - let fn_once = bcx.tcx().lang_items.fn_once_trait().unwrap(); - let call_once = bcx.tcx() - .global_tcx().associated_items(fn_once) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap().def_id; - // Now create its substs [Closure, Tuple] - let input = bcx.tcx().closure_type(def_id) - .subst(bcx.tcx(), substs.substs).input(0); - let input = - bcx.tcx().erase_late_bound_regions_and_normalize(&input); - let substs = bcx.tcx().mk_substs([operand.ty, input] - .iter().cloned().map(Kind::from)); - OperandValue::Immediate( - callee::resolve_and_get_fn(bcx.ccx, call_once, substs) - ) + let instance = monomorphize::resolve_closure( + bcx.ccx.shared(), def_id, substs, ty::ClosureKind::FnOnce); + OperandValue::Immediate(callee::get_fn(bcx.ccx, instance)) } _ => { bug!("{} cannot be cast to a fn ptr", operand.ty) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index bf073d8b97844..0d8aa0f4bda0e 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -37,7 +37,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( let call_once = tcx.associated_items(fn_once) .find(|it| it.kind == ty::AssociatedKind::Method) .unwrap().def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once, closure_did }; + let def = ty::InstanceDef::ClosureOnceShim { call_once }; let self_ty = tcx.mk_closure_from_closure_substs( closure_did, substs); @@ -54,6 +54,54 @@ fn fn_once_adapter_instance<'a, 'tcx>( Instance { def, substs } } +fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind) + -> Result +{ + match (actual_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + Ok(true) + } + _ => Err(()), + } +} + +pub fn resolve_closure<'a, 'tcx> ( + scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + requested_kind: ty::ClosureKind) + -> Instance<'tcx> +{ + let actual_kind = scx.tcx().closure_kind(def_id); + + match needs_fn_once_adapter_shim(actual_kind, requested_kind) { + Ok(true) => fn_once_adapter_instance(scx.tcx(), def_id, substs), + _ => Instance::new(def_id, substs.substs) + } +} + /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should /// guarantee to us that all nested obligations *could be* resolved if we wanted to. @@ -121,39 +169,6 @@ fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, }) } -fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind) - -> Result -{ - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - Ok(true) - } - _ => Err(()), - } -} - fn resolve_associated_item<'a, 'tcx>( scx: &SharedCrateContext<'a, 'tcx>, trait_item: &ty::AssociatedItem, @@ -180,16 +195,9 @@ fn resolve_associated_item<'a, 'tcx>( ty::Instance::new(def_id, substs) } traits::VtableClosure(closure_data) => { - let closure_def_id = closure_data.closure_def_id; let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let actual_closure_kind = tcx.closure_kind(closure_def_id); - - match needs_fn_once_adapter_shim(actual_closure_kind, - trait_closure_kind) { - Ok(true) => fn_once_adapter_instance( - tcx, closure_def_id, closure_data.substs), - _ => Instance::new(closure_def_id, closure_data.substs.substs), - } + resolve_closure(scx, closure_data.closure_def_id, closure_data.substs, + trait_closure_kind) } traits::VtableFnPointer(ref data) => { Instance { @@ -279,7 +287,6 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, AssociatedTypeNormalizer::new(scx).fold(&substituted) } - /// Returns the normalized type of a struct field pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_substs: &Substs<'tcx>, diff --git a/src/test/run-pass/issue-29948.rs b/src/test/run-pass/issue-29948.rs index ec2b53313faa7..281dde15bd336 100644 --- a/src/test/run-pass/issue-29948.rs +++ b/src/test/run-pass/issue-29948.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::panic; + +impl<'a> panic::UnwindSafe for Foo<'a> {} +impl<'a> panic::RefUnwindSafe for Foo<'a> {} + struct Foo<'a>(&'a mut bool); impl<'a> Drop for Foo<'a> { @@ -28,5 +33,15 @@ fn main() { f(x); } assert!(ran_drop); -} + let mut ran_drop = false; + { + let x = Foo(&mut ran_drop); + let result = panic::catch_unwind(move || { + let x = move || { let _ = x; panic!() }; + f(x); + }); + assert!(result.is_err()); + } + assert!(ran_drop); +} From 2b9fea1300b515e0f8929bb3a09d4fb6fef3f0ea Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 9 Mar 2017 20:10:05 +0200 Subject: [PATCH 110/662] move the drop expansion code to rustc_mir --- .../borrowck/mir/dataflow/graphviz.rs | 3 +- .../borrowck/mir/dataflow/impls.rs | 2 +- .../borrowck/mir/elaborate_drops.rs | 727 ++++-------------- src/librustc_borrowck/borrowck/mir/mod.rs | 17 +- src/librustc_driver/pretty.rs | 3 +- src/librustc_mir/lib.rs | 4 +- src/librustc_mir/mir_map.rs | 6 +- src/librustc_mir/transform/copy_prop.rs | 2 +- src/librustc_mir/transform/dump_mir.rs | 4 +- src/librustc_mir/{ => util}/def_use.rs | 0 src/librustc_mir/util/elaborate_drops.rs | 561 ++++++++++++++ src/librustc_mir/{ => util}/graphviz.rs | 0 src/librustc_mir/util/mod.rs | 20 + .../mir => librustc_mir/util}/patch.rs | 0 src/librustc_mir/{ => util}/pretty.rs | 0 15 files changed, 728 insertions(+), 621 deletions(-) rename src/librustc_mir/{ => util}/def_use.rs (100%) create mode 100644 src/librustc_mir/util/elaborate_drops.rs rename src/librustc_mir/{ => util}/graphviz.rs (100%) create mode 100644 src/librustc_mir/util/mod.rs rename src/{librustc_borrowck/borrowck/mir => librustc_mir/util}/patch.rs (100%) rename src/librustc_mir/{ => util}/pretty.rs (100%) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index b15c1873f9bd8..7f95f07f48d4a 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -15,6 +15,7 @@ use rustc::mir::{BasicBlock, Mir}; use rustc_data_structures::bitslice::bits_to_string; use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; +use rustc_mir::util as mir_util; use dot; use dot::IntoCow; @@ -219,7 +220,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> } Ok(()) } - ::rustc_mir::graphviz::write_node_label( + mir_util::write_graphviz_node_label( *n, self.mbcx.mir(), &mut v, 4, |w| { let flow = self.mbcx.flow_state(); diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 7888a56d39dfb..da8aa231ccf15 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -14,10 +14,10 @@ use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usiz use rustc_data_structures::bitslice::{BitwiseOperator}; use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; +use rustc_mir::util::elaborate_drops::DropFlagState; use super::super::gather_moves::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex}; use super::super::MoveDataParamEnv; -use super::super::DropFlagState; use super::super::drop_flag_effects_for_function_entry; use super::super::drop_flag_effects_for_location; use super::super::on_lookup_result_bits; diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index a71d23e7e1e7e..88ec86cc95d61 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -13,22 +13,20 @@ use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; use super::{drop_flag_effects_for_location, on_all_children_bits}; use super::on_lookup_result_bits; -use super::{DropFlagState, MoveDataParamEnv}; -use super::patch::MirPatch; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::ty::util::IntTypeExt; +use super::MoveDataParamEnv; +use rustc::ty::{self, TyCtxt}; use rustc::mir::*; use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; -use rustc::middle::lang_items; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; +use rustc_mir::util::patch::MirPatch; +use rustc_mir::util::elaborate_drops::{DropFlagState, elaborate_drop}; +use rustc_mir::util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode}; use syntax_pos::Span; use std::fmt; -use std::iter; use std::u32; pub struct ElaborateDrops; @@ -109,12 +107,116 @@ impl InitializationData { } } -impl fmt::Debug for InitializationData { +struct Elaborator<'a, 'b: 'a, 'tcx: 'b> { + init_data: &'a InitializationData, + ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, +} + +impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> { fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> { Ok(()) } } +impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { + type Path = MovePathIndex; + + fn patch(&mut self) -> &mut MirPatch<'tcx> { + &mut self.ctxt.patch + } + + fn mir(&self) -> &'a Mir<'tcx> { + self.ctxt.mir + } + + fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + self.ctxt.tcx + } + + fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx> { + self.ctxt.param_env() + } + + fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { + let ((maybe_live, maybe_dead), multipart) = match mode { + DropFlagMode::Shallow => (self.init_data.state(path), false), + DropFlagMode::Deep => { + let mut some_live = false; + let mut some_dead = false; + let mut children_count = 0; + on_all_children_bits( + self.tcx(), self.mir(), self.ctxt.move_data(), + path, |child| { + if self.ctxt.path_needs_drop(child) { + let (live, dead) = self.init_data.state(child); + debug!("elaborate_drop: state({:?}) = {:?}", + child, (live, dead)); + some_live |= live; + some_dead |= dead; + children_count += 1; + } + }); + ((some_live, some_dead), children_count != 1) + } + }; + match (maybe_live, maybe_dead, multipart) { + (false, _, _) => DropStyle::Dead, + (true, false, _) => DropStyle::Static, + (true, true, false) => DropStyle::Conditional, + (true, true, true) => DropStyle::Open, + } + } + + fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) { + match mode { + DropFlagMode::Shallow => { + self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent); + } + DropFlagMode::Deep => { + on_all_children_bits( + self.tcx(), self.mir(), self.ctxt.move_data(), path, + |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent) + ); + } + } + } + + fn field_subpath(&self, path: Self::Path, field: Field) -> Option { + super::move_path_children_matching(self.ctxt.move_data(), path, |p| { + match p { + &Projection { + elem: ProjectionElem::Field(idx, _), .. + } => idx == field, + _ => false + } + }) + } + + fn deref_subpath(&self, path: Self::Path) -> Option { + super::move_path_children_matching(self.ctxt.move_data(), path, |p| { + match p { + &Projection { elem: ProjectionElem::Deref, .. } => true, + _ => false + } + }) + } + + fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option { + super::move_path_children_matching(self.ctxt.move_data(), path, |p| { + match p { + &Projection { + elem: ProjectionElem::Downcast(_, idx), .. + } => idx == variant, + _ => false + } + }) + } + + fn get_drop_flag(&mut self, path: Self::Path) -> Option> { + self.ctxt.drop_flag(path).map(Operand::Consume) + } +} + struct ElaborateDropsCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, @@ -125,19 +227,6 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> { patch: MirPatch<'tcx>, } -#[derive(Copy, Clone, Debug)] -struct DropCtxt<'a, 'tcx: 'a> { - source_info: SourceInfo, - is_cleanup: bool, - - init_data: &'a InitializationData, - - lvalue: &'a Lvalue<'tcx>, - path: MovePathIndex, - succ: BasicBlock, - unwind: Option -} - impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn move_data(&self) -> &'b MoveData<'tcx> { &self.env.move_data } fn param_env(&self) -> &'b ty::ParameterEnvironment<'tcx> { @@ -254,19 +343,22 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let init_data = self.initialization_data_at(loc); match self.move_data().rev_lookup.find(location) { LookupResult::Exact(path) => { - self.elaborate_drop(&DropCtxt { - source_info: terminator.source_info, - is_cleanup: data.is_cleanup, - init_data: &init_data, - lvalue: location, - path: path, - succ: target, - unwind: if data.is_cleanup { + elaborate_drop( + &mut Elaborator { + init_data: &init_data, + ctxt: self + }, + terminator.source_info, + data.is_cleanup, + location, + path, + target, + if data.is_cleanup { None } else { Some(Option::unwrap_or(unwind, resume_block)) - } - }, bb); + }, + bb) } LookupResult::Parent(..) => { span_bug!(terminator.source_info.span, @@ -343,15 +435,18 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); let init_data = self.initialization_data_at(loc); - self.elaborate_drop(&DropCtxt { - source_info: terminator.source_info, - is_cleanup: data.is_cleanup, - init_data: &init_data, - lvalue: location, - path: path, - succ: target, - unwind: Some(unwind) - }, bb); + elaborate_drop( + &mut Elaborator { + init_data: &init_data, + ctxt: self + }, + terminator.source_info, + data.is_cleanup, + location, + path, + target, + Some(unwind), + bb); on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { self.set_drop_flag(Location { block: target, statement_index: 0 }, child, DropFlagState::Present); @@ -372,547 +467,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } - /// This elaborates a single drop instruction, located at `bb`, and - /// patches over it. - /// - /// The elaborated drop checks the drop flags to only drop what - /// is initialized. - /// - /// In addition, the relevant drop flags also need to be cleared - /// to avoid double-drops. However, in the middle of a complex - /// drop, one must avoid clearing some of the flags before they - /// are read, as that would cause a memory leak. - /// - /// In particular, when dropping an ADT, multiple fields may be - /// joined together under the `rest` subpath. They are all controlled - /// by the primary drop flag, but only the last rest-field dropped - /// should clear it (and it must also not clear anything else). - /// - /// FIXME: I think we should just control the flags externally - /// and then we do not need this machinery. - fn elaborate_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, bb: BasicBlock) { - debug!("elaborate_drop({:?})", c); - - let mut some_live = false; - let mut some_dead = false; - let mut children_count = 0; - on_all_children_bits( - self.tcx, self.mir, self.move_data(), - c.path, |child| { - if self.path_needs_drop(child) { - let (live, dead) = c.init_data.state(child); - debug!("elaborate_drop: state({:?}) = {:?}", - child, (live, dead)); - some_live |= live; - some_dead |= dead; - children_count += 1; - } - }); - - debug!("elaborate_drop({:?}): live - {:?}", c, - (some_live, some_dead)); - match (some_live, some_dead) { - (false, false) | (false, true) => { - // dead drop - patch it out - self.patch.patch_terminator(bb, TerminatorKind::Goto { - target: c.succ - }); - } - (true, false) => { - // static drop - just set the flag - self.patch.patch_terminator(bb, TerminatorKind::Drop { - location: c.lvalue.clone(), - target: c.succ, - unwind: c.unwind - }); - self.drop_flags_for_drop(c, bb); - } - (true, true) => { - // dynamic drop - let drop_bb = if children_count == 1 || self.must_complete_drop(c) { - self.conditional_drop(c) - } else { - self.open_drop(c) - }; - self.patch.patch_terminator(bb, TerminatorKind::Goto { - target: drop_bb - }); - } - } - } - - /// Return the lvalue and move path for each field of `variant`, - /// (the move path is `None` if the field is a rest field). - fn move_paths_for_fields(&self, - base_lv: &Lvalue<'tcx>, - variant_path: MovePathIndex, - variant: &'tcx ty::VariantDef, - substs: &'tcx Substs<'tcx>) - -> Vec<(Lvalue<'tcx>, Option)> - { - variant.fields.iter().enumerate().map(|(i, f)| { - let subpath = - super::move_path_children_matching(self.move_data(), variant_path, |p| { - match p { - &Projection { - elem: ProjectionElem::Field(idx, _), .. - } => idx.index() == i, - _ => false - } - }); - - let field_ty = - self.tcx.normalize_associated_type_in_env( - &f.ty(self.tcx, substs), - self.param_env() - ); - (base_lv.clone().field(Field::new(i), field_ty), subpath) - }).collect() - } - - /// Create one-half of the drop ladder for a list of fields, and return - /// the list of steps in it in reverse order. - /// - /// `unwind_ladder` is such a list of steps in reverse order, - /// which is called instead of the next step if the drop unwinds - /// (the first field is never reached). If it is `None`, all - /// unwind targets are left blank. - fn drop_halfladder<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - unwind_ladder: Option>, - succ: BasicBlock, - fields: &[(Lvalue<'tcx>, Option)], - is_cleanup: bool) - -> Vec - { - let mut unwind_succ = if is_cleanup { - None - } else { - c.unwind - }; - - let mut succ = self.new_block( - c, c.is_cleanup, TerminatorKind::Goto { target: succ } - ); - - // Always clear the "master" drop flag at the bottom of the - // ladder. This is needed because the "master" drop flag - // protects the ADT's discriminant, which is invalidated - // after the ADT is dropped. - self.set_drop_flag( - Location { block: succ, statement_index: 0 }, - c.path, - DropFlagState::Absent - ); - - fields.iter().rev().enumerate().map(|(i, &(ref lv, path))| { - succ = if let Some(path) = path { - debug!("drop_ladder: for std field {} ({:?})", i, lv); - - self.elaborated_drop_block(&DropCtxt { - source_info: c.source_info, - is_cleanup: is_cleanup, - init_data: c.init_data, - lvalue: lv, - path: path, - succ: succ, - unwind: unwind_succ, - }) - } else { - debug!("drop_ladder: for rest field {} ({:?})", i, lv); - - self.complete_drop(&DropCtxt { - source_info: c.source_info, - is_cleanup: is_cleanup, - init_data: c.init_data, - lvalue: lv, - path: c.path, - succ: succ, - unwind: unwind_succ, - }, false) - }; - - unwind_succ = unwind_ladder.as_ref().map(|p| p[i]); - succ - }).collect() - } - - /// Create a full drop ladder, consisting of 2 connected half-drop-ladders - /// - /// For example, with 3 fields, the drop ladder is - /// - /// .d0: - /// ELAB(drop location.0 [target=.d1, unwind=.c1]) - /// .d1: - /// ELAB(drop location.1 [target=.d2, unwind=.c2]) - /// .d2: - /// ELAB(drop location.2 [target=`c.succ`, unwind=`c.unwind`]) - /// .c1: - /// ELAB(drop location.1 [target=.c2]) - /// .c2: - /// ELAB(drop location.2 [target=`c.unwind]) - fn drop_ladder<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - fields: Vec<(Lvalue<'tcx>, Option)>) - -> BasicBlock - { - debug!("drop_ladder({:?}, {:?})", c, fields); - - let mut fields = fields; - fields.retain(|&(ref lvalue, _)| { - let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - self.tcx.type_needs_drop_given_env(ty, self.param_env()) - }); - - debug!("drop_ladder - fields needing drop: {:?}", fields); - - let unwind_ladder = if c.is_cleanup { - None - } else { - Some(self.drop_halfladder(c, None, c.unwind.unwrap(), &fields, true)) - }; - - self.drop_halfladder(c, unwind_ladder, c.succ, &fields, c.is_cleanup) - .last().cloned().unwrap_or(c.succ) - } - - fn open_drop_for_tuple<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, tys: &[Ty<'tcx>]) - -> BasicBlock - { - debug!("open_drop_for_tuple({:?}, {:?})", c, tys); - - let fields = tys.iter().enumerate().map(|(i, &ty)| { - (c.lvalue.clone().field(Field::new(i), ty), - super::move_path_children_matching( - self.move_data(), c.path, |proj| match proj { - &Projection { - elem: ProjectionElem::Field(f, _), .. - } => f.index() == i, - _ => false - } - )) - }).collect(); - - self.drop_ladder(c, fields) - } - - fn open_drop_for_box<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, ty: Ty<'tcx>) - -> BasicBlock - { - debug!("open_drop_for_box({:?}, {:?})", c, ty); - - let interior_path = super::move_path_children_matching( - self.move_data(), c.path, |proj| match proj { - &Projection { elem: ProjectionElem::Deref, .. } => true, - _ => false - }).unwrap(); - - let interior = c.lvalue.clone().deref(); - let inner_c = DropCtxt { - lvalue: &interior, - unwind: c.unwind.map(|u| { - self.box_free_block(c, ty, u, true) - }), - succ: self.box_free_block(c, ty, c.succ, c.is_cleanup), - path: interior_path, - ..*c - }; - - self.elaborated_drop_block(&inner_c) - } - - fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>, - adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) - -> BasicBlock { - debug!("open_drop_for_adt({:?}, {:?}, {:?})", c, adt, substs); - - match adt.variants.len() { - 1 => { - let fields = self.move_paths_for_fields( - c.lvalue, - c.path, - &adt.variants[0], - substs - ); - self.drop_ladder(c, fields) - } - _ => { - let mut values = Vec::with_capacity(adt.variants.len()); - let mut blocks = Vec::with_capacity(adt.variants.len()); - let mut otherwise = None; - for (variant_index, discr) in adt.discriminants(self.tcx).enumerate() { - let subpath = super::move_path_children_matching( - self.move_data(), c.path, |proj| match proj { - &Projection { - elem: ProjectionElem::Downcast(_, idx), .. - } => idx == variant_index, - _ => false - }); - if let Some(variant_path) = subpath { - let base_lv = c.lvalue.clone().elem( - ProjectionElem::Downcast(adt, variant_index) - ); - let fields = self.move_paths_for_fields( - &base_lv, - variant_path, - &adt.variants[variant_index], - substs); - values.push(discr); - blocks.push(self.drop_ladder(c, fields)); - } else { - // variant not found - drop the entire enum - if let None = otherwise { - otherwise = Some(self.complete_drop(c, true)); - } - } - } - if let Some(block) = otherwise { - blocks.push(block); - } else { - values.pop(); - } - // If there are multiple variants, then if something - // is present within the enum the discriminant, tracked - // by the rest path, must be initialized. - // - // Additionally, we do not want to switch on the - // discriminant after it is free-ed, because that - // way lies only trouble. - let discr_ty = adt.repr.discr_type().to_ty(self.tcx); - let discr = Lvalue::Local(self.patch.new_temp(discr_ty)); - let switch_block = self.patch.new_block(BasicBlockData { - statements: vec![ - Statement { - source_info: c.source_info, - kind: StatementKind::Assign(discr.clone(), - Rvalue::Discriminant(c.lvalue.clone())) - } - ], - terminator: Some(Terminator { - source_info: c.source_info, - kind: TerminatorKind::SwitchInt { - discr: Operand::Consume(discr), - switch_ty: discr_ty, - values: From::from(values), - targets: blocks, - } - }), - is_cleanup: c.is_cleanup, - }); - self.drop_flag_test_block(c, switch_block) - } - } - } - - /// The slow-path - create an "open", elaborated drop for a type - /// which is moved-out-of only partially, and patch `bb` to a jump - /// to it. This must not be called on ADTs with a destructor, - /// as these can't be moved-out-of, except for `Box`, which is - /// special-cased. - /// - /// This creates a "drop ladder" that drops the needed fields of the - /// ADT, both in the success case or if one of the destructors fail. - fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { - let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - match ty.sty { - ty::TyClosure(def_id, substs) => { - let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect(); - self.open_drop_for_tuple(c, &tys) - } - ty::TyTuple(tys, _) => { - self.open_drop_for_tuple(c, tys) - } - ty::TyAdt(def, _) if def.is_box() => { - self.open_drop_for_box(c, ty.boxed_ty()) - } - ty::TyAdt(def, substs) => { - self.open_drop_for_adt(c, def, substs) - } - _ => bug!("open drop from non-ADT `{:?}`", ty) - } - } - - /// Return a basic block that drop an lvalue using the context - /// and path in `c`. If `update_drop_flag` is true, also - /// clear `c`. - /// - /// if FLAG(c.path) - /// if(update_drop_flag) FLAG(c.path) = false - /// drop(c.lv) - fn complete_drop<'a>( - &mut self, - c: &DropCtxt<'a, 'tcx>, - update_drop_flag: bool) - -> BasicBlock - { - debug!("complete_drop({:?},{:?})", c, update_drop_flag); - - let drop_block = self.drop_block(c); - if update_drop_flag { - self.set_drop_flag( - Location { block: drop_block, statement_index: 0 }, - c.path, - DropFlagState::Absent - ); - } - - self.drop_flag_test_block(c, drop_block) - } - - /// Create a simple conditional drop. - /// - /// if FLAG(c.lv) - /// FLAGS(c.lv) = false - /// drop(c.lv) - fn conditional_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) - -> BasicBlock - { - debug!("conditional_drop({:?})", c); - let drop_bb = self.drop_block(c); - self.drop_flags_for_drop(c, drop_bb); - - self.drop_flag_test_block(c, drop_bb) - } - - fn new_block<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - is_cleanup: bool, - k: TerminatorKind<'tcx>) - -> BasicBlock - { - self.patch.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: c.source_info, kind: k - }), - is_cleanup: is_cleanup - }) - } - - fn elaborated_drop_block<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { - debug!("elaborated_drop_block({:?})", c); - let blk = self.drop_block(c); - self.elaborate_drop(c, blk); - blk - } - - fn drop_flag_test_block<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - on_set: BasicBlock) - -> BasicBlock { - self.drop_flag_test_block_with_succ(c, c.is_cleanup, on_set, c.succ) - } - - fn drop_flag_test_block_with_succ<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - is_cleanup: bool, - on_set: BasicBlock, - on_unset: BasicBlock) - -> BasicBlock - { - let (maybe_live, maybe_dead) = c.init_data.state(c.path); - debug!("drop_flag_test_block({:?},{:?},{:?}) - {:?}", - c, is_cleanup, on_set, (maybe_live, maybe_dead)); - - match (maybe_live, maybe_dead) { - (false, _) => on_unset, - (true, false) => on_set, - (true, true) => { - let flag = self.drop_flag(c.path).unwrap(); - let term = TerminatorKind::if_(self.tcx, Operand::Consume(flag), on_set, on_unset); - self.new_block(c, is_cleanup, term) - } - } - } - - fn drop_block<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { - self.new_block(c, c.is_cleanup, TerminatorKind::Drop { - location: c.lvalue.clone(), - target: c.succ, - unwind: c.unwind - }) - } - - fn box_free_block<'a>( - &mut self, - c: &DropCtxt<'a, 'tcx>, - ty: Ty<'tcx>, - target: BasicBlock, - is_cleanup: bool - ) -> BasicBlock { - let block = self.unelaborated_free_block(c, ty, target, is_cleanup); - self.drop_flag_test_block_with_succ(c, is_cleanup, block, target) - } - - fn unelaborated_free_block<'a>( - &mut self, - c: &DropCtxt<'a, 'tcx>, - ty: Ty<'tcx>, - target: BasicBlock, - is_cleanup: bool - ) -> BasicBlock { - let mut statements = vec![]; - if let Some(&flag) = self.drop_flags.get(&c.path) { - statements.push(Statement { - source_info: c.source_info, - kind: StatementKind::Assign( - Lvalue::Local(flag), - self.constant_bool(c.source_info.span, false) - ) - }); - } - - let tcx = self.tcx; - let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil())); - let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); - let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let fty = tcx.item_type(free_func).subst(tcx, substs); - - self.patch.new_block(BasicBlockData { - statements: statements, - terminator: Some(Terminator { - source_info: c.source_info, kind: TerminatorKind::Call { - func: Operand::Constant(Constant { - span: c.source_info.span, - ty: fty, - literal: Literal::Item { - def_id: free_func, - substs: substs - } - }), - args: vec![Operand::Consume(c.lvalue.clone())], - destination: Some((unit_temp, target)), - cleanup: None - } - }), - is_cleanup: is_cleanup - }) - } - - fn must_complete_drop<'a>(&self, c: &DropCtxt<'a, 'tcx>) -> bool { - // if we have a destuctor, we must *not* split the drop. - - // dataflow can create unneeded children in some cases - // - be sure to ignore them. - - let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - - match ty.sty { - ty::TyAdt(def, _) => { - if def.has_dtor(self.tcx) && !def.is_box() { - self.tcx.sess.span_warn( - c.source_info.span, - &format!("dataflow bug??? moving out of type with dtor {:?}", - c)); - true - } else { - false - } - } - _ => false - } - } - fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { Rvalue::Use(Operand::Constant(Constant { span: span, @@ -1023,15 +577,4 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } } - - fn drop_flags_for_drop<'a>(&mut self, - c: &DropCtxt<'a, 'tcx>, - bb: BasicBlock) - { - let loc = self.patch.terminator_loc(self.mir, bb); - on_all_children_bits( - self.tcx, self.mir, self.move_data(), c.path, - |child| self.set_drop_flag(loc, child, DropFlagState::Absent) - ); - } } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 1c9ee335699ae..9237bb31f6bd7 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -16,12 +16,12 @@ use syntax_pos::DUMMY_SP; use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location}; use rustc::session::Session; use rustc::ty::{self, TyCtxt}; +use rustc_mir::util::elaborate_drops::DropFlagState; mod abs_domain; pub mod elaborate_drops; mod dataflow; mod gather_moves; -mod patch; // mod graphviz; use self::dataflow::{BitDenotation}; @@ -183,21 +183,6 @@ impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { } } -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -enum DropFlagState { - Present, // i.e. initialized - Absent, // i.e. deinitialized or "moved" -} - -impl DropFlagState { - fn value(self) -> bool { - match self { - DropFlagState::Present => true, - DropFlagState::Absent => false - } - } -} - fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b6978478085d5..6cd97e9559885 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -26,8 +26,7 @@ use rustc::session::config::Input; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; -use rustc_mir::pretty::write_mir_pretty; -use rustc_mir::graphviz::write_mir_graphviz; +use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast::{self, BlockCheckMode}; use syntax::fold::{self, Folder}; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 2718a0204a1ed..590c6a430b98a 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -49,13 +49,11 @@ pub mod diagnostics; pub mod build; pub mod callgraph; -pub mod def_use; -pub mod graphviz; mod hair; mod shim; pub mod mir_map; -pub mod pretty; pub mod transform; +pub mod util; use rustc::ty::maps::Providers; diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 2d2b90235ca3b..8c138d779c106 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -23,8 +23,8 @@ use rustc::mir::Mir; use rustc::mir::transform::MirSource; use rustc::mir::visit::MutVisitor; use shim; -use pretty; use hair::cx::Cx; +use util as mir_util; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; @@ -175,7 +175,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) mem::transmute::>(mir) }; - pretty::dump_mir(tcx, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, "mir_map", &0, src, &mir); tcx.alloc_mir(mir) }) @@ -234,7 +234,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mem::transmute::>(mir) }; - pretty::dump_mir(tcx, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, "mir_map", &0, src, &mir); tcx.alloc_mir(mir) }) diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 2194c20c2f442..5d127a5aed461 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -29,11 +29,11 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use def_use::DefUseAnalysis; use rustc::mir::{Constant, Local, LocalKind, Location, Lvalue, Mir, Operand, Rvalue, StatementKind}; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; +use util::def_use::DefUseAnalysis; use transform::qualify_consts; pub struct CopyPropagation; diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 035f33de91aa5..f22a71636a98e 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -15,7 +15,7 @@ use std::fmt; use rustc::ty::TyCtxt; use rustc::mir::*; use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource}; -use pretty; +use util as mir_util; pub struct Marker<'a>(pub &'a str); @@ -56,7 +56,7 @@ impl<'tcx> MirPassHook<'tcx> for DumpMir { pass: &Pass, is_after: bool) { - pretty::dump_mir( + mir_util::dump_mir( tcx, &*pass.name(), &Disambiguator { diff --git a/src/librustc_mir/def_use.rs b/src/librustc_mir/util/def_use.rs similarity index 100% rename from src/librustc_mir/def_use.rs rename to src/librustc_mir/util/def_use.rs diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs new file mode 100644 index 0000000000000..ce6debab9a4b8 --- /dev/null +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -0,0 +1,561 @@ +// Copyright 2017 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::fmt; +use rustc::mir::*; +use rustc::middle::lang_items; +use rustc::ty::{self, Ty}; +use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::util::IntTypeExt; +use rustc_data_structures::indexed_vec::Idx; +use util::patch::MirPatch; + +use std::iter; + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum DropFlagState { + Present, // i.e. initialized + Absent, // i.e. deinitialized or "moved" +} + +impl DropFlagState { + pub fn value(self) -> bool { + match self { + DropFlagState::Present => true, + DropFlagState::Absent => false + } + } +} + +#[derive(Debug)] +pub enum DropStyle { + Dead, + Static, + Conditional, + Open, +} + +#[derive(Debug)] +pub enum DropFlagMode { + Shallow, + Deep +} + +pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug { + type Path : Copy + fmt::Debug; + + fn patch(&mut self) -> &mut MirPatch<'tcx>; + fn mir(&self) -> &'a Mir<'tcx>; + fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx>; + fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx>; + + fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; + fn get_drop_flag(&mut self, path: Self::Path) -> Option>; + fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode); + + + fn field_subpath(&self, path: Self::Path, field: Field) -> Option; + fn deref_subpath(&self, path: Self::Path) -> Option; + fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option; +} + +#[derive(Debug)] +struct DropCtxt<'l, 'b: 'l, 'tcx: 'b, D> + where D : DropElaborator<'b, 'tcx> + 'l +{ + elaborator: &'l mut D, + + source_info: SourceInfo, + is_cleanup: bool, + + lvalue: &'l Lvalue<'tcx>, + path: D::Path, + succ: BasicBlock, + unwind: Option, +} + +pub fn elaborate_drop<'b, 'tcx, D>( + elaborator: &mut D, + source_info: SourceInfo, + is_cleanup: bool, + lvalue: &Lvalue<'tcx>, + path: D::Path, + succ: BasicBlock, + unwind: Option, + bb: BasicBlock) + where D: DropElaborator<'b, 'tcx> +{ + DropCtxt { + elaborator, source_info, is_cleanup, lvalue, path, succ, unwind + }.elaborate_drop(bb) +} + +impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> + where D: DropElaborator<'b, 'tcx> +{ + fn lvalue_ty(&self, lvalue: &Lvalue<'tcx>) -> Ty<'tcx> { + lvalue.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx()) + } + + fn tcx(&self) -> ty::TyCtxt<'b, 'tcx, 'tcx> { + self.elaborator.tcx() + } + + /// This elaborates a single drop instruction, located at `bb`, and + /// patches over it. + /// + /// The elaborated drop checks the drop flags to only drop what + /// is initialized. + /// + /// In addition, the relevant drop flags also need to be cleared + /// to avoid double-drops. However, in the middle of a complex + /// drop, one must avoid clearing some of the flags before they + /// are read, as that would cause a memory leak. + /// + /// In particular, when dropping an ADT, multiple fields may be + /// joined together under the `rest` subpath. They are all controlled + /// by the primary drop flag, but only the last rest-field dropped + /// should clear it (and it must also not clear anything else). + /// + /// FIXME: I think we should just control the flags externally + /// and then we do not need this machinery. + pub fn elaborate_drop<'a>(&mut self, bb: BasicBlock) { + debug!("elaborate_drop({:?})", self); + let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep); + debug!("elaborate_drop({:?}): live - {:?}", self, style); + match style { + DropStyle::Dead => { + self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto { + target: self.succ + }); + } + DropStyle::Static => { + let loc = self.terminator_loc(bb); + self.elaborator.clear_drop_flag(loc, self.path, DropFlagMode::Deep); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::Drop { + location: self.lvalue.clone(), + target: self.succ, + unwind: self.unwind + }); + } + DropStyle::Conditional => { + let drop_bb = self.complete_drop(Some(DropFlagMode::Deep)); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto { + target: drop_bb + }); + } + DropStyle::Open => { + let drop_bb = self.open_drop(); + self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto { + target: drop_bb + }); + } + } + } + + /// Return the lvalue and move path for each field of `variant`, + /// (the move path is `None` if the field is a rest field). + fn move_paths_for_fields(&self, + base_lv: &Lvalue<'tcx>, + variant_path: D::Path, + variant: &'tcx ty::VariantDef, + substs: &'tcx Substs<'tcx>) + -> Vec<(Lvalue<'tcx>, Option)> + { + variant.fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let subpath = self.elaborator.field_subpath(variant_path, field); + + let field_ty = + self.tcx().normalize_associated_type_in_env( + &f.ty(self.tcx(), substs), + self.elaborator.param_env() + ); + (base_lv.clone().field(field, field_ty), subpath) + }).collect() + } + + fn drop_subpath(&mut self, + is_cleanup: bool, + lvalue: &Lvalue<'tcx>, + path: Option, + succ: BasicBlock, + unwind: Option) + -> BasicBlock + { + if let Some(path) = path { + debug!("drop_subpath: for std field {:?}", lvalue); + + DropCtxt { + elaborator: self.elaborator, + source_info: self.source_info, + path, lvalue, succ, unwind, is_cleanup + }.elaborated_drop_block() + } else { + debug!("drop_subpath: for rest field {:?}", lvalue); + + DropCtxt { + elaborator: self.elaborator, + source_info: self.source_info, + lvalue, succ, unwind, is_cleanup, + // Using `self.path` here to condition the drop on + // our own drop flag. + path: self.path + }.complete_drop(None) + } + } + + /// Create one-half of the drop ladder for a list of fields, and return + /// the list of steps in it in reverse order. + /// + /// `unwind_ladder` is such a list of steps in reverse order, + /// which is called instead of the next step if the drop unwinds + /// (the first field is never reached). If it is `None`, all + /// unwind targets are left blank. + fn drop_halfladder<'a>(&mut self, + unwind_ladder: Option>, + succ: BasicBlock, + fields: &[(Lvalue<'tcx>, Option)], + is_cleanup: bool) + -> Vec + { + let mut unwind_succ = if is_cleanup { + None + } else { + self.unwind + }; + + let goto = TerminatorKind::Goto { target: succ }; + let mut succ = self.new_block(is_cleanup, goto); + + // Always clear the "master" drop flag at the bottom of the + // ladder. This is needed because the "master" drop flag + // protects the ADT's discriminant, which is invalidated + // after the ADT is dropped. + let succ_loc = Location { block: succ, statement_index: 0 }; + self.elaborator.clear_drop_flag(succ_loc, self.path, DropFlagMode::Shallow); + + fields.iter().rev().enumerate().map(|(i, &(ref lv, path))| { + succ = self.drop_subpath(is_cleanup, lv, path, succ, unwind_succ); + unwind_succ = unwind_ladder.as_ref().map(|p| p[i]); + succ + }).collect() + } + + /// Create a full drop ladder, consisting of 2 connected half-drop-ladders + /// + /// For example, with 3 fields, the drop ladder is + /// + /// .d0: + /// ELAB(drop location.0 [target=.d1, unwind=.c1]) + /// .d1: + /// ELAB(drop location.1 [target=.d2, unwind=.c2]) + /// .d2: + /// ELAB(drop location.2 [target=`self.succ`, unwind=`self.unwind`]) + /// .c1: + /// ELAB(drop location.1 [target=.c2]) + /// .c2: + /// ELAB(drop location.2 [target=`self.unwind]) + fn drop_ladder<'a>(&mut self, + fields: Vec<(Lvalue<'tcx>, Option)>) + -> BasicBlock + { + debug!("drop_ladder({:?}, {:?})", self, fields); + + let mut fields = fields; + fields.retain(|&(ref lvalue, _)| { + self.tcx().type_needs_drop_given_env( + self.lvalue_ty(lvalue), self.elaborator.param_env()) + }); + + debug!("drop_ladder - fields needing drop: {:?}", fields); + + let unwind_ladder = if self.is_cleanup { + None + } else { + let unwind = self.unwind.unwrap(); // FIXME(#6393) + Some(self.drop_halfladder(None, unwind, &fields, true)) + }; + + let succ = self.succ; // FIXME(#6393) + let is_cleanup = self.is_cleanup; + self.drop_halfladder(unwind_ladder, succ, &fields, is_cleanup) + .last().cloned().unwrap_or(succ) + } + + fn open_drop_for_tuple<'a>(&mut self, tys: &[Ty<'tcx>]) + -> BasicBlock + { + debug!("open_drop_for_tuple({:?}, {:?})", self, tys); + + let fields = tys.iter().enumerate().map(|(i, &ty)| { + (self.lvalue.clone().field(Field::new(i), ty), + self.elaborator.field_subpath(self.path, Field::new(i))) + }).collect(); + + self.drop_ladder(fields) + } + + fn open_drop_for_box<'a>(&mut self, ty: Ty<'tcx>) -> BasicBlock + { + debug!("open_drop_for_box({:?}, {:?})", self, ty); + + let interior = self.lvalue.clone().deref(); + let interior_path = self.elaborator.deref_subpath(self.path); + + let succ = self.succ; // FIXME(#6393) + let is_cleanup = self.is_cleanup; + let succ = self.box_free_block(ty, succ, is_cleanup); + let unwind_succ = self.unwind.map(|u| { + self.box_free_block(ty, u, true) + }); + + self.drop_subpath(is_cleanup, &interior, interior_path, succ, unwind_succ) + } + + fn open_drop_for_adt<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) + -> BasicBlock { + debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs); + + match adt.variants.len() { + 1 => { + let fields = self.move_paths_for_fields( + self.lvalue, + self.path, + &adt.variants[0], + substs + ); + self.drop_ladder(fields) + } + _ => { + let mut values = Vec::with_capacity(adt.variants.len()); + let mut blocks = Vec::with_capacity(adt.variants.len()); + let mut otherwise = None; + for (variant_index, discr) in adt.discriminants(self.tcx()).enumerate() { + let subpath = self.elaborator.downcast_subpath( + self.path, variant_index); + if let Some(variant_path) = subpath { + let base_lv = self.lvalue.clone().elem( + ProjectionElem::Downcast(adt, variant_index) + ); + let fields = self.move_paths_for_fields( + &base_lv, + variant_path, + &adt.variants[variant_index], + substs); + values.push(discr); + blocks.push(self.drop_ladder(fields)); + } else { + // variant not found - drop the entire enum + if let None = otherwise { + otherwise = + Some(self.complete_drop(Some(DropFlagMode::Shallow))); + } + } + } + if let Some(block) = otherwise { + blocks.push(block); + } else { + values.pop(); + } + // If there are multiple variants, then if something + // is present within the enum the discriminant, tracked + // by the rest path, must be initialized. + // + // Additionally, we do not want to switch on the + // discriminant after it is free-ed, because that + // way lies only trouble. + let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); + let discr = Lvalue::Local(self.new_temp(discr_ty)); + let discr_rv = Rvalue::Discriminant(self.lvalue.clone()); + let switch_block = self.elaborator.patch().new_block(BasicBlockData { + statements: vec![ + Statement { + source_info: self.source_info, + kind: StatementKind::Assign(discr.clone(), discr_rv), + } + ], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::SwitchInt { + discr: Operand::Consume(discr), + switch_ty: discr_ty, + values: From::from(values), + targets: blocks, + } + }), + is_cleanup: self.is_cleanup, + }); + self.drop_flag_test_block(switch_block) + } + } + } + + /// The slow-path - create an "open", elaborated drop for a type + /// which is moved-out-of only partially, and patch `bb` to a jump + /// to it. This must not be called on ADTs with a destructor, + /// as these can't be moved-out-of, except for `Box`, which is + /// special-cased. + /// + /// This creates a "drop ladder" that drops the needed fields of the + /// ADT, both in the success case or if one of the destructors fail. + fn open_drop<'a>(&mut self) -> BasicBlock { + let ty = self.lvalue_ty(self.lvalue); + match ty.sty { + ty::TyClosure(def_id, substs) => { + let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); + self.open_drop_for_tuple(&tys) + } + ty::TyTuple(tys, _) => { + self.open_drop_for_tuple(tys) + } + ty::TyAdt(def, _) if def.is_box() => { + self.open_drop_for_box(ty.boxed_ty()) + } + ty::TyAdt(def, substs) => { + self.open_drop_for_adt(def, substs) + } + _ => bug!("open drop from non-ADT `{:?}`", ty) + } + } + + /// Return a basic block that drop an lvalue using the context + /// and path in `c`. If `mode` is something, also clear `c` + /// according to it. + /// + /// if FLAG(self.path) + /// if let Some(mode) = mode: FLAG(self.path)[mode] = false + /// drop(self.lv) + fn complete_drop<'a>(&mut self, drop_mode: Option) -> BasicBlock + { + debug!("complete_drop({:?},{:?})", self, drop_mode); + + let drop_block = self.drop_block(); + if let Some(mode) = drop_mode { + let block_start = Location { block: drop_block, statement_index: 0 }; + self.elaborator.clear_drop_flag(block_start, self.path, mode); + } + + self.drop_flag_test_block(drop_block) + } + + fn elaborated_drop_block<'a>(&mut self) -> BasicBlock { + debug!("elaborated_drop_block({:?})", self); + let blk = self.drop_block(); + self.elaborate_drop(blk); + blk + } + + fn box_free_block<'a>( + &mut self, + ty: Ty<'tcx>, + target: BasicBlock, + is_cleanup: bool + ) -> BasicBlock { + let block = self.unelaborated_free_block(ty, target, is_cleanup); + self.drop_flag_test_block_with_succ(is_cleanup, block, target) + } + + fn unelaborated_free_block<'a>( + &mut self, + ty: Ty<'tcx>, + target: BasicBlock, + is_cleanup: bool + ) -> BasicBlock { + let tcx = self.tcx(); + let unit_temp = Lvalue::Local(self.new_temp(tcx.mk_nil())); + let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); + let substs = tcx.mk_substs(iter::once(Kind::from(ty))); + let fty = tcx.item_type(free_func).subst(tcx, substs); + + let free_block = self.elaborator.patch().new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: self.source_info, kind: TerminatorKind::Call { + func: Operand::Constant(Constant { + span: self.source_info.span, + ty: fty, + literal: Literal::Item { + def_id: free_func, + substs: substs + } + }), + args: vec![Operand::Consume(self.lvalue.clone())], + destination: Some((unit_temp, target)), + cleanup: None + } + }), + is_cleanup: is_cleanup + }); + let block_start = Location { block: free_block, statement_index: 0 }; + self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); + free_block + } + + fn drop_block<'a>(&mut self) -> BasicBlock { + let block = TerminatorKind::Drop { + location: self.lvalue.clone(), + target: self.succ, + unwind: self.unwind + }; + let is_cleanup = self.is_cleanup; // FIXME(#6393) + self.new_block(is_cleanup, block) + } + + fn drop_flag_test_block<'a>(&mut self, on_set: BasicBlock) -> BasicBlock { + let is_cleanup = self.is_cleanup; + let succ = self.succ; // FIXME(#6393) + self.drop_flag_test_block_with_succ(is_cleanup, on_set, succ) + } + + fn drop_flag_test_block_with_succ<'a>(&mut self, + is_cleanup: bool, + on_set: BasicBlock, + on_unset: BasicBlock) + -> BasicBlock + { + let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); + debug!("drop_flag_test_block({:?},{:?},{:?}) - {:?}", + self, is_cleanup, on_set, style); + + match style { + DropStyle::Dead => on_unset, + DropStyle::Static => on_set, + DropStyle::Conditional | DropStyle::Open => { + let flag = self.elaborator.get_drop_flag(self.path).unwrap(); + let term = TerminatorKind::if_(self.tcx(), flag, on_set, on_unset); + self.new_block(is_cleanup, term) + } + } + } + + fn new_block<'a>(&mut self, + is_cleanup: bool, + k: TerminatorKind<'tcx>) + -> BasicBlock + { + self.elaborator.patch().new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: self.source_info, kind: k + }), + is_cleanup: is_cleanup + }) + } + + fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { + self.elaborator.patch().new_temp(ty) + } + + fn terminator_loc(&mut self, bb: BasicBlock) -> Location { + let mir = self.elaborator.mir(); + self.elaborator.patch().terminator_loc(mir, bb) + } +} diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/util/graphviz.rs similarity index 100% rename from src/librustc_mir/graphviz.rs rename to src/librustc_mir/util/graphviz.rs diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs new file mode 100644 index 0000000000000..cafc5bca76acd --- /dev/null +++ b/src/librustc_mir/util/mod.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +pub mod elaborate_drops; +pub mod def_use; +pub mod patch; + +mod graphviz; +mod pretty; + +pub use self::pretty::{dump_mir, write_mir_pretty}; +pub use self::graphviz::{write_mir_graphviz}; +pub use self::graphviz::write_node_label as write_graphviz_node_label; diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_mir/util/patch.rs similarity index 100% rename from src/librustc_borrowck/borrowck/mir/patch.rs rename to src/librustc_mir/util/patch.rs diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/util/pretty.rs similarity index 100% rename from src/librustc_mir/pretty.rs rename to src/librustc_mir/util/pretty.rs From 26df816f520d00fe5ddf332a0a08ad6e26a5698d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 9 Mar 2017 20:36:01 +0200 Subject: [PATCH 111/662] apply pre-trans passes to Shim MIR --- src/librustc_mir/shim.rs | 23 +++---- src/librustc_mir/transform/add_call_guards.rs | 68 ++++++++++--------- src/librustc_mir/transform/no_landing_pads.rs | 10 ++- src/librustc_mir/transform/simplify.rs | 14 ++-- 4 files changed, 62 insertions(+), 53 deletions(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 35ad296006dad..2d9ef124ad244 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -28,6 +28,8 @@ use std::cell::RefCell; use std::iter; use std::mem; +use transform::{add_call_guards, no_landing_pads, simplify}; + pub fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } @@ -42,7 +44,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, let param_env = tcx.construct_parameter_environment(span, did, ROOT_CODE_EXTENT); - let result = match instance { + let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), ty::InstanceDef::FnPtrShim(def_id, ty) => { @@ -103,6 +105,10 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, bug!("creating shims from intrinsics ({:?}) is unsupported", instance) } }; + debug!("make_shim({:?}) = untransformed {:?}", instance, result); + no_landing_pads::no_landing_pads(tcx, &mut result); + simplify::simplify_cfg(&mut result); + add_call_guards::add_call_guards(&mut result); debug!("make_shim({:?}) = {:?}", instance, result); let result = tcx.alloc_mir(result); @@ -230,18 +236,13 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, }) }; - let have_unwind = match (rcvr_adjustment, tcx.sess.no_landing_pads()) { - (Adjustment::RefMut, false) => true, - _ => false - }; - // BB #0 block(&mut blocks, statements, TerminatorKind::Call { func: callee, args: args, destination: Some((Lvalue::Local(RETURN_POINTER), BasicBlock::new(1))), - cleanup: if have_unwind { + cleanup: if let Adjustment::RefMut = rcvr_adjustment { Some(BasicBlock::new(3)) } else { None @@ -253,16 +254,12 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, block(&mut blocks, vec![], TerminatorKind::Drop { location: Lvalue::Local(rcvr_arg), target: BasicBlock::new(2), - unwind: if have_unwind { - Some(BasicBlock::new(4)) - } else { - None - } + unwind: None }, false); } // BB #1/#2 - return block(&mut blocks, vec![], TerminatorKind::Return, false); - if have_unwind { + if let Adjustment::RefMut = rcvr_adjustment { // BB #3 - drop if closure panics block(&mut blocks, vec![], TerminatorKind::Drop { location: Lvalue::Local(rcvr_arg), diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 89e644e4fb077..80b17c6a008f5 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -37,46 +37,50 @@ pub struct AddCallGuards; impl<'tcx> MirPass<'tcx> for AddCallGuards { fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { - let pred_count: IndexVec<_, _> = - mir.predecessors().iter().map(|ps| ps.len()).collect(); + add_call_guards(mir); + } +} + +pub fn add_call_guards(mir: &mut Mir) { + let pred_count: IndexVec<_, _> = + mir.predecessors().iter().map(|ps| ps.len()).collect(); - // We need a place to store the new blocks generated - let mut new_blocks = Vec::new(); + // We need a place to store the new blocks generated + let mut new_blocks = Vec::new(); - let cur_len = mir.basic_blocks().len(); + let cur_len = mir.basic_blocks().len(); - for block in mir.basic_blocks_mut() { - match block.terminator { - Some(Terminator { - kind: TerminatorKind::Call { - destination: Some((_, ref mut destination)), - cleanup: Some(_), - .. - }, source_info - }) if pred_count[*destination] > 1 => { - // It's a critical edge, break it - let call_guard = BasicBlockData { - statements: vec![], - is_cleanup: block.is_cleanup, - terminator: Some(Terminator { - source_info: source_info, - kind: TerminatorKind::Goto { target: *destination } - }) - }; + for block in mir.basic_blocks_mut() { + match block.terminator { + Some(Terminator { + kind: TerminatorKind::Call { + destination: Some((_, ref mut destination)), + cleanup: Some(_), + .. + }, source_info + }) if pred_count[*destination] > 1 => { + // It's a critical edge, break it + let call_guard = BasicBlockData { + statements: vec![], + is_cleanup: block.is_cleanup, + terminator: Some(Terminator { + source_info: source_info, + kind: TerminatorKind::Goto { target: *destination } + }) + }; - // Get the index it will be when inserted into the MIR - let idx = cur_len + new_blocks.len(); - new_blocks.push(call_guard); - *destination = BasicBlock::new(idx); - } - _ => {} + // Get the index it will be when inserted into the MIR + let idx = cur_len + new_blocks.len(); + new_blocks.push(call_guard); + *destination = BasicBlock::new(idx); } + _ => {} } + } - debug!("Broke {} N edges", new_blocks.len()); + debug!("Broke {} N edges", new_blocks.len()); - mir.basic_blocks_mut().extend(new_blocks); - } + mir.basic_blocks_mut().extend(new_blocks); } impl Pass for AddCallGuards {} diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 55a26f4b37fe2..3654ae6940c52 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -42,12 +42,16 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { } } +pub fn no_landing_pads<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) { + if tcx.sess.no_landing_pads() { + NoLandingPads.visit_mir(mir); + } +} + impl<'tcx> MirPass<'tcx> for NoLandingPads { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { - if tcx.sess.no_landing_pads() { - self.visit_mir(mir); - } + no_landing_pads(tcx, mir) } } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index a762507f35e7e..0a8f147b21410 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -53,14 +53,18 @@ impl<'a> SimplifyCfg<'a> { } } +pub fn simplify_cfg(mir: &mut Mir) { + CfgSimplifier::new(mir).simplify(); + remove_dead_blocks(mir); + + // FIXME: Should probably be moved into some kind of pass manager + mir.basic_blocks_mut().raw.shrink_to_fit(); +} + impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> { fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir); - CfgSimplifier::new(mir).simplify(); - remove_dead_blocks(mir); - - // FIXME: Should probably be moved into some kind of pass manager - mir.basic_blocks_mut().raw.shrink_to_fit(); + simplify_cfg(mir); } } From f2c7917402ebd858f5b517a3406bec8ef187bfb1 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 14 Mar 2017 01:08:21 +0200 Subject: [PATCH 112/662] translate drop glue using MIR Drop of arrays is now translated in trans::block in an ugly way that I should clean up in a later PR, and does not handle panics in the middle of an array drop, but this commit & PR are growing too big. --- src/libcore/intrinsics.rs | 8 +- src/libcore/ptr.rs | 29 ++ src/librustc/middle/lang_items.rs | 4 +- src/librustc/mir/mod.rs | 18 +- src/librustc/ty/instance.rs | 9 +- .../borrowck/mir/gather_moves.rs | 2 +- src/librustc_mir/shim.rs | 132 +++++- src/librustc_mir/util/elaborate_drops.rs | 301 +++++++++---- src/librustc_trans/abi.rs | 24 +- src/librustc_trans/adt.rs | 22 - src/librustc_trans/attributes.rs | 1 + src/librustc_trans/base.rs | 4 +- src/librustc_trans/callee.rs | 3 + src/librustc_trans/cleanup.rs | 144 ------- src/librustc_trans/collector.rs | 260 ++++------- src/librustc_trans/common.rs | 13 +- src/librustc_trans/context.rs | 16 +- src/librustc_trans/glue.rs | 403 +----------------- src/librustc_trans/lib.rs | 1 - src/librustc_trans/meth.rs | 52 ++- src/librustc_trans/mir/block.rs | 89 ++-- src/librustc_trans/mir/lvalue.rs | 58 +-- src/librustc_trans/mir/operand.rs | 24 +- src/librustc_trans/mir/rvalue.rs | 6 +- src/librustc_trans/monomorphize.rs | 27 +- src/librustc_trans/partitioning.rs | 5 +- src/librustc_trans/symbol_map.rs | 1 - src/librustc_trans/trans_item.rs | 80 +--- src/librustc_trans/tvec.rs | 7 +- .../cross-crate-generic-functions.rs | 2 - .../drop_in_place_intrinsic.rs | 7 +- .../item-collection/function-as-argument.rs | 2 - .../item-collection/generic-drop-glue.rs | 19 +- .../instantiation-through-vtable.rs | 3 +- .../items-within-generic-items.rs | 2 - .../item-collection/non-generic-drop-glue.rs | 8 +- .../item-collection/non-generic-functions.rs | 2 - .../item-collection/overloaded-operators.rs | 2 - .../item-collection/static-init.rs | 1 - .../item-collection/statics-and-consts.rs | 2 - .../item-collection/trait-implementations.rs | 2 - .../trait-method-as-argument.rs | 2 - .../trait-method-default-impl.rs | 2 - .../item-collection/transitive-drop-glue.rs | 21 +- .../item-collection/tuple-drop-glue.rs | 9 +- .../codegen-units/item-collection/unsizing.rs | 8 +- .../unused-traits-and-generics.rs | 1 - .../partitioning/extern-drop-glue.rs | 7 +- .../partitioning/extern-generic.rs | 2 - .../partitioning/local-drop-glue.rs | 9 +- .../partitioning/regular-modules.rs | 2 - .../codegen-units/partitioning/statics.rs | 2 - .../partitioning/vtable-through-const.rs | 2 +- 53 files changed, 721 insertions(+), 1141 deletions(-) delete mode 100644 src/librustc_trans/cleanup.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 12410c08f399b..e74e13d1a6b05 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -46,8 +46,13 @@ issue = "0")] #![allow(missing_docs)] -extern "rust-intrinsic" { +#[cfg(not(stage0))] +#[stable(feature = "drop_in_place", since = "1.8.0")] +#[rustc_deprecated(reason = "no longer an intrinsic - use `ptr::drop_in_place` directly", + since = "1.18.0")] +pub use ptr::drop_in_place; +extern "rust-intrinsic" { // NB: These intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. @@ -622,6 +627,7 @@ extern "rust-intrinsic" { pub fn size_of_val(_: &T) -> usize; pub fn min_align_of_val(_: &T) -> usize; + #[cfg(stage0)] /// Executes the destructor (if any) of the pointed-to value. /// /// This has two use cases: diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 0b7aa4fa9117c..c4409d3cb5590 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -37,9 +37,38 @@ pub use intrinsics::copy; #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::write_bytes; +#[cfg(stage0)] #[stable(feature = "drop_in_place", since = "1.8.0")] pub use intrinsics::drop_in_place; +#[cfg(not(stage0))] +/// Executes the destructor (if any) of the pointed-to value. +/// +/// This has two use cases: +/// +/// * It is *required* to use `drop_in_place` to drop unsized types like +/// trait objects, because they can't be read out onto the stack and +/// dropped normally. +/// +/// * It is friendlier to the optimizer to do this over `ptr::read` when +/// dropping manually allocated memory (e.g. when writing Box/Rc/Vec), +/// as the compiler doesn't need to prove that it's sound to elide the +/// copy. +/// +/// # Undefined Behavior +/// +/// This has all the same safety problems as `ptr::read` with respect to +/// invalid pointers, types, and double drops. +#[stable(feature = "drop_in_place", since = "1.8.0")] +#[lang="drop_in_place"] +#[inline] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + /// Creates a null raw pointer. /// /// # Examples diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index b9f1611f62baf..81a415a2f5309 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -335,7 +335,7 @@ language_item_table! { ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; - StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn; + DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; StartFnLangItem, "start", start_fn; @@ -355,8 +355,6 @@ language_item_table! { ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime; InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime; - NoCopyItem, "no_copy_bound", no_copy_bound; - NonZeroItem, "non_zero", non_zero; DebugTraitLangItem, "debug_trait", debug_trait; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index fea576f706780..33df648f172d6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -17,7 +17,7 @@ use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccesso use rustc_data_structures::control_flow_graph::ControlFlowGraph; use hir::def::CtorKind; use hir::def_id::DefId; -use ty::subst::Substs; +use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use util::ppaux; @@ -982,6 +982,22 @@ impl<'tcx> Debug for Operand<'tcx> { } } +impl<'tcx> Operand<'tcx> { + pub fn item<'a>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + span: Span) + -> Self + { + Operand::Constant(Constant { + span: span, + ty: tcx.item_type(def_id).subst(tcx, substs), + literal: Literal::Item { def_id, substs } + }) + } + +} + /////////////////////////////////////////////////////////////////////////// /// Rvalues diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index aeb1fe079ff25..67287f1b4ff72 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -35,6 +35,8 @@ pub enum InstanceDef<'tcx> { Virtual(DefId, usize), // <[mut closure] as FnOnce>::call_once ClosureOnceShim { call_once: DefId }, + // drop_in_place::; None for empty drop glue. + DropGlue(DefId, Option>), } impl<'tcx> InstanceDef<'tcx> { @@ -46,7 +48,8 @@ impl<'tcx> InstanceDef<'tcx> { InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id, ) | InstanceDef::ClosureOnceShim { call_once: def_id } - => def_id + => def_id, + InstanceDef::DropGlue(def_id, _) => def_id } } @@ -65,6 +68,7 @@ impl<'tcx> InstanceDef<'tcx> { // real on-demand. let ty = match self { &InstanceDef::FnPtrShim(_, ty) => Some(ty), + &InstanceDef::DropGlue(_, ty) => ty, _ => None }.into_iter(); @@ -97,6 +101,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> { InstanceDef::ClosureOnceShim { .. } => { write!(f, " - shim") } + InstanceDef::DropGlue(_, ty) => { + write!(f, " - shim({:?})", ty) + } } } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 8d866676dbd18..81037fe40d9da 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -437,7 +437,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } Rvalue::Ref(..) | Rvalue::Discriminant(..) | - Rvalue::Len(..) => {} + Rvalue::Len(..) | Rvalue::Box(..) => { // This returns an rvalue with uninitialized contents. We can't // move out of it here because it is an rvalue - assignments always diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 2d9ef124ad244..26d5b7fd38ab0 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -15,7 +15,7 @@ use rustc::middle::region::ROOT_CODE_EXTENT; use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::ty::{self, Ty}; -use rustc::ty::subst::Subst; +use rustc::ty::subst::{Kind, Subst}; use rustc::ty::maps::Providers; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -25,10 +25,13 @@ use syntax::ast; use syntax_pos::Span; use std::cell::RefCell; +use std::fmt; use std::iter; use std::mem; use transform::{add_call_guards, no_landing_pads, simplify}; +use util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode}; +use util::patch::MirPatch; pub fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; @@ -101,6 +104,9 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, None ) } + ty::InstanceDef::DropGlue(def_id, ty) => { + build_drop_shim(tcx, ¶m_env, def_id, ty) + } ty::InstanceDef::Intrinsic(_) => { bug!("creating shims from intrinsics ({:?}) is unsupported", instance) } @@ -143,6 +149,129 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) .collect() } +fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + def_id: DefId, + ty: Option>) + -> Mir<'tcx> +{ + debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); + + let substs = if let Some(ty) = ty { + tcx.mk_substs(iter::once(Kind::from(ty))) + } else { + param_env.free_substs + }; + let fn_ty = tcx.item_type(def_id).subst(tcx, substs); + let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); + let span = tcx.def_span(def_id); + + let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; + + let return_block = BasicBlock::new(1); + let mut blocks = IndexVec::new(); + let block = |blocks: &mut IndexVec<_, _>, kind| { + blocks.push(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { source_info, kind }), + is_cleanup: false + }) + }; + block(&mut blocks, TerminatorKind::Goto { target: return_block }); + block(&mut blocks, TerminatorKind::Return); + + let mut mir = Mir::new( + blocks, + IndexVec::from_elem_n( + VisibilityScopeData { span: span, parent_scope: None }, 1 + ), + IndexVec::new(), + sig.output(), + local_decls_for_sig(&sig), + sig.inputs().len(), + vec![], + span + ); + + if let Some(..) = ty { + let patch = { + let mut elaborator = DropShimElaborator { + mir: &mir, + patch: MirPatch::new(&mir), + tcx, param_env + }; + let dropee = Lvalue::Projection( + box Projection { + base: Lvalue::Local(Local::new(1+0)), + elem: ProjectionElem::Deref + } + ); + let resume_block = elaborator.patch.resume_block(); + elaborate_drops::elaborate_drop( + &mut elaborator, + source_info, + false, + &dropee, + (), + return_block, + Some(resume_block), + START_BLOCK + ); + elaborator.patch + }; + patch.apply(&mut mir); + } + + mir +} + +pub struct DropShimElaborator<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + patch: MirPatch<'tcx>, + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + param_env: &'a ty::ParameterEnvironment<'tcx>, +} + +impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> { + fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + Ok(()) + } +} + +impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { + type Path = (); + + fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch } + fn mir(&self) -> &'a Mir<'tcx> { self.mir } + fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { self.tcx } + fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx> { self.param_env } + + fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { + if let DropFlagMode::Shallow = mode { + DropStyle::Static + } else { + DropStyle::Open + } + } + + fn get_drop_flag(&mut self, _path: Self::Path) -> Option> { + None + } + + fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) { + } + + fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option { + None + } + fn deref_subpath(&self, _path: Self::Path) -> Option { + None + } + fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option { + Some(()) + } +} + /// Build a "call" shim for `def_id`. The shim calls the /// function specified by `call_kind`, first adjusting its first /// argument according to `rcvr_adjustment`. @@ -162,7 +291,6 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, def_id, rcvr_adjustment, call_kind, untuple_args); let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs); - // Not normalizing here without a param env. let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let span = tcx.def_span(def_id); diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index ce6debab9a4b8..d0f142ad7d7a8 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -9,10 +9,12 @@ // except according to those terms. use std::fmt; +use rustc::hir; use rustc::mir::*; +use rustc::middle::const_val::ConstInt; use rustc::middle::lang_items; use rustc::ty::{self, Ty}; -use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; @@ -92,6 +94,7 @@ pub fn elaborate_drop<'b, 'tcx, D>( bb: BasicBlock) where D: DropElaborator<'b, 'tcx> { + assert_eq!(unwind.is_none(), is_cleanup); DropCtxt { elaborator, source_info, is_cleanup, lvalue, path, succ, unwind }.elaborate_drop(bb) @@ -146,7 +149,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }); } DropStyle::Conditional => { - let drop_bb = self.complete_drop(Some(DropFlagMode::Deep)); + let is_cleanup = self.is_cleanup; // FIXME(#6393) + let succ = self.succ; + let drop_bb = self.complete_drop( + is_cleanup, Some(DropFlagMode::Deep), succ); self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); @@ -208,7 +214,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // Using `self.path` here to condition the drop on // our own drop flag. path: self.path - }.complete_drop(None) + }.complete_drop(is_cleanup, None, succ) } } @@ -220,7 +226,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// (the first field is never reached). If it is `None`, all /// unwind targets are left blank. fn drop_halfladder<'a>(&mut self, - unwind_ladder: Option>, + unwind_ladder: Option<&[BasicBlock]>, succ: BasicBlock, fields: &[(Lvalue<'tcx>, Option)], is_cleanup: bool) @@ -262,10 +268,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// .c1: /// ELAB(drop location.1 [target=.c2]) /// .c2: - /// ELAB(drop location.2 [target=`self.unwind]) + /// ELAB(drop location.2 [target=`self.unwind`]) fn drop_ladder<'a>(&mut self, fields: Vec<(Lvalue<'tcx>, Option)>) - -> BasicBlock + -> (BasicBlock, Option) { debug!("drop_ladder({:?}, {:?})", self, fields); @@ -286,8 +292,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let succ = self.succ; // FIXME(#6393) let is_cleanup = self.is_cleanup; - self.drop_halfladder(unwind_ladder, succ, &fields, is_cleanup) - .last().cloned().unwrap_or(succ) + let normal_ladder = + self.drop_halfladder(unwind_ladder.as_ref().map(|x| &**x), + succ, &fields, is_cleanup); + + (normal_ladder.last().cloned().unwrap_or(succ), + unwind_ladder.and_then(|l| l.last().cloned()).or(self.unwind)) } fn open_drop_for_tuple<'a>(&mut self, tys: &[Ty<'tcx>]) @@ -300,7 +310,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.elaborator.field_subpath(self.path, Field::new(i))) }).collect(); - self.drop_ladder(fields) + self.drop_ladder(fields).0 } fn open_drop_for_box<'a>(&mut self, ty: Ty<'tcx>) -> BasicBlock @@ -323,7 +333,33 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn open_drop_for_adt<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) -> BasicBlock { debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs); + if adt.variants.len() == 0 { + return self.elaborator.patch().new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Unreachable + }), + is_cleanup: self.is_cleanup + }); + } + + let contents_drop = if adt.is_union() { + (self.succ, self.unwind) + } else { + self.open_drop_for_adt_contents(adt, substs) + }; + if adt.has_dtor(self.tcx()) { + self.destructor_call_block(contents_drop) + } else { + contents_drop.0 + } + } + + fn open_drop_for_adt_contents<'a>(&mut self, adt: &'tcx ty::AdtDef, + substs: &'tcx Substs<'tcx>) + -> (BasicBlock, Option) { match adt.variants.len() { 1 => { let fields = self.move_paths_for_fields( @@ -335,9 +371,19 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_ladder(fields) } _ => { + let is_cleanup = self.is_cleanup; + let succ = self.succ; + let unwind = self.unwind; // FIXME(#6393) + let mut values = Vec::with_capacity(adt.variants.len()); - let mut blocks = Vec::with_capacity(adt.variants.len()); + let mut normal_blocks = Vec::with_capacity(adt.variants.len()); + let mut unwind_blocks = if is_cleanup { + None + } else { + Some(Vec::with_capacity(adt.variants.len())) + }; let mut otherwise = None; + let mut unwind_otherwise = None; for (variant_index, discr) in adt.discriminants(self.tcx()).enumerate() { let subpath = self.elaborator.downcast_subpath( self.path, variant_index); @@ -351,53 +397,146 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> &adt.variants[variant_index], substs); values.push(discr); - blocks.push(self.drop_ladder(fields)); + if let Some(ref mut unwind_blocks) = unwind_blocks { + // We can't use the half-ladder from the original + // drop ladder, because this breaks the + // "funclet can't have 2 successor funclets" + // requirement from MSVC: + // + // switch unwind-switch + // / \ / \ + // v1.0 v2.0 v2.0-unwind v1.0-unwind + // | | / | + // v1.1-unwind v2.1-unwind | + // ^ | + // \-------------------------------/ + // + // Create a duplicate half-ladder to avoid that. We + // could technically only do this on MSVC, but I + // I want to minimize the divergence between MSVC + // and non-MSVC. + + let unwind = unwind.unwrap(); + let halfladder = self.drop_halfladder( + None, unwind, &fields, true); + unwind_blocks.push( + halfladder.last().cloned().unwrap_or(unwind) + ); + } + let (normal, _) = self.drop_ladder(fields); + normal_blocks.push(normal); } else { // variant not found - drop the entire enum if let None = otherwise { - otherwise = - Some(self.complete_drop(Some(DropFlagMode::Shallow))); + otherwise = Some(self.complete_drop( + is_cleanup, + Some(DropFlagMode::Shallow), + succ)); + unwind_otherwise = unwind.map(|unwind| self.complete_drop( + true, + Some(DropFlagMode::Shallow), + unwind + )); } } } if let Some(block) = otherwise { - blocks.push(block); + normal_blocks.push(block); + if let Some(ref mut unwind_blocks) = unwind_blocks { + unwind_blocks.push(unwind_otherwise.unwrap()); + } } else { values.pop(); } - // If there are multiple variants, then if something - // is present within the enum the discriminant, tracked - // by the rest path, must be initialized. - // - // Additionally, we do not want to switch on the - // discriminant after it is free-ed, because that - // way lies only trouble. - let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); - let discr = Lvalue::Local(self.new_temp(discr_ty)); - let discr_rv = Rvalue::Discriminant(self.lvalue.clone()); - let switch_block = self.elaborator.patch().new_block(BasicBlockData { - statements: vec![ - Statement { - source_info: self.source_info, - kind: StatementKind::Assign(discr.clone(), discr_rv), - } - ], - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: Operand::Consume(discr), - switch_ty: discr_ty, - values: From::from(values), - targets: blocks, - } - }), - is_cleanup: self.is_cleanup, - }); - self.drop_flag_test_block(switch_block) + + (self.adt_switch_block(is_cleanup, adt, normal_blocks, &values, succ), + unwind_blocks.map(|unwind_blocks| { + self.adt_switch_block( + is_cleanup, adt, unwind_blocks, &values, unwind.unwrap() + ) + })) } } } + fn adt_switch_block(&mut self, + is_cleanup: bool, + adt: &'tcx ty::AdtDef, + blocks: Vec, + values: &[ConstInt], + succ: BasicBlock) + -> BasicBlock { + // If there are multiple variants, then if something + // is present within the enum the discriminant, tracked + // by the rest path, must be initialized. + // + // Additionally, we do not want to switch on the + // discriminant after it is free-ed, because that + // way lies only trouble. + let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); + let discr = Lvalue::Local(self.new_temp(discr_ty)); + let discr_rv = Rvalue::Discriminant(self.lvalue.clone()); + let switch_block = self.elaborator.patch().new_block(BasicBlockData { + statements: vec![ + Statement { + source_info: self.source_info, + kind: StatementKind::Assign(discr.clone(), discr_rv), + } + ], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::SwitchInt { + discr: Operand::Consume(discr), + switch_ty: discr_ty, + values: From::from(values.to_owned()), + targets: blocks, + } + }), + is_cleanup: is_cleanup, + }); + self.drop_flag_test_block(is_cleanup, switch_block, succ) + } + + fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Option)) + -> BasicBlock + { + debug!("destructor_call_block({:?}, {:?})", self, succ); + let tcx = self.tcx(); + let drop_trait = tcx.lang_items.drop_trait().unwrap(); + let drop_fn = tcx.associated_items(drop_trait).next().unwrap(); + let ty = self.lvalue_ty(self.lvalue); + let substs = tcx.mk_substs(iter::once(Kind::from(ty))); + + let re_erased = tcx.mk_region(ty::ReErased); + let ref_ty = tcx.mk_ref(re_erased, ty::TypeAndMut { + ty: ty, + mutbl: hir::Mutability::MutMutable + }); + let ref_lvalue = self.new_temp(ref_ty); + let unit_temp = Lvalue::Local(self.new_temp(tcx.mk_nil())); + + self.elaborator.patch().new_block(BasicBlockData { + statements: vec![Statement { + source_info: self.source_info, + kind: StatementKind::Assign( + Lvalue::Local(ref_lvalue), + Rvalue::Ref(re_erased, BorrowKind::Mut, self.lvalue.clone()) + ) + }], + terminator: Some(Terminator { + kind: TerminatorKind::Call { + func: Operand::item(tcx, drop_fn.def_id, substs, + self.source_info.span), + args: vec![Operand::Consume(Lvalue::Local(ref_lvalue))], + destination: Some((unit_temp, succ)), + cleanup: unwind, + }, + source_info: self.source_info + }), + is_cleanup: self.is_cleanup, + }) + } + /// The slow-path - create an "open", elaborated drop for a type /// which is moved-out-of only partially, and patch `bb` to a jump /// to it. This must not be called on ADTs with a destructor, @@ -408,6 +547,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// ADT, both in the success case or if one of the destructors fail. fn open_drop<'a>(&mut self) -> BasicBlock { let ty = self.lvalue_ty(self.lvalue); + let is_cleanup = self.is_cleanup; // FIXME(#6393) + let succ = self.succ; match ty.sty { ty::TyClosure(def_id, substs) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); @@ -422,6 +563,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty::TyAdt(def, substs) => { self.open_drop_for_adt(def, substs) } + ty::TyDynamic(..) => { + self.complete_drop(is_cleanup, Some(DropFlagMode::Deep), succ) + } + ty::TyArray(..) | ty::TySlice(..) => { + // FIXME(#34708): handle partially-dropped + // array/slice elements. + self.complete_drop(is_cleanup, Some(DropFlagMode::Deep), succ) + } _ => bug!("open drop from non-ADT `{:?}`", ty) } } @@ -433,22 +582,27 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// if FLAG(self.path) /// if let Some(mode) = mode: FLAG(self.path)[mode] = false /// drop(self.lv) - fn complete_drop<'a>(&mut self, drop_mode: Option) -> BasicBlock + fn complete_drop<'a>(&mut self, + is_cleanup: bool, + drop_mode: Option, + succ: BasicBlock) -> BasicBlock { debug!("complete_drop({:?},{:?})", self, drop_mode); - let drop_block = self.drop_block(); + let drop_block = self.drop_block(is_cleanup, succ); if let Some(mode) = drop_mode { let block_start = Location { block: drop_block, statement_index: 0 }; self.elaborator.clear_drop_flag(block_start, self.path, mode); } - self.drop_flag_test_block(drop_block) + self.drop_flag_test_block(is_cleanup, drop_block, succ) } fn elaborated_drop_block<'a>(&mut self) -> BasicBlock { debug!("elaborated_drop_block({:?})", self); - let blk = self.drop_block(); + let is_cleanup = self.is_cleanup; // FIXME(#6393) + let succ = self.succ; + let blk = self.drop_block(is_cleanup, succ); self.elaborate_drop(blk); blk } @@ -460,7 +614,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> is_cleanup: bool ) -> BasicBlock { let block = self.unelaborated_free_block(ty, target, is_cleanup); - self.drop_flag_test_block_with_succ(is_cleanup, block, target) + self.drop_flag_test_block(is_cleanup, block, target) } fn unelaborated_free_block<'a>( @@ -473,53 +627,34 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let unit_temp = Lvalue::Local(self.new_temp(tcx.mk_nil())); let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let fty = tcx.item_type(free_func).subst(tcx, substs); - let free_block = self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: self.source_info, kind: TerminatorKind::Call { - func: Operand::Constant(Constant { - span: self.source_info.span, - ty: fty, - literal: Literal::Item { - def_id: free_func, - substs: substs - } - }), - args: vec![Operand::Consume(self.lvalue.clone())], - destination: Some((unit_temp, target)), - cleanup: None - } - }), - is_cleanup: is_cleanup - }); + let call = TerminatorKind::Call { + func: Operand::item(tcx, free_func, substs, self.source_info.span), + args: vec![Operand::Consume(self.lvalue.clone())], + destination: Some((unit_temp, target)), + cleanup: None + }; // FIXME(#6393) + let free_block = self.new_block(is_cleanup, call); + let block_start = Location { block: free_block, statement_index: 0 }; self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); free_block } - fn drop_block<'a>(&mut self) -> BasicBlock { + fn drop_block<'a>(&mut self, is_cleanup: bool, succ: BasicBlock) -> BasicBlock { let block = TerminatorKind::Drop { location: self.lvalue.clone(), - target: self.succ, - unwind: self.unwind + target: succ, + unwind: if is_cleanup { None } else { self.unwind } }; - let is_cleanup = self.is_cleanup; // FIXME(#6393) self.new_block(is_cleanup, block) } - fn drop_flag_test_block<'a>(&mut self, on_set: BasicBlock) -> BasicBlock { - let is_cleanup = self.is_cleanup; - let succ = self.succ; // FIXME(#6393) - self.drop_flag_test_block_with_succ(is_cleanup, on_set, succ) - } - - fn drop_flag_test_block_with_succ<'a>(&mut self, - is_cleanup: bool, - on_set: BasicBlock, - on_unset: BasicBlock) - -> BasicBlock + fn drop_flag_test_block(&mut self, + is_cleanup: bool, + on_set: BasicBlock, + on_unset: BasicBlock) + -> BasicBlock { let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); debug!("drop_flag_test_block({:?},{:?},{:?}) - {:?}", diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 710aa1fbbc6d9..27a19d211c290 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace}; use base; use builder::Builder; -use common::{self, type_is_fat_ptr, C_uint}; +use common::{type_is_fat_ptr, C_uint}; use context::CrateContext; use cabi_x86; use cabi_x86_64; @@ -59,6 +59,7 @@ enum ArgKind { pub use self::attr_impl::ArgAttribute; #[allow(non_upper_case_globals)] +#[allow(unused)] mod attr_impl { // The subset of llvm::Attribute needed for arguments, packed into a bitfield. bitflags! { @@ -223,16 +224,6 @@ impl ArgType { self.kind == ArgKind::Ignore } - /// Get the LLVM type for an lvalue of the original Rust type of - /// this argument/return, i.e. the result of `type_of::type_of`. - pub fn memory_ty(&self, ccx: &CrateContext) -> Type { - if self.original_ty == Type::i1(ccx) { - Type::i8(ccx) - } else { - self.original_ty - } - } - /// Store a direct/indirect value described by this ArgType into a /// lvalue for the original Rust type of this argument/return. /// Can be used for both storing formal arguments into Rust variables @@ -344,17 +335,6 @@ impl FnType { fn_ty } - pub fn from_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &ty::Instance<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType - { - let ity = common::instance_ty(ccx.shared(), instance); - let sig = common::ty_fn_sig(ccx, ity); - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); - - Self::new(ccx, sig, extra_args) - } - fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType { diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 11d3fae823830..058f37f62dd82 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -363,28 +363,6 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, } } -/// Yield information about how to dispatch a case of the -/// discriminant-like value returned by `trans_switch`. -/// -/// This should ideally be less tightly tied to `_match`. -pub fn trans_case<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, value: Disr) -> ValueRef { - let l = bcx.ccx.layout_of(t); - match *l { - layout::CEnum { discr, .. } - | layout::General { discr, .. }=> { - C_integral(Type::from_integer(bcx.ccx, discr), value.0, true) - } - layout::RawNullablePointer { .. } | - layout::StructWrappedNullablePointer { .. } => { - assert!(value == Disr(0) || value == Disr(1)); - C_bool(bcx.ccx, value != Disr(0)) - } - _ => { - bug!("{} does not have a discriminant. Represented as {:#?}", t, l); - } - } -} - /// Set the discriminant for a new value of the given case of the given /// representation. pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) { diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index efdd1b736f0e7..6bef31ccf64a4 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -17,6 +17,7 @@ pub use syntax::attr::InlineAttr; use syntax::ast; use context::CrateContext; + /// Mark LLVM function to use provided inline heuristic. #[inline] pub fn inline(val: ValueRef, inline: InlineAttr) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a58764878a318..6593b8e68d425 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -403,7 +403,9 @@ pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, // a char is a Unicode codepoint, and so takes values from 0 // to 0x10FFFF inclusive only. b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False, alignment.to_align()) - } else if (t.is_region_ptr() || t.is_box()) && !common::type_is_fat_ptr(ccx, t) { + } else if (t.is_region_ptr() || t.is_box() || t.is_fn()) + && !common::type_is_fat_ptr(ccx, t) + { b.load_nonnull(ptr, alignment.to_align()) } else { b.load(ptr, alignment.to_align()) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 4d0bd9fa201d8..aefee51191ac4 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -96,6 +96,9 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert_eq!(common::val_ty(llfn), llptrty); debug!("get_fn: not casting pointer!"); + if common::is_inline_instance(tcx, &instance) { + attributes::inline(llfn, attributes::InlineAttr::Hint); + } let attrs = instance.def.attrs(ccx.tcx()); attributes::from_fn_attrs(ccx, &attrs, llfn); diff --git a/src/librustc_trans/cleanup.rs b/src/librustc_trans/cleanup.rs deleted file mode 100644 index 2b2e5e85ea50d..0000000000000 --- a/src/librustc_trans/cleanup.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2013-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. - -//! ## The Cleanup module -//! -//! The cleanup module tracks what values need to be cleaned up as scopes -//! are exited, either via panic or just normal control flow. -//! -//! Cleanup items can be scheduled into any of the scopes on the stack. -//! Typically, when a scope is finished, we generate the cleanup code. This -//! corresponds to a normal exit from a block (for example, an expression -//! completing evaluation successfully without panic). - -use llvm::BasicBlockRef; -use base; -use mir::lvalue::LvalueRef; -use rustc::mir::tcx::LvalueTy; -use builder::Builder; -use common::Funclet; -use glue; -use type_::Type; - -pub struct CleanupScope<'tcx> { - // Cleanup to run upon scope exit. - cleanup: Option>, - - // Computed on creation if compiling with landing pads (!sess.no_landing_pads) - pub landing_pad: Option, -} - -#[derive(Copy, Clone)] -pub struct DropValue<'tcx> { - val: LvalueRef<'tcx>, - skip_dtor: bool, -} - -impl<'tcx> DropValue<'tcx> { - fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &Builder<'a, 'tcx>) { - glue::call_drop_glue(bcx, self.val, self.skip_dtor, funclet) - } - - /// Creates a landing pad for the top scope. The landing pad will perform all cleanups necessary - /// for an unwind and then `resume` to continue error propagation: - /// - /// landing_pad -> ... cleanups ... -> [resume] - /// - /// This should only be called once per function, as it creates an alloca for the landingpad. - fn get_landing_pad<'a>(&self, bcx: &Builder<'a, 'tcx>) -> BasicBlockRef { - debug!("get_landing_pad"); - let bcx = bcx.build_sibling_block("cleanup_unwind"); - let llpersonality = bcx.ccx.eh_personality(); - bcx.set_personality_fn(llpersonality); - - if base::wants_msvc_seh(bcx.sess()) { - let pad = bcx.cleanup_pad(None, &[]); - let funclet = Some(Funclet::new(pad)); - self.trans(funclet.as_ref(), &bcx); - - bcx.cleanup_ret(pad, None); - } else { - // The landing pad return type (the type being propagated). Not sure - // what this represents but it's determined by the personality - // function and this is what the EH proposal example uses. - let llretty = Type::struct_(bcx.ccx, &[Type::i8p(bcx.ccx), Type::i32(bcx.ccx)], false); - - // The only landing pad clause will be 'cleanup' - let llretval = bcx.landing_pad(llretty, llpersonality, 1, bcx.llfn()); - - // The landing pad block is a cleanup - bcx.set_cleanup(llretval); - - // Insert cleanup instructions into the cleanup block - self.trans(None, &bcx); - - if !bcx.sess().target.target.options.custom_unwind_resume { - bcx.resume(llretval); - } else { - let exc_ptr = bcx.extract_value(llretval, 0); - bcx.call(bcx.ccx.eh_unwind_resume(), &[exc_ptr], None); - bcx.unreachable(); - } - } - - bcx.llbb() - } -} - -impl<'a, 'tcx> CleanupScope<'tcx> { - /// Issue #23611: Schedules a (deep) drop of the contents of - /// `val`, which is a pointer to an instance of struct/enum type - /// `ty`. The scheduled code handles extracting the discriminant - /// and dropping the contents associated with that variant - /// *without* executing any associated drop implementation. - pub fn schedule_drop_adt_contents( - bcx: &Builder<'a, 'tcx>, val: LvalueRef<'tcx> - ) -> CleanupScope<'tcx> { - if let LvalueTy::Downcast { .. } = val.ty { - bug!("Cannot drop downcast ty yet"); - } - // `if` below could be "!contents_needs_drop"; skipping drop - // is just an optimization, so sound to be conservative. - if !bcx.ccx.shared().type_needs_drop(val.ty.to_ty(bcx.tcx())) { - return CleanupScope::noop(); - } - - let drop = DropValue { - val: val, - skip_dtor: true, - }; - - CleanupScope::new(bcx, drop) - } - - fn new(bcx: &Builder<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> { - CleanupScope { - cleanup: Some(drop_val), - landing_pad: if !bcx.sess().no_landing_pads() { - Some(drop_val.get_landing_pad(bcx)) - } else { - None - }, - } - } - - pub fn noop() -> CleanupScope<'tcx> { - CleanupScope { - cleanup: None, - landing_pad: None, - } - } - - pub fn trans(self, bcx: &'a Builder<'a, 'tcx>) { - if let Some(cleanup) = self.cleanup { - cleanup.trans(None, &bcx); - } - } -} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index f076fc4710222..500802a4135d0 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -193,25 +193,21 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; -use rustc::middle::lang_items::{BoxFreeFnLangItem, ExchangeMallocFnLangItem}; +use rustc::middle::lang_items::{ExchangeMallocFnLangItem}; use rustc::traits; -use rustc::ty::subst::{Kind, Substs, Subst}; +use rustc::ty::subst::{Substs, Subst}; use rustc::ty::{self, TypeFoldable, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::{self, Location}; -use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; use context::SharedCrateContext; use common::{def_ty, instance_ty}; -use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; use trans_item::{TransItem, DefPathBasedNames, InstantiationMode}; -use std::iter; - #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { Eager, @@ -327,10 +323,6 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, let recursion_depth_reset; match starting_point { - TransItem::DropGlue(t) => { - find_drop_glue_neighbors(scx, t, &mut neighbors); - recursion_depth_reset = None; - } TransItem::Static(node_id) => { let def_id = scx.tcx().hir.local_def_id(node_id); let instance = Instance::mono(scx.tcx(), def_id); @@ -339,8 +331,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, debug_assert!(should_trans_locally(scx.tcx(), &instance)); let ty = instance_ty(scx, &instance); - let ty = glue::get_drop_glue_type(scx, ty); - neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); + visit_drop_use(scx, ty, true, &mut neighbors); recursion_depth_reset = None; @@ -396,6 +387,14 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); debug!(" => recursion depth={}", recursion_depth); + let recursion_depth = if Some(def_id) == tcx.lang_items.drop_in_place_fn() { + // HACK: drop_in_place creates tight monomorphization loops. Give + // it more margin. + recursion_depth / 4 + } else { + recursion_depth + }; + // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. @@ -521,27 +520,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_rvalue(rvalue, location); } - fn visit_lvalue(&mut self, - lvalue: &mir::Lvalue<'tcx>, - context: mir_visit::LvalueContext<'tcx>, - location: Location) { - debug!("visiting lvalue {:?}", *lvalue); - - if let mir_visit::LvalueContext::Drop = context { - let ty = lvalue.ty(self.mir, self.scx.tcx()) - .to_ty(self.scx.tcx()); - - let ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &ty); - assert!(ty.is_normalized_for_trans()); - let ty = glue::get_drop_glue_type(self.scx, ty); - self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); - } - - self.super_lvalue(lvalue, context, location); - } - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { debug!("visiting constant {:?} @ {:?}", *constant, location); @@ -568,54 +546,90 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { kind: &mir::TerminatorKind<'tcx>, location: Location) { let tcx = self.scx.tcx(); - if let mir::TerminatorKind::Call { - ref func, - .. - } = *kind { - let callee_ty = func.ty(self.mir, tcx); - let callee_ty = monomorphize::apply_param_substs( - self.scx, self.param_substs, &callee_ty); - visit_fn_use(self.scx, callee_ty, true, &mut self.output); + match *kind { + mir::TerminatorKind::Call { ref func, .. } => { + let callee_ty = func.ty(self.mir, tcx); + let callee_ty = monomorphize::apply_param_substs( + self.scx, self.param_substs, &callee_ty); + visit_fn_use(self.scx, callee_ty, true, &mut self.output); + } + mir::TerminatorKind::Drop { ref location, .. } | + mir::TerminatorKind::DropAndReplace { ref location, .. } => { + let ty = location.ty(self.mir, self.scx.tcx()) + .to_ty(self.scx.tcx()); + let ty = monomorphize::apply_param_substs(self.scx, + self.param_substs, + &ty); + visit_drop_use(self.scx, ty, true, self.output); + } + mir::TerminatorKind::Goto { .. } | + mir::TerminatorKind::SwitchInt { .. } | + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable | + mir::TerminatorKind::Assert { .. } => {} } self.super_terminator_kind(block, kind, location); } } +fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + ty: ty::Ty<'tcx>, + is_direct_call: bool, + output: &mut Vec>) +{ + let instance = monomorphize::resolve_drop_in_place(scx, ty); + visit_instance_use(scx, instance, is_direct_call, output); +} + fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, is_direct_call: bool, output: &mut Vec>) { - debug!("visit_fn_use({:?}, is_direct_call={:?})", ty, is_direct_call); - let (def_id, substs) = match ty.sty { - ty::TyFnDef(def_id, substs, _) => (def_id, substs), - _ => return - }; + if let ty::TyFnDef(def_id, substs, _) = ty.sty { + let instance = monomorphize::resolve(scx, def_id, substs); + visit_instance_use(scx, instance, is_direct_call, output); + } +} - let instance = monomorphize::resolve(scx, def_id, substs); +fn visit_instance_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + instance: ty::Instance<'tcx>, + is_direct_call: bool, + output: &mut Vec>) +{ + debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); if !should_trans_locally(scx.tcx(), &instance) { return } match instance.def { - ty::InstanceDef::Intrinsic(..) => { + ty::InstanceDef::Intrinsic(def_id) => { if !is_direct_call { - bug!("intrinsic {:?} being reified", ty); - } - if scx.tcx().item_name(def_id) == "drop_in_place" { - // drop_in_place is a call to drop glue, need to instantiate - // that. - let ty = glue::get_drop_glue_type(scx, substs.type_at(0)); - output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); + bug!("intrinsic {:?} being reified", def_id); } } - ty::InstanceDef::Virtual(..) => { + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::DropGlue(_, None) => { // don't need to emit shim if we are calling directly. if !is_direct_call { output.push(create_fn_trans_item(instance)); } } + ty::InstanceDef::DropGlue(_, Some(ty)) => { + match ty.sty { + ty::TyArray(ety, _) | + ty::TySlice(ety) + if is_direct_call => + { + // drop of arrays/slices is translated in-line. + visit_drop_use(scx, ety, false, output); + } + _ => {} + }; + output.push(create_fn_trans_item(instance)); + } ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) => { @@ -634,6 +648,7 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Virtual(..) | ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Intrinsic(_) => return true }; match tcx.hir.get_if_local(def_id) { @@ -658,124 +673,6 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan } } -fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - dg: DropGlueKind<'tcx>, - output: &mut Vec>) { - let ty = match dg { - DropGlueKind::Ty(ty) => ty, - DropGlueKind::TyContents(_) => { - // We already collected the neighbors of this item via the - // DropGlueKind::Ty variant. - return - } - }; - - debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty)); - - // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value. - if ty.is_box() { - let tcx = scx.tcx(); - let def_id = tcx.require_lang_item(BoxFreeFnLangItem); - let box_free_instance = Instance::new( - def_id, - tcx.mk_substs(iter::once(Kind::from(ty.boxed_ty()))) - ); - if should_trans_locally(tcx, &box_free_instance) { - output.push(create_fn_trans_item(box_free_instance)); - } - } - - // If the type implements Drop, also add a translation item for the - // monomorphized Drop::drop() implementation. - let has_dtor = match ty.sty { - ty::TyAdt(def, _) => def.has_dtor(scx.tcx()), - _ => false - }; - - if has_dtor && !ty.is_box() { - let drop_trait_def_id = scx.tcx() - .lang_items - .drop_trait() - .unwrap(); - let drop_method = scx.tcx().associated_items(drop_trait_def_id) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap().def_id; - let substs = scx.tcx().mk_substs_trait(ty, &[]); - let instance = monomorphize::resolve(scx, drop_method, substs); - if should_trans_locally(scx.tcx(), &instance) { - output.push(create_fn_trans_item(instance)); - } - - // This type has a Drop implementation, we'll need the contents-only - // version of the glue too. - output.push(TransItem::DropGlue(DropGlueKind::TyContents(ty))); - } - - // Finally add the types of nested values - match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyStr | - ty::TyFloat(_) | - ty::TyRawPtr(_) | - ty::TyRef(..) | - ty::TyFnDef(..) | - ty::TyFnPtr(_) | - ty::TyNever | - ty::TyDynamic(..) => { - /* nothing to do */ - } - ty::TyAdt(def, _) if def.is_box() => { - let inner_type = glue::get_drop_glue_type(scx, ty.boxed_ty()); - if scx.type_needs_drop(inner_type) { - output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type))); - } - } - ty::TyAdt(def, substs) => { - for field in def.all_fields() { - let field_type = def_ty(scx, field.did, substs); - let field_type = glue::get_drop_glue_type(scx, field_type); - - if scx.type_needs_drop(field_type) { - output.push(TransItem::DropGlue(DropGlueKind::Ty(field_type))); - } - } - } - ty::TyClosure(def_id, substs) => { - for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) { - let upvar_ty = glue::get_drop_glue_type(scx, upvar_ty); - if scx.type_needs_drop(upvar_ty) { - output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty))); - } - } - } - ty::TySlice(inner_type) | - ty::TyArray(inner_type, _) => { - let inner_type = glue::get_drop_glue_type(scx, inner_type); - if scx.type_needs_drop(inner_type) { - output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type))); - } - } - ty::TyTuple(args, _) => { - for arg in args { - let arg = glue::get_drop_glue_type(scx, arg); - if scx.type_needs_drop(arg) { - output.push(TransItem::DropGlue(DropGlueKind::Ty(arg))); - } - } - } - ty::TyProjection(_) | - ty::TyParam(_) | - ty::TyInfer(_) | - ty::TyAnon(..) | - ty::TyError => { - bug!("encountered unexpected type"); - } - } -} - /// For given pair of source and target type that occur in an unsizing coercion, /// this function finds the pair of types that determines the vtable linking /// them. @@ -894,8 +791,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, output.extend(methods); } // Also add the destructor - let dg_type = glue::get_drop_glue_type(scx, impl_ty); - output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); + visit_drop_use(scx, impl_ty, false, output); } } @@ -940,8 +836,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { def_id_to_string(self.scx.tcx(), def_id)); let ty = def_ty(self.scx, def_id, Substs::empty()); - let ty = glue::get_drop_glue_type(self.scx, ty); - self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); + visit_drop_use(self.scx, ty, true, self.output); } } } @@ -1093,12 +988,3 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, printer.push_def_path(def_id, &mut output); output } - -fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: ty::Ty<'tcx>) - -> String { - let mut output = String::new(); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_type_name(ty, &mut output); - output -} diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 431325c5ec74e..a0906bb02f5a3 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -535,16 +535,27 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn requests_inline<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &ty::Instance<'tcx> +) -> bool { + if is_inline_instance(tcx, instance) { + return true + } + attr::requests_inline(&instance.def.attrs(tcx)[..]) +} + +pub fn is_inline_instance<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: &ty::Instance<'tcx> ) -> bool { let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, + ty::InstanceDef::DropGlue(_, Some(_)) => return false, _ => return true }; match tcx.def_key(def_id).disambiguated_data.data { DefPathData::StructCtor | DefPathData::EnumVariant(..) | DefPathData::ClosureExpr => true, - _ => attr::requests_inline(&tcx.get_attrs(def_id)[..]), + _ => false } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 9297c0108468a..1c1395f1b7762 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -21,7 +21,6 @@ use debuginfo; use callee; use base; use declare; -use glue::DropGlueKind; use monomorphize::Instance; use partitioning::CodegenUnit; @@ -46,7 +45,7 @@ use std::str; use syntax::ast; use syntax::symbol::InternedString; use syntax_pos::DUMMY_SP; -use abi::{Abi, FnType}; +use abi::Abi; pub struct Stats { pub n_glues_created: Cell, @@ -94,8 +93,6 @@ pub struct LocalCrateContext<'tcx> { previous_work_product: Option, codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, - fn_pointer_shims: RefCell, ValueRef>>, - drop_glues: RefCell, (ValueRef, FnType)>>, /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, /// Cache generated vtables @@ -587,8 +584,6 @@ impl<'tcx> LocalCrateContext<'tcx> { previous_work_product: previous_work_product, codegen_unit: codegen_unit, needs_unwind_cleanup_cache: RefCell::new(FxHashMap()), - fn_pointer_shims: RefCell::new(FxHashMap()), - drop_glues: RefCell::new(FxHashMap()), instances: RefCell::new(FxHashMap()), vtables: RefCell::new(FxHashMap()), const_cstr_cache: RefCell::new(FxHashMap()), @@ -723,15 +718,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().needs_unwind_cleanup_cache } - pub fn fn_pointer_shims(&self) -> &RefCell, ValueRef>> { - &self.local().fn_pointer_shims - } - - pub fn drop_glues<'a>(&'a self) - -> &'a RefCell, (ValueRef, FnType)>> { - &self.local().drop_glues - } - pub fn instances<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().instances } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 9a639ed21f1ac..41a9ab2842dcd 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -13,69 +13,35 @@ // Code relating to drop glue. use std; -use std::iter; use llvm; -use llvm::{ValueRef, get_param}; -use middle::lang_items::BoxFreeFnLangItem; -use rustc::ty::subst::{Substs}; +use llvm::{ValueRef}; use rustc::traits; -use rustc::ty::{self, layout, AdtDef, AdtKind, Ty, TypeFoldable}; -use rustc::ty::subst::Kind; -use rustc::mir::tcx::LvalueTy; -use mir::lvalue::LvalueRef; -use abi::FnType; -use adt; -use base::*; -use callee::get_fn; -use cleanup::CleanupScope; +use rustc::ty::{self, Ty, TypeFoldable}; use common::*; use machine::*; +use meth; use monomorphize; -use trans_item::TransItem; -use tvec; -use type_of::{type_of, sizing_type_of, align_of}; -use type_::Type; +use type_of::{sizing_type_of, align_of}; use value::Value; -use Disr; use builder::Builder; -use mir::lvalue::Alignment; - -pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef<'tcx>) { - let content_ty = ptr.ty.to_ty(bcx.tcx()); - let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem); - let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty))); - let instance = monomorphize::resolve(bcx.ccx.shared(), def_id, substs); - - let fn_ty = FnType::from_instance(bcx.ccx, &instance, &[]); - let llret = bcx.call(get_fn(bcx.ccx, instance), - &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize], None); - fn_ty.apply_attrs_callsite(llret); -} - -pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { +pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>) -> bool { assert!(t.is_normalized_for_trans()); let t = scx.tcx().erase_regions(&t); - // Even if there is no dtor for t, there might be one deeper down and we - // might need to pass in the vtable ptr. - if !scx.type_is_sized(t) { - return t; - } - // FIXME (#22815): note that type_needs_drop conservatively // approximates in some cases and may say a type expression // requires drop glue when it actually does not. // // (In this case it is not clear whether any harm is done, i.e. - // erroneously returning `t` in some cases where we could have - // returned `tcx.types.i8` does not appear unsound. The impact on + // erroneously returning `true` in some cases where we could have + // returned `false` does not appear unsound. The impact on // code quality is unknown at this time.) if !scx.type_needs_drop(t) { - return scx.tcx().types.i8; + return false; } match t.sty { ty::TyAdt(def, _) if def.is_box() => { @@ -85,210 +51,19 @@ pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'t let layout = t.layout(&infcx).unwrap(); if layout.size(&scx.tcx().data_layout).bytes() == 0 { // `Box` does not allocate. - scx.tcx().types.i8 + false } else { - t + true } }) } else { - t + true } } - _ => t - } -} - -fn drop_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, args: LvalueRef<'tcx>) { - call_drop_glue(bcx, args, false, None) -} - -pub fn call_drop_glue<'a, 'tcx>( - bcx: &Builder<'a, 'tcx>, - mut args: LvalueRef<'tcx>, - skip_dtor: bool, - funclet: Option<&'a Funclet>, -) { - let t = args.ty.to_ty(bcx.tcx()); - // NB: v is an *alias* of type t here, not a direct value. - debug!("call_drop_glue(t={:?}, skip_dtor={})", t, skip_dtor); - if bcx.ccx.shared().type_needs_drop(t) { - let ccx = bcx.ccx; - let g = if skip_dtor { - DropGlueKind::TyContents(t) - } else { - DropGlueKind::Ty(t) - }; - let glue = get_drop_glue_core(ccx, g); - let glue_type = get_drop_glue_type(ccx.shared(), t); - if glue_type != t { - args.llval = bcx.pointercast(args.llval, type_of(ccx, glue_type).ptr_to()); - } - - // No drop-hint ==> call standard drop glue - bcx.call(glue, &[args.llval, args.llextra][..1 + args.has_extra() as usize], - funclet.map(|b| b.bundle())); + _ => true } } -pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef { - get_drop_glue_core(ccx, DropGlueKind::Ty(t)) -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum DropGlueKind<'tcx> { - /// The normal path; runs the dtor, and then recurs on the contents - Ty(Ty<'tcx>), - /// Skips the dtor, if any, for ty; drops the contents directly. - /// Note that the dtor is only skipped at the most *shallow* - /// level, namely, an `impl Drop for Ty` itself. So, for example, - /// if Ty is Newtype(S) then only the Drop impl for Newtype itself - /// will be skipped, while the Drop impl for S, if any, will be - /// invoked. - TyContents(Ty<'tcx>), -} - -impl<'tcx> DropGlueKind<'tcx> { - pub fn ty(&self) -> Ty<'tcx> { - match *self { DropGlueKind::Ty(t) | DropGlueKind::TyContents(t) => t } - } - - pub fn map_ty(&self, mut f: F) -> DropGlueKind<'tcx> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> - { - match *self { - DropGlueKind::Ty(t) => DropGlueKind::Ty(f(t)), - DropGlueKind::TyContents(t) => DropGlueKind::TyContents(f(t)), - } - } -} - -fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKind<'tcx>) -> ValueRef { - let g = g.map_ty(|t| get_drop_glue_type(ccx.shared(), t)); - match ccx.drop_glues().borrow().get(&g) { - Some(&(glue, _)) => glue, - None => { - bug!("Could not find drop glue for {:?} -- {} -- {}.", - g, - TransItem::DropGlue(g).to_raw_string(), - ccx.codegen_unit().name()); - } - } -} - -pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKind<'tcx>) { - assert_eq!(g.ty(), get_drop_glue_type(ccx.shared(), g.ty())); - let (llfn, _) = ccx.drop_glues().borrow().get(&g).unwrap().clone(); - - let mut bcx = Builder::new_block(ccx, llfn, "entry-block"); - - ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1); - // All glue functions take values passed *by alias*; this is a - // requirement since in many contexts glue is invoked indirectly and - // the caller has no idea if it's dealing with something that can be - // passed by value. - // - // llfn is expected be declared to take a parameter of the appropriate - // type, so we don't need to explicitly cast the function parameter. - - // NB: v0 is an *alias* of type t here, not a direct value. - // Only drop the value when it ... well, we used to check for - // non-null, (and maybe we need to continue doing so), but we now - // must definitely check for special bit-patterns corresponding to - // the special dtor markings. - let t = g.ty(); - - let value = get_param(llfn, 0); - let ptr = if ccx.shared().type_is_sized(t) { - LvalueRef::new_sized_ty(value, t, Alignment::AbiAligned) - } else { - LvalueRef::new_unsized_ty(value, get_param(llfn, 1), t, Alignment::AbiAligned) - }; - - let skip_dtor = match g { - DropGlueKind::Ty(_) => false, - DropGlueKind::TyContents(_) => true - }; - - let bcx = match t.sty { - ty::TyAdt(def, _) if def.is_box() => { - // Support for Box is built-in as yet and its drop glue is special - // despite having a dummy Drop impl in the library. - assert!(!skip_dtor); - let content_ty = t.boxed_ty(); - let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) { - let llbox = bcx.load(get_dataptr(&bcx, ptr.llval), None); - let info = bcx.load(get_meta(&bcx, ptr.llval), None); - LvalueRef::new_unsized_ty(llbox, info, content_ty, Alignment::AbiAligned) - } else { - LvalueRef::new_sized_ty( - bcx.load(ptr.llval, None), - content_ty, Alignment::AbiAligned) - }; - drop_ty(&bcx, ptr); - trans_exchange_free_ty(&bcx, ptr); - bcx - } - ty::TyDynamic(..) => { - // No support in vtable for distinguishing destroying with - // versus without calling Drop::drop. Assert caller is - // okay with always calling the Drop impl, if any. - assert!(!skip_dtor); - let dtor = bcx.load(ptr.llextra, None); - bcx.call(dtor, &[ptr.llval], None); - bcx - } - ty::TyAdt(def, ..) if def.has_dtor(bcx.tcx()) && !skip_dtor => { - let shallow_drop = def.is_union(); - let tcx = bcx.tcx(); - - // Be sure to put the contents into a scope so we can use an invoke - // instruction to call the user destructor but still call the field - // destructors if the user destructor panics. - // - // FIXME (#14875) panic-in-drop semantics might be unsupported; we - // might well consider changing below to more direct code. - // Issue #23611: schedule cleanup of contents, re-inspecting the - // discriminant (if any) in case of variant swap in drop code. - let contents_scope = if !shallow_drop { - CleanupScope::schedule_drop_adt_contents(&bcx, ptr) - } else { - CleanupScope::noop() - }; - let drop_trait_def_id = tcx.lang_items.drop_trait().unwrap(); - let drop_method = tcx.associated_items(drop_trait_def_id) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap().def_id; - let self_type_substs = tcx.mk_substs_trait(t, &[]); - let drop_instance = monomorphize::resolve( - bcx.ccx.shared(), drop_method, self_type_substs); - let fn_ty = FnType::from_instance(bcx.ccx, &drop_instance, &[]); - let llfn = get_fn(bcx.ccx, drop_instance); - let llret; - let args = &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize]; - if let Some(landing_pad) = contents_scope.landing_pad { - let normal_bcx = bcx.build_sibling_block("normal-return"); - llret = bcx.invoke(llfn, args, normal_bcx.llbb(), landing_pad, None); - bcx = normal_bcx; - } else { - llret = bcx.call(llfn, args, None); - } - fn_ty.apply_attrs_callsite(llret); - contents_scope.trans(&bcx); - bcx - } - ty::TyAdt(def, ..) if def.is_union() => { - bcx - } - _ => { - if bcx.ccx.shared().type_needs_drop(t) { - drop_structural_ty(bcx, ptr) - } else { - bcx - } - } - }; - bcx.ret_void(); -} - pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) -> (ValueRef, ValueRef) { debug!("calculate size of DST: {}; with lost info: {:?}", @@ -375,20 +150,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf (size, align) } ty::TyDynamic(..) => { - // info points to the vtable and the second entry in the vtable is the - // dynamic size of the object. - let info = bcx.pointercast(info, Type::int(bcx.ccx).ptr_to()); - let size_ptr = bcx.gepi(info, &[1]); - let align_ptr = bcx.gepi(info, &[2]); - - let size = bcx.load(size_ptr, None); - let align = bcx.load(align_ptr, None); - - // Vtable loads are invariant - bcx.set_invariant_load(size); - bcx.set_invariant_load(align); - - (size, align) + // load size/align from vtable + (meth::SIZE.get_usize(bcx, info), meth::ALIGN.get_usize(bcx, info)) } ty::TySlice(_) | ty::TyStr => { let unit_ty = t.sequence_element_type(bcx.tcx()); @@ -403,141 +166,3 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf _ => bug!("Unexpected unsized type, found {}", t) } } - -// Iterates through the elements of a structural type, dropping them. -fn drop_structural_ty<'a, 'tcx>( - cx: Builder<'a, 'tcx>, - mut ptr: LvalueRef<'tcx> -) -> Builder<'a, 'tcx> { - fn iter_variant_fields<'a, 'tcx>( - cx: &'a Builder<'a, 'tcx>, - av: LvalueRef<'tcx>, - adt_def: &'tcx AdtDef, - variant_index: usize, - substs: &'tcx Substs<'tcx> - ) { - let variant = &adt_def.variants[variant_index]; - let tcx = cx.tcx(); - for (i, field) in variant.fields.iter().enumerate() { - let arg = monomorphize::field_ty(tcx, substs, field); - let (field_ptr, align) = av.trans_field_ptr(&cx, i); - drop_ty(&cx, LvalueRef::new_sized_ty(field_ptr, arg, align)); - } - } - - let mut cx = cx; - let t = ptr.ty.to_ty(cx.tcx()); - match t.sty { - ty::TyClosure(def_id, substs) => { - for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() { - let (llupvar, align) = ptr.trans_field_ptr(&cx, i); - drop_ty(&cx, LvalueRef::new_sized_ty(llupvar, upvar_ty, align)); - } - } - ty::TyArray(_, n) => { - let base = get_dataptr(&cx, ptr.llval); - let len = C_uint(cx.ccx, n); - let unit_ty = t.sequence_element_type(cx.tcx()); - cx = tvec::slice_for_each(&cx, base, unit_ty, len, - |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty, ptr.alignment))); - } - ty::TySlice(_) | ty::TyStr => { - let unit_ty = t.sequence_element_type(cx.tcx()); - cx = tvec::slice_for_each(&cx, ptr.llval, unit_ty, ptr.llextra, - |bb, vv| drop_ty(bb, LvalueRef::new_sized_ty(vv, unit_ty, ptr.alignment))); - } - ty::TyTuple(ref args, _) => { - for (i, arg) in args.iter().enumerate() { - let (llfld_a, align) = ptr.trans_field_ptr(&cx, i); - drop_ty(&cx, LvalueRef::new_sized_ty(llfld_a, *arg, align)); - } - } - ty::TyAdt(adt, substs) => match adt.adt_kind() { - AdtKind::Struct => { - for (i, field) in adt.variants[0].fields.iter().enumerate() { - let field_ty = monomorphize::field_ty(cx.tcx(), substs, field); - let (llval, align) = ptr.trans_field_ptr(&cx, i); - let field_ptr = if cx.ccx.shared().type_is_sized(field_ty) { - LvalueRef::new_sized_ty(llval, field_ty, align) - } else { - LvalueRef::new_unsized_ty(llval, ptr.llextra, field_ty, align) - }; - drop_ty(&cx, field_ptr); - } - } - AdtKind::Union => { - bug!("Union in `glue::drop_structural_ty`"); - } - AdtKind::Enum => { - let n_variants = adt.variants.len(); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - - // Obtain a representation of the discriminant sufficient to translate - // destructuring; this may or may not involve the actual discriminant. - let l = cx.ccx.layout_of(t); - match *l { - layout::Univariant { .. } | - layout::UntaggedUnion { .. } => { - if n_variants != 0 { - assert!(n_variants == 1); - ptr.ty = LvalueTy::Downcast { - adt_def: adt, - substs: substs, - variant_index: 0, - }; - iter_variant_fields(&cx, ptr, &adt, 0, substs); - } - } - layout::CEnum { .. } | - layout::General { .. } | - layout::RawNullablePointer { .. } | - layout::StructWrappedNullablePointer { .. } => { - let lldiscrim_a = adt::trans_get_discr( - &cx, t, ptr.llval, ptr.alignment, None, false); - - // Create a fall-through basic block for the "else" case of - // the switch instruction we're about to generate. Note that - // we do **not** use an Unreachable instruction here, even - // though most of the time this basic block will never be hit. - // - // When an enum is dropped it's contents are currently - // overwritten to DTOR_DONE, which means the discriminant - // could have changed value to something not within the actual - // range of the discriminant. Currently this function is only - // used for drop glue so in this case we just return quickly - // from the outer function, and any other use case will only - // call this for an already-valid enum in which case the `ret - // void` will never be hit. - let ret_void_cx = cx.build_sibling_block("enum-iter-ret-void"); - ret_void_cx.ret_void(); - let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants); - let next_cx = cx.build_sibling_block("enum-iter-next"); - - for (i, discr) in adt.discriminants(cx.tcx()).enumerate() { - let variant_cx_name = format!("enum-iter-variant-{}", i); - let variant_cx = cx.build_sibling_block(&variant_cx_name); - let case_val = adt::trans_case(&cx, t, Disr::from(discr)); - variant_cx.add_case(llswitch, case_val, variant_cx.llbb()); - ptr.ty = LvalueTy::Downcast { - adt_def: adt, - substs: substs, - variant_index: i, - }; - iter_variant_fields(&variant_cx, ptr, &adt, i, substs); - variant_cx.br(next_cx.llbb()); - } - cx = next_cx; - } - _ => bug!("{} is not an enum.", t), - } - } - }, - - _ => { - cx.sess().unimpl(&format!("type in drop_structural_ty: {}", t)) - } - } - return cx; -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 49cc0b5fad401..f3e30ed4839ae 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -113,7 +113,6 @@ mod cabi_x86; mod cabi_x86_64; mod cabi_x86_win64; mod callee; -mod cleanup; mod collector; mod common; mod consts; diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 6b823756c8eab..75ab407614050 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -14,28 +14,45 @@ use callee; use common::*; use builder::Builder; use consts; -use glue; use machine; +use monomorphize; use type_::Type; use type_of::*; use value::Value; use rustc::ty; -// drop_glue pointer, size, align. -const VTABLE_OFFSET: usize = 3; - -/// Extracts a method from a trait object's vtable, at the specified index. -pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, - llvtable: ValueRef, - vtable_index: usize) -> ValueRef { - // Load the data pointer from the object. - debug!("get_virtual_method(vtable_index={}, llvtable={:?})", - vtable_index, Value(llvtable)); - - let ptr = bcx.load_nonnull(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None); - // Vtable loads are invariant - bcx.set_invariant_load(ptr); - ptr +#[derive(Copy, Clone, Debug)] +pub struct VirtualIndex(usize); + +pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0); +pub const SIZE: VirtualIndex = VirtualIndex(1); +pub const ALIGN: VirtualIndex = VirtualIndex(2); + +impl<'a, 'tcx> VirtualIndex { + pub fn from_index(index: usize) -> Self { + VirtualIndex(index + 3) + } + + pub fn get_fn(self, bcx: &Builder<'a, 'tcx>, llvtable: ValueRef) -> ValueRef { + // Load the data pointer from the object. + debug!("get_fn({:?}, {:?})", Value(llvtable), self); + + let ptr = bcx.load_nonnull(bcx.gepi(llvtable, &[self.0]), None); + // Vtable loads are invariant + bcx.set_invariant_load(ptr); + ptr + } + + pub fn get_usize(self, bcx: &Builder<'a, 'tcx>, llvtable: ValueRef) -> ValueRef { + // Load the data pointer from the object. + debug!("get_int({:?}, {:?})", Value(llvtable), self); + + let llvtable = bcx.pointercast(llvtable, Type::int(bcx.ccx).ptr_to()); + let ptr = bcx.load(bcx.gepi(llvtable, &[self.0]), None); + // Vtable loads are invariant + bcx.set_invariant_load(ptr); + ptr + } } /// Creates a dynamic vtable for the given type and vtable origin. @@ -68,8 +85,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let align = align_of(ccx, ty); let mut components: Vec<_> = [ - // Generate a destructor for the vtable. - glue::get_drop_glue(ccx, ty), + callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)), C_uint(ccx, size), C_uint(ccx, align) ].iter().cloned().collect(); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 761f6b208e747..226d40948c4dc 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -19,13 +19,13 @@ use base::{self, Lifetime}; use callee; use builder::Builder; use common::{self, Funclet}; -use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef}; +use common::{C_bool, C_str_slice, C_struct, C_u32, C_uint, C_undef}; use consts; use machine::llalign_of_min; use meth; use monomorphize; +use tvec; use type_of::{self, align_of}; -use glue; use type_::Type; use rustc_data_structures::indexed_vec::IndexVec; @@ -209,21 +209,49 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::TerminatorKind::Drop { ref location, target, unwind } => { let ty = location.ty(&self.mir, bcx.tcx()).to_ty(bcx.tcx()); let ty = self.monomorphize(&ty); + let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.shared(), ty); - // Double check for necessity to drop - if !bcx.ccx.shared().type_needs_drop(ty) { + if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + // we don't actually need to drop anything. funclet_br(self, bcx, target); - return; + return } - let mut lvalue = self.trans_lvalue(&bcx, location); - let drop_fn = glue::get_drop_glue(bcx.ccx, ty); - let drop_ty = glue::get_drop_glue_type(bcx.ccx.shared(), ty); - if bcx.ccx.shared().type_is_sized(ty) && drop_ty != ty { - lvalue.llval = bcx.pointercast( - lvalue.llval, type_of::type_of(bcx.ccx, drop_ty).ptr_to()); - } - let args = &[lvalue.llval, lvalue.llextra][..1 + lvalue.has_extra() as usize]; + let lvalue = self.trans_lvalue(&bcx, location); + let (drop_fn, need_extra) = match ty.sty { + ty::TyDynamic(..) => (meth::DESTRUCTOR.get_fn(&bcx, lvalue.llextra), + false), + ty::TyArray(ety, _) | ty::TySlice(ety) => { + // FIXME: handle panics + let drop_fn = monomorphize::resolve_drop_in_place( + bcx.ccx.shared(), ety); + let drop_fn = callee::get_fn(bcx.ccx, drop_fn); + let bcx = tvec::slice_for_each( + &bcx, + lvalue.project_index(&bcx, C_uint(bcx.ccx, 0u64)), + ety, + lvalue.len(bcx.ccx), + |bcx, llval, loop_bb| { + self.set_debug_loc(&bcx, terminator.source_info); + if let Some(unwind) = unwind { + bcx.invoke( + drop_fn, + &[llval], + loop_bb, + llblock(self, unwind), + cleanup_bundle + ); + } else { + bcx.call(drop_fn, &[llval], cleanup_bundle); + bcx.br(loop_bb); + } + }); + funclet_br(self, bcx, target); + return + } + _ => (callee::get_fn(bcx.ccx, drop_fn), lvalue.has_extra()) + }; + let args = &[lvalue.llval, lvalue.llextra][..1 + need_extra as usize]; if let Some(unwind) = unwind { bcx.invoke( drop_fn, @@ -417,23 +445,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { Some(ty::InstanceDef::Virtual(..)) => { FnType::new_vtable(bcx.ccx, sig, &extra_args) } - _ => FnType::new(bcx.ccx, sig, &extra_args) - }; - - if intrinsic == Some("drop_in_place") { - let &(_, target) = destination.as_ref().unwrap(); - let ty = instance.unwrap().substs.type_at(0); - - // Double check for necessity to drop - if !bcx.ccx.shared().type_needs_drop(ty) { + Some(ty::InstanceDef::DropGlue(_, None)) => { + // empty drop glue - a nop. + let &(_, target) = destination.as_ref().unwrap(); funclet_br(self, bcx, target); return; } - - let drop_fn = glue::get_drop_glue(bcx.ccx, ty); - let llty = fn_ty.llvm_type(bcx.ccx).ptr_to(); - llfn = Some(bcx.pointercast(drop_fn, llty)); - } + _ => FnType::new(bcx.ccx, sig, &extra_args) + }; // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize; @@ -588,7 +607,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (ptr, meta) = (a, b); if *next_idx == 0 { if let Some(ty::InstanceDef::Virtual(_, idx)) = *def { - let llmeth = meth::get_virtual_method(bcx, meta, idx); + let llmeth = meth::VirtualIndex::from_index(idx).get_fn(bcx, meta); let llty = fn_ty.llvm_type(bcx.ccx).ptr_to(); *llfn = Some(bcx.pointercast(llmeth, llty)); } @@ -756,14 +775,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { return block; } + let block = self.blocks[target_bb]; + let landing_pad = self.landing_pad_uncached(block); + self.landing_pads[target_bb] = Some(landing_pad); + landing_pad + } + + fn landing_pad_uncached(&mut self, target_bb: BasicBlockRef) -> BasicBlockRef { if base::wants_msvc_seh(self.ccx.sess()) { - return self.blocks[target_bb]; + return target_bb; } - let target = self.get_builder(target_bb); - let bcx = self.new_block("cleanup"); - self.landing_pads[target_bb] = Some(bcx.llbb()); let ccx = bcx.ccx; let llpersonality = self.ccx.eh_personality(); @@ -772,7 +795,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx.set_cleanup(llretval); let slot = self.get_personality_slot(&bcx); bcx.store(llretval, slot, None); - bcx.br(target.llbb()); + bcx.br(target_bb); bcx.llbb() } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 49e1e3855571b..dd8c1d0e1f031 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -27,7 +27,6 @@ use std::ptr; use std::ops; use super::{MirContext, LocalRef}; -use super::operand::OperandValue; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Alignment { @@ -95,16 +94,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> { LvalueRef::new_sized(llval, LvalueTy::from_ty(ty), alignment) } - pub fn new_unsized_ty(llval: ValueRef, llextra: ValueRef, ty: Ty<'tcx>, alignment: Alignment) - -> LvalueRef<'tcx> { - LvalueRef { - llval: llval, - llextra: llextra, - ty: LvalueTy::from_ty(ty), - alignment: alignment, - } - } - pub fn alloca(bcx: &Builder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> { debug!("alloca({:?}: {:?})", name, ty); let tmp = bcx.alloca(type_of::type_of(bcx.ccx, ty), name); @@ -279,6 +268,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> { _ => bug!("element access in type without elements: {} represented as {:#?}", t, l) } } + + pub fn project_index(&self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef { + if let ty::TySlice(_) = self.ty.to_ty(bcx.tcx()).sty { + // Slices already point to the array element type. + bcx.inbounds_gep(self.llval, &[llindex]) + } else { + let zero = common::C_uint(bcx.ccx, 0u64); + bcx.inbounds_gep(self.llval, &[zero, llindex]) + } + } } impl<'a, 'tcx> MirContext<'a, 'tcx> { @@ -314,21 +313,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { elem: mir::ProjectionElem::Deref }) => { // Load the pointer from its location. - let ptr = self.trans_consume(bcx, base); - let projected_ty = LvalueTy::from_ty(ptr.ty) - .projection_ty(tcx, &mir::ProjectionElem::Deref); - let projected_ty = self.monomorphize(&projected_ty); - let (llptr, llextra) = match ptr.val { - OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()), - OperandValue::Pair(llptr, llextra) => (llptr, llextra), - OperandValue::Ref(..) => bug!("Deref of by-Ref type {:?}", ptr.ty) - }; - LvalueRef { - llval: llptr, - llextra: llextra, - ty: projected_ty, - alignment: Alignment::AbiAligned, - } + self.trans_consume(bcx, base).deref() } mir::Lvalue::Projection(ref projection) => { let tr_base = self.trans_lvalue(bcx, &projection.base); @@ -336,17 +321,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let projected_ty = self.monomorphize(&projected_ty); let align = tr_base.alignment; - let project_index = |llindex| { - let element = if let ty::TySlice(_) = tr_base.ty.to_ty(tcx).sty { - // Slices already point to the array element type. - bcx.inbounds_gep(tr_base.llval, &[llindex]) - } else { - let zero = common::C_uint(bcx.ccx, 0u64); - bcx.inbounds_gep(tr_base.llval, &[zero, llindex]) - }; - (element, align) - }; - let ((llprojected, align), llextra) = match projection.elem { mir::ProjectionElem::Deref => bug!(), mir::ProjectionElem::Field(ref field, _) => { @@ -359,13 +333,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::ProjectionElem::Index(ref index) => { let index = self.trans_operand(bcx, index); - (project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut()) + let llindex = self.prepare_index(bcx, index.immediate()); + ((tr_base.project_index(bcx, llindex), align), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { let lloffset = C_uint(bcx.ccx, offset); - (project_index(lloffset), ptr::null_mut()) + ((tr_base.project_index(bcx, lloffset), align), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, @@ -373,11 +348,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let lloffset = C_uint(bcx.ccx, offset); let lllen = tr_base.len(bcx.ccx); let llindex = bcx.sub(lllen, lloffset); - (project_index(llindex), ptr::null_mut()) + ((tr_base.project_index(bcx, llindex), align), ptr::null_mut()) } mir::ProjectionElem::Subslice { from, to } => { - let llindex = C_uint(bcx.ccx, from); - let (llbase, align) = project_index(llindex); + let llbase = tr_base.project_index(bcx, C_uint(bcx.ccx, from)); let base_ty = tr_base.ty.to_ty(bcx.tcx()); match base_ty.sty { diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 3f29545ecf45a..da24c03fdc2a0 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -9,9 +9,10 @@ // except according to those terms. use llvm::ValueRef; -use rustc::ty::Ty; +use rustc::ty::{self, Ty}; use rustc::ty::layout::Layout; use rustc::mir; +use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; use base; @@ -22,9 +23,10 @@ use type_of; use type_::Type; use std::fmt; +use std::ptr; use super::{MirContext, LocalRef}; -use super::lvalue::Alignment; +use super::lvalue::{Alignment, LvalueRef}; /// The representation of a Rust value. The enum variant is in fact /// uniquely determined by the value's type, but is kept as a @@ -86,6 +88,22 @@ impl<'a, 'tcx> OperandRef<'tcx> { } } + pub fn deref(self) -> LvalueRef<'tcx> { + let projected_ty = self.ty.builtin_deref(true, ty::NoPreference) + .unwrap().ty; + let (llptr, llextra) = match self.val { + OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()), + OperandValue::Pair(llptr, llextra) => (llptr, llextra), + OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) + }; + LvalueRef { + llval: llptr, + llextra: llextra, + ty: LvalueTy::from_ty(projected_ty), + alignment: Alignment::AbiAligned, + } + } + /// If this operand is a Pair, we return an /// Immediate aggregate with the two values. pub fn pack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> { @@ -236,7 +254,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Operand::Constant(ref constant) => { - let val = self.trans_constant(bcx, constant); + let val = self.trans_constant(&bcx, constant); let operand = val.to_operand(bcx.ccx); if let OperandValue::Ref(ptr, align) = operand.val { // If this is a OperandValue::Ref to an immediate constant, load it. diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 178347369c915..d487aa6cd5be6 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -98,8 +98,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let size = count.as_u64(bcx.tcx().sess.target.uint_type); let size = C_uint(bcx.ccx, size); let base = base::get_dataptr(&bcx, dest.llval); - tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| { + tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot, loop_bb| { self.store_operand(bcx, llslot, dest.alignment.to_align(), tr_elem); + bcx.br(loop_bb); }) } @@ -459,7 +460,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; (bcx, operand) } - mir::Rvalue::Use(ref operand) => { let operand = self.trans_operand(&bcx, operand); (bcx, operand) @@ -662,7 +662,7 @@ pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) | mir::Rvalue::Box(..) | - mir::Rvalue::Use(..) => + mir::Rvalue::Use(..) => // (*) true, mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 0d8aa0f4bda0e..fcf6937d4b6d5 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -10,9 +10,11 @@ use abi::Abi; use common::*; +use glue; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; +use rustc::middle::lang_items::DropInPlaceFnLangItem; use rustc::traits::{self, SelectionContext, Reveal}; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::ty::fold::{TypeFolder, TypeFoldable}; @@ -242,8 +244,19 @@ pub fn resolve<'a, 'tcx>( ty::InstanceDef::Intrinsic(def_id) } _ => { - debug!(" => free item"); - ty::InstanceDef::Item(def_id) + if Some(def_id) == scx.tcx().lang_items.drop_in_place_fn() { + let ty = substs.type_at(0); + if glue::needs_drop_glue(scx, ty) { + debug!(" => nontrivial drop glue"); + ty::InstanceDef::DropGlue(def_id, Some(ty)) + } else { + debug!(" => trivial drop glue"); + ty::InstanceDef::DropGlue(def_id, None) + } + } else { + debug!(" => free item"); + ty::InstanceDef::Item(def_id) + } } }; Instance { def, substs } @@ -253,6 +266,16 @@ pub fn resolve<'a, 'tcx>( result } +pub fn resolve_drop_in_place<'a, 'tcx>( + scx: &SharedCrateContext<'a, 'tcx>, + ty: Ty<'tcx>) + -> ty::Instance<'tcx> +{ + let def_id = scx.tcx().require_lang_item(DropInPlaceFnLangItem); + let substs = scx.tcx().intern_substs(&[Kind::from(ty)]); + resolve(scx, def_id, substs) +} + pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index d0cf32508d44c..90ce40cfbcf8f 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -194,7 +194,6 @@ impl<'tcx> CodegenUnit<'tcx> { TransItem::Static(node_id) => { exported_symbols.contains(&node_id) } - TransItem::DropGlue(..) => false, }; exported.hash(&mut state); } @@ -245,7 +244,6 @@ impl<'tcx> CodegenUnit<'tcx> { tcx.hir.as_local_node_id(instance.def_id()) } TransItem::Static(node_id) => Some(node_id), - TransItem::DropGlue(_) => None, } } } @@ -341,7 +339,6 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, match trans_item { TransItem::Fn(..) | TransItem::Static(..) => llvm::ExternalLinkage, - TransItem::DropGlue(..) => unreachable!(), } } }; @@ -461,6 +458,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Intrinsic(..) | + ty::InstanceDef::DropGlue(..) | ty::InstanceDef::Virtual(..) => return None }; @@ -485,7 +483,6 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't Some(def_id) } - TransItem::DropGlue(dg) => characteristic_def_id_of_type(dg.ty()), TransItem::Static(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index cd285bfaa6010..1b48e131b720a 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -100,7 +100,6 @@ impl<'tcx> SymbolMap<'tcx> { tcx.hir.as_local_node_id(def.def_id()) } TransItem::Static(node_id) => Some(node_id), - TransItem::DropGlue(_) => None, }.map(|node_id| { tcx.hir.span(node_id) }) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 13af081e0b698..410e3f30be731 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -20,28 +20,23 @@ use consts; use context::{CrateContext, SharedCrateContext}; use common; use declare; -use glue::DropGlueKind; use llvm; use monomorphize::Instance; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::hir::map::definitions::DefPathData; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; use rustc_const_eval::fatal_const_eval_err; use syntax::ast::{self, NodeId}; use syntax::attr; use type_of; -use glue; -use abi::{Abi, FnType}; use back::symbol_names; use std::fmt::Write; use std::iter; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { - DropGlue(DropGlueKind<'tcx>), Fn(Instance<'tcx>), Static(NodeId) } @@ -100,9 +95,6 @@ impl<'a, 'tcx> TransItem<'tcx> { base::trans_instance(&ccx, instance); } - TransItem::DropGlue(dg) => { - glue::implement_drop_glue(&ccx, dg); - } } debug!("END IMPLEMENTING '{} ({})' in cgu {}", @@ -131,9 +123,6 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(instance) => { TransItem::predefine_fn(ccx, instance, linkage, &symbol_name); } - TransItem::DropGlue(dg) => { - TransItem::predefine_drop_glue(ccx, dg, linkage, &symbol_name); - } } debug!("END PREDEFINING '{} ({})' in cgu {}", @@ -180,52 +169,14 @@ impl<'a, 'tcx> TransItem<'tcx> { } debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); - match ccx.tcx().def_key(instance.def_id()).disambiguated_data.data { - DefPathData::StructCtor | - DefPathData::EnumVariant(..) | - DefPathData::ClosureExpr => { - attributes::inline(lldecl, attributes::InlineAttr::Hint); - } - _ => {} + if common::is_inline_instance(ccx.tcx(), &instance) { + attributes::inline(lldecl, attributes::InlineAttr::Hint); } - attributes::from_fn_attrs(ccx, &attrs, lldecl); ccx.instances().borrow_mut().insert(instance, lldecl); } - fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>, - dg: glue::DropGlueKind<'tcx>, - linkage: llvm::Linkage, - symbol_name: &str) { - let tcx = ccx.tcx(); - assert_eq!(dg.ty(), glue::get_drop_glue_type(ccx.shared(), dg.ty())); - let t = dg.ty(); - - let sig = tcx.mk_fn_sig( - iter::once(tcx.mk_mut_ptr(t)), - tcx.mk_nil(), - false, - hir::Unsafety::Normal, - Abi::Rust - ); - - debug!("predefine_drop_glue: sig={}", sig); - - let fn_ty = FnType::new(ccx, sig, &[]); - let llfnty = fn_ty.llvm_type(ccx); - - assert!(declare::get_defined_value(ccx, symbol_name).is_none()); - let llfn = declare::declare_cfn(ccx, symbol_name, llfnty); - unsafe { llvm::LLVMRustSetLinkage(llfn, linkage) }; - if linkage == llvm::Linkage::LinkOnceODRLinkage || - linkage == llvm::Linkage::WeakODRLinkage { - llvm::SetUniqueComdat(ccx.llmod(), llfn); - } - attributes::set_frame_pointer_elimination(ccx, llfn); - ccx.drop_glues().borrow_mut().insert(dg, (llfn, fn_ty)); - } - pub fn compute_symbol_name(&self, scx: &SharedCrateContext<'a, 'tcx>) -> String { match *self { @@ -234,13 +185,6 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = scx.tcx().hir.local_def_id(node_id); symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) } - TransItem::DropGlue(dg) => { - let prefix = match dg { - DropGlueKind::Ty(_) => "drop", - DropGlueKind::TyContents(_) => "drop_contents", - }; - symbol_names::exported_name_from_type_and_prefix(scx, dg.ty(), prefix) - } } } @@ -257,7 +201,6 @@ impl<'a, 'tcx> TransItem<'tcx> { InstantiationMode::GloballyShared } } - TransItem::DropGlue(..) => InstantiationMode::LocalCopy, TransItem::Static(..) => InstantiationMode::GloballyShared, } } @@ -267,7 +210,6 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } - TransItem::DropGlue(..) | TransItem::Static(..) => false, } } @@ -276,7 +218,6 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = match *self { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), - TransItem::DropGlue(..) => return None, }; let attributes = tcx.get_attrs(def_id); @@ -300,16 +241,6 @@ impl<'a, 'tcx> TransItem<'tcx> { let hir_map = &tcx.hir; return match *self { - TransItem::DropGlue(dg) => { - let mut s = String::with_capacity(32); - match dg { - DropGlueKind::Ty(_) => s.push_str("drop-glue "), - DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), - }; - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_type_name(dg.ty(), &mut s); - s - } TransItem::Fn(instance) => { to_string_internal(tcx, "fn ", instance) }, @@ -334,13 +265,6 @@ impl<'a, 'tcx> TransItem<'tcx> { pub fn to_raw_string(&self) -> String { match *self { - TransItem::DropGlue(dg) => { - let prefix = match dg { - DropGlueKind::Ty(_) => "Ty", - DropGlueKind::TyContents(_) => "TyContents", - }; - format!("DropGlue({}: {})", prefix, dg.ty() as *const _ as usize) - } TransItem::Fn(instance) => { format!("Fn({:?}, {})", instance.def, diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index cbcbb02bdc890..4216a73a8dd85 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -10,7 +10,7 @@ use llvm; use builder::Builder; -use llvm::ValueRef; +use llvm::{BasicBlockRef, ValueRef}; use common::*; use rustc::ty::Ty; @@ -20,7 +20,7 @@ pub fn slice_for_each<'a, 'tcx, F>( unit_ty: Ty<'tcx>, len: ValueRef, f: F -) -> Builder<'a, 'tcx> where F: FnOnce(&Builder<'a, 'tcx>, ValueRef) { +) -> Builder<'a, 'tcx> where F: FnOnce(&Builder<'a, 'tcx>, ValueRef, BasicBlockRef) { // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) let zst = type_is_zero_size(bcx.ccx, unit_ty); let add = |bcx: &Builder, a, b| if zst { @@ -46,9 +46,8 @@ pub fn slice_for_each<'a, 'tcx, F>( let keep_going = header_bcx.icmp(llvm::IntNE, current, end); header_bcx.cond_br(keep_going, body_bcx.llbb(), next_bcx.llbb()); - f(&body_bcx, if zst { data_ptr } else { current }); let next = add(&body_bcx, current, C_uint(bcx.ccx, 1usize)); + f(&body_bcx, if zst { data_ptr } else { current }, header_bcx.llbb()); header_bcx.add_incoming_to_phi(current, next, body_bcx.llbb()); - body_bcx.br(header_bcx.llbb()); next_bcx } diff --git a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs index ada1234b852a1..eb4f9e8e28e2d 100644 --- a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs +++ b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs @@ -30,5 +30,3 @@ fn main() // This should not introduce a codegen item let _ = cgu_generic_function::exported_but_not_generic(3); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs index db940b680473a..d8e6028b799fb 100644 --- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -11,8 +11,7 @@ // ignore-tidy-linelength // compile-flags:-Zprint-trans-items=eager -//~ TRANS_ITEM drop-glue drop_in_place_intrinsic::StructWithDtor[0] -//~ TRANS_ITEM drop-glue-contents drop_in_place_intrinsic::StructWithDtor[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic.cgu-0[Internal] struct StructWithDtor(u32); impl Drop for StructWithDtor { @@ -23,7 +22,7 @@ impl Drop for StructWithDtor { //~ TRANS_ITEM fn drop_in_place_intrinsic::main[0] fn main() { - //~ TRANS_ITEM drop-glue [drop_in_place_intrinsic::StructWithDtor[0]; 2] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic.cgu-0[Internal] let x = [StructWithDtor(0), StructWithDtor(1)]; drop_slice_in_place(&x); @@ -35,7 +34,7 @@ fn drop_slice_in_place(x: &[StructWithDtor]) { // This is the interesting thing in this test case: Normally we would // not have drop-glue for the unsized [StructWithDtor]. This has to be // generated though when the drop_in_place() intrinsic is used. - //~ TRANS_ITEM drop-glue [drop_in_place_intrinsic::StructWithDtor[0]] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic.cgu-0[Internal] ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]); } } diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs index 51df38cabef30..c4aed7465bcb0 100644 --- a/src/test/codegen-units/item-collection/function-as-argument.rs +++ b/src/test/codegen-units/item-collection/function-as-argument.rs @@ -44,5 +44,3 @@ fn main() { //~ TRANS_ITEM fn function_as_argument::function[0] take_fn_pointer(function, 0f32, 0i64); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs index 6da8154540574..06e02b100152e 100644 --- a/src/test/codegen-units/item-collection/generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs @@ -45,8 +45,7 @@ enum EnumNoDrop { struct NonGenericNoDrop(i32); struct NonGenericWithDrop(i32); -//~ TRANS_ITEM drop-glue generic_drop_glue::NonGenericWithDrop[0] -//~ TRANS_ITEM drop-glue-contents generic_drop_glue::NonGenericWithDrop[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue.cgu-0[Internal] impl Drop for NonGenericWithDrop { //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] @@ -55,13 +54,11 @@ impl Drop for NonGenericWithDrop { //~ TRANS_ITEM fn generic_drop_glue::main[0] fn main() { - //~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0] - //~ TRANS_ITEM drop-glue-contents generic_drop_glue::StructWithDrop[0] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue.cgu-0[Internal] //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] let _ = StructWithDrop { x: 0i8, y: 'a' }.x; - //~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> - //~ TRANS_ITEM drop-glue-contents generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue.cgu-0[Internal] //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; @@ -70,19 +67,17 @@ fn main() { // This is supposed to generate drop-glue because it contains a field that // needs to be dropped. - //~ TRANS_ITEM drop-glue generic_drop_glue::StructNoDrop[0] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue.cgu-0[Internal] let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; - //~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0] - //~ TRANS_ITEM drop-glue-contents generic_drop_glue::EnumWithDrop[0] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue.cgu-0[Internal] //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; - //~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0] - //~ TRANS_ITEM drop-glue-contents generic_drop_glue::EnumWithDrop[0] + //~TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue.cgu-0[Internal] //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, @@ -99,5 +94,3 @@ fn main() { EnumNoDrop::B(x) => x as f64 }; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index ad466671cf79b..9c6bdb6624eae 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -31,12 +31,13 @@ impl Trait for Struct { fn main() { let s1 = Struct { _a: 0u32 }; - //~ TRANS_ITEM drop-glue i8 + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable.cgu-0[Internal] //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable.cgu-0[Internal] //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; diff --git a/src/test/codegen-units/item-collection/items-within-generic-items.rs b/src/test/codegen-units/item-collection/items-within-generic-items.rs index a2dcd81b6750c..75d842d3c0bfc 100644 --- a/src/test/codegen-units/item-collection/items-within-generic-items.rs +++ b/src/test/codegen-units/item-collection/items-within-generic-items.rs @@ -40,5 +40,3 @@ fn main() { //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0] let _ = generic_fn(0i8); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs index 91be81a0b8996..5f70ff396ddd5 100644 --- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs @@ -13,8 +13,7 @@ #![deny(dead_code)] -//~ TRANS_ITEM drop-glue non_generic_drop_glue::StructWithDrop[0] -//~ TRANS_ITEM drop-glue-contents non_generic_drop_glue::StructWithDrop[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue.cgu-0[Internal] struct StructWithDrop { x: i32 } @@ -28,8 +27,7 @@ struct StructNoDrop { x: i32 } -//~ TRANS_ITEM drop-glue non_generic_drop_glue::EnumWithDrop[0] -//~ TRANS_ITEM drop-glue-contents non_generic_drop_glue::EnumWithDrop[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue.cgu-0[Internal] enum EnumWithDrop { A(i32) } @@ -54,5 +52,3 @@ fn main() { EnumNoDrop::A(x) => x }; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/non-generic-functions.rs b/src/test/codegen-units/item-collection/non-generic-functions.rs index 4e2a7c8508468..26f9eb11876cb 100644 --- a/src/test/codegen-units/item-collection/non-generic-functions.rs +++ b/src/test/codegen-units/item-collection/non-generic-functions.rs @@ -77,5 +77,3 @@ fn main() { let x = Struct { _x: 0 }; x.bar(); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/overloaded-operators.rs b/src/test/codegen-units/item-collection/overloaded-operators.rs index 0295311334b6b..05848a727e951 100644 --- a/src/test/codegen-units/item-collection/overloaded-operators.rs +++ b/src/test/codegen-units/item-collection/overloaded-operators.rs @@ -68,5 +68,3 @@ impl Deref for Equatable { &self.0 } } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs index 41c0f46f80bfb..3c9dcf32e0c78 100644 --- a/src/test/codegen-units/item-collection/static-init.rs +++ b/src/test/codegen-units/item-collection/static-init.rs @@ -20,4 +20,3 @@ pub fn foo() { } fn main() { } //~ TRANS_ITEM fn static_init::main[0] -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/statics-and-consts.rs b/src/test/codegen-units/item-collection/statics-and-consts.rs index 7c8b2b117ef7c..89bc620b7c552 100644 --- a/src/test/codegen-units/item-collection/statics-and-consts.rs +++ b/src/test/codegen-units/item-collection/statics-and-consts.rs @@ -60,5 +60,3 @@ fn main() { //~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[2] //~ TRANS_ITEM fn statics_and_consts::main[0] - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/trait-implementations.rs b/src/test/codegen-units/item-collection/trait-implementations.rs index 2eb2212f0cacd..e8a7d8f25b22c 100644 --- a/src/test/codegen-units/item-collection/trait-implementations.rs +++ b/src/test/codegen-units/item-collection/trait-implementations.rs @@ -78,5 +78,3 @@ fn main() { //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> 0f32.bar("&str", "&str"); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs index f7afd3f0891e3..f095b637a84e4 100644 --- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs +++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs @@ -64,5 +64,3 @@ fn main() { //~ TRANS_ITEM fn core::ops[0]::FnMut[0]::call_mut[0] u32, (u32)> take_foo_mut(Trait::foo, 'c'); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs index 47892781902ea..5b24a219f354b 100644 --- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs +++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs @@ -66,5 +66,3 @@ fn main() { //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0u32.bar(0i16, ()); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs index 81a7059fe209f..e41cb34eec6ab 100644 --- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs +++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs @@ -13,12 +13,11 @@ #![deny(dead_code)] -//~ TRANS_ITEM drop-glue transitive_drop_glue::Root[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue.cgu-0[Internal] struct Root(Intermediate); -//~ TRANS_ITEM drop-glue transitive_drop_glue::Intermediate[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue.cgu-0[Internal] struct Intermediate(Leaf); -//~ TRANS_ITEM drop-glue transitive_drop_glue::Leaf[0] -//~ TRANS_ITEM drop-glue-contents transitive_drop_glue::Leaf[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue.cgu-0[Internal] struct Leaf; impl Drop for Leaf { @@ -39,17 +38,15 @@ fn main() { let _ = Root(Intermediate(Leaf)); - //~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0] - //~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0] - //~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0] - //~ TRANS_ITEM drop-glue-contents transitive_drop_glue::LeafGen[0] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue.cgu-0[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue.cgu-0[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue.cgu-0[Internal] //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0u32))); - //~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0] - //~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0] - //~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0] - //~ TRANS_ITEM drop-glue-contents transitive_drop_glue::LeafGen[0] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue.cgu-0[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue.cgu-0[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue.cgu-0[Internal] //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0i16))); } diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs index ef4bc1dca594c..39043cf87cbec 100644 --- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs +++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs @@ -13,8 +13,7 @@ #![deny(dead_code)] -//~ TRANS_ITEM drop-glue tuple_drop_glue::Dropped[0] -//~ TRANS_ITEM drop-glue-contents tuple_drop_glue::Dropped[0] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue.cgu-0[Internal] struct Dropped; impl Drop for Dropped { @@ -24,10 +23,10 @@ impl Drop for Dropped { //~ TRANS_ITEM fn tuple_drop_glue::main[0] fn main() { - //~ TRANS_ITEM drop-glue (u32, tuple_drop_glue::Dropped[0]) + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue.cgu-0[Internal] let x = (0u32, Dropped); - //~ TRANS_ITEM drop-glue (i16, (tuple_drop_glue::Dropped[0], bool)) - //~ TRANS_ITEM drop-glue (tuple_drop_glue::Dropped[0], bool) + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue.cgu-0[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue.cgu-0[Internal] let x = (0i16, (Dropped, true)); } diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index cd4cc258f7a68..de7613741b27b 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -57,11 +57,13 @@ fn main() { // simple case let bool_sized = &true; - //~ TRANS_ITEM drop-glue i8 + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing.cgu-0[Internal] //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0] let _bool_unsized = bool_sized as &Trait; - let char_sized = &true; + let char_sized = &'a'; + + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing.cgu-0[Internal] //~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0] let _char_unsized = char_sized as &Trait; @@ -71,11 +73,13 @@ fn main() _b: 2, _c: 3.0f64 }; + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing.cgu-0[Internal] //~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0] let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing.cgu-0[Internal] //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } diff --git a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs index 8689beb3fb77e..ce85c4fc13ce2 100644 --- a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs +++ b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs @@ -86,4 +86,3 @@ impl NonGeneric { // Only the non-generic methods should be instantiated: //~ TRANS_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 910ffd2959ed0..f28c4872111c9 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -20,15 +20,14 @@ // aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; -//~ TRANS_ITEM drop-glue cgu_extern_drop_glue::Struct[0] @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal] -//~ TRANS_ITEM drop-glue-contents cgu_extern_drop_glue::Struct[0] @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal] struct LocalStruct(cgu_extern_drop_glue::Struct); //~ TRANS_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] fn user() { - //~ TRANS_ITEM drop-glue extern_drop_glue::LocalStruct[0] @@ extern_drop_glue[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } @@ -40,7 +39,7 @@ mod mod1 { //~ TRANS_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] fn user() { - //~ TRANS_ITEM drop-glue extern_drop_glue::mod1[0]::LocalStruct[0] @@ extern_drop_glue-mod1[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-mod1[Internal] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } } diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index db36b50702a43..e32c946f8554f 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -60,5 +60,3 @@ mod mod3 { // once for the current crate //~ TRANS_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function.volatile[External] //~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[External] - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index f61e3fe12931e..64f4f854c2d7f 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -16,8 +16,7 @@ #![allow(dead_code)] #![crate_type="lib"] -//~ TRANS_ITEM drop-glue local_drop_glue::Struct[0] @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] -//~ TRANS_ITEM drop-glue-contents local_drop_glue::Struct[0] @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] struct Struct { _a: u32 } @@ -27,7 +26,7 @@ impl Drop for Struct { fn drop(&mut self) {} } -//~ TRANS_ITEM drop-glue local_drop_glue::Outer[0] @@ local_drop_glue[Internal] +//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] struct Outer { _a: Struct } @@ -46,10 +45,10 @@ mod mod1 { use super::Struct; - //~ TRANS_ITEM drop-glue local_drop_glue::mod1[0]::Struct2[0] @@ local_drop_glue-mod1[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-mod1[Internal] struct Struct2 { _a: Struct, - //~ TRANS_ITEM drop-glue (u32, local_drop_glue::Struct[0]) @@ local_drop_glue-mod1[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-mod1[Internal] _b: (u32, Struct), } diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index 4da6411032168..07c341203f9e2 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -80,5 +80,3 @@ mod mod2 { static BAZ: u64 = 0; } } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index ffe1ec278b8dd..d06b3ac407a7f 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -46,5 +46,3 @@ mod mod1 { static BAR: u32 = 0; } } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index 7a0217072f32c..c4594bb547ef5 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -69,7 +69,7 @@ mod mod1 { //~ TRANS_ITEM fn vtable_through_const::main[0] @@ vtable_through_const[External] fn main() { - //~ TRANS_ITEM drop-glue i8 @@ vtable_through_const[Internal] + //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ vtable_through_const[Internal] // Since Trait1::do_something() is instantiated via its default implementation, // it is considered a generic and is instantiated here only because it is From db00ba9eb2afa1a3db24e208cbd63125d0157090 Mon Sep 17 00:00:00 2001 From: David Roundy Date: Tue, 1 Dec 2015 17:29:56 -0500 Subject: [PATCH 113/662] Fix race condition in fs::create_dir_all It is more robust to not fail if any directory in a path was created concurrently. This change lifts rustc internal `create_dir_racy` that was created to handle such conditions to be new `create_dir_all` implementation. --- src/librustc/util/fs.rs | 20 ------------------ src/librustc_incremental/persist/fs.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/libstd/fs.rs | 24 ++++++++++++++++++---- src/tools/compiletest/src/runtest.rs | 28 ++++++-------------------- 5 files changed, 28 insertions(+), 48 deletions(-) diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index da6a202e5afb2..090753b18c0ba 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -109,23 +109,3 @@ pub fn rename_or_copy_remove, Q: AsRef>(p: P, } } } - -// Like std::fs::create_dir_all, except handles concurrent calls among multiple -// threads or processes. -pub fn create_dir_racy(path: &Path) -> io::Result<()> { - match fs::create_dir(path) { - Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => (), - Err(e) => return Err(e), - } - match path.parent() { - Some(p) => try!(create_dir_racy(p)), - None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")), - } - match fs::create_dir(path) { - Ok(()) => Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), - Err(e) => Err(e), - } -} diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 2ad37e98c708a..2a4a01cd4a453 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -461,7 +461,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { } fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(),()> { - match fs_util::create_dir_racy(path) { + match std_fs::create_dir_all(path) { Ok(()) => { debug!("{} directory created successfully", dir_tag); Ok(()) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 111c8370be2b1..1cc73a3dce045 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -885,7 +885,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, }, }; - if let Err(e) = rustc::util::fs::create_dir_racy(&root_path) { + if let Err(e) = std::fs::create_dir_all(&root_path) { tcx.sess.err(&format!("Could not create directory {}: {}", root_path.display(), e)); diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index b074e8b86b9a3..bb8b4064fab7a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1534,6 +1534,12 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// error conditions for when a directory is being created (after it is /// determined to not exist) are outlined by `fs::create_dir`. /// +/// Notable exception is made for situations where any of the directories +/// specified in the `path` could not be created as it was created concurrently. +/// Such cases are considered success. In other words: calling `create_dir_all` +/// concurrently from multiple threads or processes is guaranteed to not fail +/// due to race itself. +/// /// # Examples /// /// ``` @@ -1769,11 +1775,21 @@ impl DirBuilder { } fn create_dir_all(&self, path: &Path) -> io::Result<()> { - if path == Path::new("") || path.is_dir() { return Ok(()) } - if let Some(p) = path.parent() { - self.create_dir_all(p)? + match self.inner.mkdir(path) { + Ok(()) => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(e) => return Err(e), + } + match path.parent() { + Some(p) => try!(create_dir_all(p)), + None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")), + } + match self.inner.mkdir(path) { + Ok(()) => Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), + Err(e) => Err(e), } - self.inner.mkdir(path) } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1ec0838d45f76..2865fa6a79253 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -25,7 +25,7 @@ use util::logv; use std::collections::HashSet; use std::env; use std::fmt; -use std::fs::{self, File}; +use std::fs::{self, File, create_dir_all}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; @@ -395,7 +395,7 @@ actual:\n\ let out_dir = self.output_base_name().with_extension("pretty-out"); let _ = fs::remove_dir_all(&out_dir); - self.create_dir_racy(&out_dir); + create_dir_all(&out_dir).unwrap(); // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec!["-".to_owned(), @@ -1269,7 +1269,7 @@ actual:\n\ fn compose_and_run_compiler(&self, args: ProcArgs, input: Option) -> ProcRes { if !self.props.aux_builds.is_empty() { - self.create_dir_racy(&self.aux_output_dir_name()); + create_dir_all(&self.aux_output_dir_name()).unwrap(); } let aux_dir = self.aux_output_dir_name(); @@ -1340,22 +1340,6 @@ actual:\n\ input) } - // Like std::fs::create_dir_all, except handles concurrent calls among multiple - // threads or processes. - fn create_dir_racy(&self, path: &Path) { - match fs::create_dir(path) { - Ok(()) => return, - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return, - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(e) => panic!("failed to create dir {:?}: {}", path, e), - } - self.create_dir_racy(path.parent().unwrap()); - match fs::create_dir(path) { - Ok(()) => {} - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {} - Err(e) => panic!("failed to create dir {:?}: {}", path, e), - } - } fn compose_and_run(&self, ProcArgs{ args, prog }: ProcArgs, @@ -1435,7 +1419,7 @@ actual:\n\ let mir_dump_dir = self.get_mir_dump_dir(); - self.create_dir_racy(mir_dump_dir.as_path()); + create_dir_all(mir_dump_dir.as_path()).unwrap(); let mut dir_opt = "dump-mir-dir=".to_string(); dir_opt.push_str(mir_dump_dir.to_str().unwrap()); debug!("dir_opt: {:?}", dir_opt); @@ -1923,7 +1907,7 @@ actual:\n\ let out_dir = self.output_base_name(); let _ = fs::remove_dir_all(&out_dir); - self.create_dir_racy(&out_dir); + create_dir_all(&out_dir).unwrap(); let proc_res = self.document(&out_dir); if !proc_res.status.success() { @@ -2299,7 +2283,7 @@ actual:\n\ if tmpdir.exists() { self.aggressive_rm_rf(&tmpdir).unwrap(); } - self.create_dir_racy(&tmpdir); + create_dir_all(&tmpdir).unwrap(); let host = &self.config.host; let make = if host.contains("bitrig") || host.contains("dragonfly") || From 0ec28b796d1206c4442f0269febe2a1cc0794411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Sat, 11 Mar 2017 08:04:30 -0800 Subject: [PATCH 114/662] Fix new version of `create_dir_all` It will now correctly fail on existing non-directories. --- src/libstd/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index bb8b4064fab7a..6a465e38f3810 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1777,7 +1777,7 @@ impl DirBuilder { fn create_dir_all(&self, path: &Path) -> io::Result<()> { match self.inner.mkdir(path) { Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && path.is_dir() => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} Err(e) => return Err(e), } @@ -1787,7 +1787,7 @@ impl DirBuilder { } match self.inner.mkdir(path) { Ok(()) => Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && path.is_dir() => Ok(()), Err(e) => Err(e), } } From f2adee74a318503334c07290ca767fd609aebf1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Sun, 12 Mar 2017 23:07:16 -0700 Subject: [PATCH 115/662] Add `concurrent_recursive_mkdir` test --- src/libstd/fs.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 6a465e38f3810..7ba88d6a3e13c 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1782,7 +1782,7 @@ impl DirBuilder { Err(e) => return Err(e), } match path.parent() { - Some(p) => try!(create_dir_all(p)), + Some(p) => try!(self.create_dir_all(p)), None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")), } match self.inner.mkdir(path) { @@ -1809,6 +1809,7 @@ mod tests { use rand::{StdRng, Rng}; use str; use sys_common::io::test::{TempDir, tmpdir}; + use thread; #[cfg(windows)] use os::windows::fs::{symlink_dir, symlink_file}; @@ -2276,6 +2277,26 @@ mod tests { assert!(result.is_err()); } + #[test] + fn concurrent_recursive_mkdir() { + for _ in 0..100 { + let mut dir = tmpdir().join("a"); + for _ in 0..100 { + dir = dir.join("a"); + } + let mut join = vec!(); + for _ in 0..8 { + let dir = dir.clone(); + join.push(thread::spawn(move || { + check!(fs::create_dir_all(&dir)); + })) + } + + // No `Display` on result of `join()` + join.drain(..).map(|join| join.join().unwrap()).count(); + } + } + #[test] fn recursive_mkdir_slash() { check!(fs::create_dir_all(&Path::new("/"))); From a51c6aaf848a6cd64ace890effb6e377bbefce7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Mon, 13 Mar 2017 22:29:00 -0700 Subject: [PATCH 116/662] Break line longer than 100 characters --- src/libstd/fs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 7ba88d6a3e13c..e26b84d6b0786 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1777,7 +1777,8 @@ impl DirBuilder { fn create_dir_all(&self, path: &Path) -> io::Result<()> { match self.inner.mkdir(path) { Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && path.is_dir() => return Ok(()), + Err(ref e) + if e.kind() == io::ErrorKind::AlreadyExists && path.is_dir() => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} Err(e) => return Err(e), } From c3e2eaf4cb774f776f4022406742f978580c0a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Tue, 14 Mar 2017 22:29:00 -0700 Subject: [PATCH 117/662] Fix problems found on Windows in `dir_create_all` Ignore the type of error altogether. The rationale is: it doesn't matter what was the problem if the directory is there. In the previous versions if the directory was there already we wouldn't even attempt to create it, so we wouldn't know about the problem neither. Make test path length smaller in `concurrent_recursive_mkdir` test. --- src/libstd/fs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index e26b84d6b0786..91cf0d44d9d8b 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1777,8 +1777,7 @@ impl DirBuilder { fn create_dir_all(&self, path: &Path) -> io::Result<()> { match self.inner.mkdir(path) { Ok(()) => return Ok(()), - Err(ref e) - if e.kind() == io::ErrorKind::AlreadyExists && path.is_dir() => return Ok(()), + Err(_) if path.is_dir() => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} Err(e) => return Err(e), } @@ -1788,7 +1787,7 @@ impl DirBuilder { } match self.inner.mkdir(path) { Ok(()) => Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && path.is_dir() => Ok(()), + Err(_) if path.is_dir() => Ok(()), Err(e) => Err(e), } } @@ -2280,7 +2279,7 @@ mod tests { #[test] fn concurrent_recursive_mkdir() { - for _ in 0..100 { + for _ in 0..50 { let mut dir = tmpdir().join("a"); for _ in 0..100 { dir = dir.join("a"); From bcae6a3734cdcecffc3ee30981a5b9107bee2ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Tue, 14 Mar 2017 22:29:00 -0700 Subject: [PATCH 118/662] Reorder match checks in `create_dir_all` Avoid doing `is_dir` in the fast path. --- src/libstd/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 91cf0d44d9d8b..59a6a99201f1e 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1777,8 +1777,8 @@ impl DirBuilder { fn create_dir_all(&self, path: &Path) -> io::Result<()> { match self.inner.mkdir(path) { Ok(()) => return Ok(()), - Err(_) if path.is_dir() => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(_) if path.is_dir() => return Ok(()), Err(e) => return Err(e), } match path.parent() { From b5d590b3f0483bc943df8f59011b85500456d748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Tue, 14 Mar 2017 22:03:00 -0700 Subject: [PATCH 119/662] Fix `create_dir_all("")` Add a test for `""` and `"."`. --- src/libstd/fs.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 59a6a99201f1e..cc9df743ef1da 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1775,6 +1775,10 @@ impl DirBuilder { } fn create_dir_all(&self, path: &Path) -> io::Result<()> { + if path == Path::new("") { + return Ok(()) + } + match self.inner.mkdir(path) { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} @@ -2302,6 +2306,16 @@ mod tests { check!(fs::create_dir_all(&Path::new("/"))); } + #[test] + fn recursive_mkdir_dot() { + check!(fs::create_dir_all(&Path::new("."))); + } + + #[test] + fn recursive_mkdir_empty() { + check!(fs::create_dir_all(&Path::new(""))); + } + #[test] fn recursive_rmdir() { let tmpdir = tmpdir(); From 60c1c961c73cd347e389d7961a7ba82396103029 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 17 Mar 2017 20:38:32 -0700 Subject: [PATCH 120/662] Make priv in pub hard error for crates using pub(restricted) --- src/librustc/hir/mod.rs | 12 ++++++ src/librustc_privacy/lib.rs | 38 ++++++++++++++++++- .../privacy/restricted/private-in-public.rs | 4 -- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 22bc28eb3fec0..7a9468cf7d2e1 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1468,6 +1468,18 @@ pub enum Visibility { Inherited, } +impl Visibility { + pub fn is_pub_restricted(&self) -> bool { + use self::Visibility::*; + match self { + &Public | + &Inherited => false, + &Crate | + &Restricted { .. } => true, + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct StructField { pub span: Span, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 074e2b873ec60..e32ec25a7e8f7 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -45,6 +45,26 @@ use std::mem::replace; pub mod diagnostics; +//////////////////////////////////////////////////////////////////////////////// +/// Visitor used to determine if pub(restricted) is used anywhere in the crate. +/// +/// This is done so that `private_in_public` warnings can be turned into hard errors +/// in crates that have been updated to use pub(restricted). +//////////////////////////////////////////////////////////////////////////////// +struct PubRestrictedVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + has_pub_restricted: bool, +} + +impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.tcx.hir) + } + fn visit_vis(&mut self, vis: &'tcx hir::Visibility) { + self.has_pub_restricted = self.has_pub_restricted || vis.is_pub_restricted(); + } +} + //////////////////////////////////////////////////////////////////////////////// /// The embargo visitor, used to determine the exports of the ast //////////////////////////////////////////////////////////////////////////////// @@ -891,6 +911,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> { required_visibility: ty::Visibility, /// The visibility of the least visible component that has been visited min_visibility: ty::Visibility, + has_pub_restricted: bool, has_old_errors: bool, } @@ -951,7 +972,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' self.min_visibility = vis; } if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.has_old_errors { + if self.has_pub_restricted || self.has_old_errors { let mut err = struct_span_err!(self.tcx.sess, self.span, E0446, "private type `{}` in public interface", ty); err.span_label(self.span, &format!("can't leak private type")); @@ -986,7 +1007,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' self.min_visibility = vis; } if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.has_old_errors { + if self.has_pub_restricted || self.has_old_errors { struct_span_err!(self.tcx.sess, self.span, E0445, "private trait `{}` in public interface", trait_ref) .span_label(self.span, &format!( @@ -1008,6 +1029,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + has_pub_restricted: bool, old_error_set: &'a NodeSet, inner_visibility: ty::Visibility, } @@ -1044,6 +1066,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { span: self.tcx.hir.span(item_id), min_visibility: ty::Visibility::Public, required_visibility: required_visibility, + has_pub_restricted: self.has_pub_restricted, has_old_errors: has_old_errors, } } @@ -1227,9 +1250,20 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; intravisit::walk_crate(&mut visitor, krate); + + let has_pub_restricted = { + let mut pub_restricted_visitor = PubRestrictedVisitor { + tcx: tcx, + has_pub_restricted: false + }; + intravisit::walk_crate(&mut pub_restricted_visitor, krate); + pub_restricted_visitor.has_pub_restricted + }; + // Check for private types and traits in public interfaces let mut visitor = PrivateItemsInPublicInterfacesVisitor { tcx: tcx, + has_pub_restricted: has_pub_restricted, old_error_set: &visitor.old_error_set, inner_visibility: ty::Visibility::Public, }; diff --git a/src/test/compile-fail/privacy/restricted/private-in-public.rs b/src/test/compile-fail/privacy/restricted/private-in-public.rs index 2f06362880315..0fdfbaa84bb5a 100644 --- a/src/test/compile-fail/privacy/restricted/private-in-public.rs +++ b/src/test/compile-fail/privacy/restricted/private-in-public.rs @@ -8,16 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] -#![allow(unused)] - mod foo { struct Priv; mod bar { use foo::Priv; pub(super) fn f(_: Priv) {} pub(crate) fn g(_: Priv) {} //~ ERROR E0446 - //~^ this was previously accepted } } From 9fb737b7b5ca1eae4b83574f43d178ea80b291be Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Mar 2017 20:47:35 -0700 Subject: [PATCH 121/662] Update the cargo submodule again Unfortunately it was reverted back to a broken state in e06c51553ddc202a79f2c0b76822ad56c4a30f80 by accident, so let's bring it forward again! --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 5f3b9c4c6a7be..c995e9eb5acf3 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 5f3b9c4c6a7be1f177d6024cb83d150b6479148a +Subproject commit c995e9eb5acf3976ae8674a0dc6d9e958053d9fd From fc04eaacc5bd5760e98cd3aa390dcc3ae795d12f Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 28 Feb 2017 11:05:03 -0800 Subject: [PATCH 122/662] Implement ? in catch expressions and add tests --- src/librustc/cfg/construct.rs | 94 ++++++-- src/librustc/hir/intravisit.rs | 18 +- src/librustc/hir/lowering.rs | 89 +++++--- src/librustc/hir/mod.rs | 21 +- src/librustc/middle/liveness.rs | 135 ++++++----- src/librustc_mir/build/expr/into.rs | 18 +- src/librustc_mir/build/expr/stmt.rs | 12 +- src/librustc_mir/build/mod.rs | 6 +- src/librustc_mir/build/scope.rs | 49 ++-- src/librustc_mir/hair/cx/expr.rs | 23 +- src/librustc_passes/loops.rs | 25 +- src/librustc_typeck/check/mod.rs | 240 +++++++++++++------- src/test/compile-fail/catch-bad-lifetime.rs | 35 +++ src/test/compile-fail/catch-bad-type.rs | 21 ++ src/test/compile-fail/catch-opt-init.rs | 22 ++ src/test/run-pass/catch-expr.rs | 34 +++ 16 files changed, 570 insertions(+), 272 deletions(-) create mode 100644 src/test/compile-fail/catch-bad-lifetime.rs create mode 100644 src/test/compile-fail/catch-bad-type.rs create mode 100644 src/test/compile-fail/catch-opt-init.rs diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 7a70eda955b69..777408457d1f6 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -22,13 +22,20 @@ struct CFGBuilder<'a, 'tcx: 'a> { graph: CFGGraph, fn_exit: CFGIndex, loop_scopes: Vec, + breakable_block_scopes: Vec, +} + +#[derive(Copy, Clone)] +struct BlockScope { + block_expr_id: ast::NodeId, // id of breakable block expr node + break_index: CFGIndex, // where to go on `break` } #[derive(Copy, Clone)] struct LoopScope { loop_id: ast::NodeId, // id of loop/while node continue_index: CFGIndex, // where to go on a `loop` - break_index: CFGIndex, // where to go on a `break + break_index: CFGIndex, // where to go on a `break` } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -53,6 +60,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, graph: graph, fn_exit: fn_exit, loop_scopes: Vec::new(), + breakable_block_scopes: Vec::new(), }; body_exit = cfg_builder.expr(&body.value, entry); cfg_builder.add_contained_edge(body_exit, fn_exit); @@ -66,14 +74,34 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { - let mut stmts_exit = pred; - for stmt in &blk.stmts { - stmts_exit = self.stmt(stmt, stmts_exit); - } + if let Some(break_to_expr_id) = blk.break_to_expr_id { + let expr_exit = self.add_ast_node(blk.id, &[]); + + self.breakable_block_scopes.push(BlockScope { + block_expr_id: break_to_expr_id, + break_index: expr_exit, + }); + + let mut stmts_exit = pred; + for stmt in &blk.stmts { + stmts_exit = self.stmt(stmt, stmts_exit); + } + let blk_expr_exit = self.opt_expr(&blk.expr, stmts_exit); + self.add_contained_edge(blk_expr_exit, blk_expr_exit); + + self.breakable_block_scopes.pop(); + + expr_exit + } else { + let mut stmts_exit = pred; + for stmt in &blk.stmts { + stmts_exit = self.stmt(stmt, stmts_exit); + } - let expr_exit = self.opt_expr(&blk.expr, stmts_exit); + let expr_exit = self.opt_expr(&blk.expr, stmts_exit); - self.add_ast_node(blk.id, &[expr_exit]) + self.add_ast_node(blk.id, &[expr_exit]) + } } fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex { @@ -295,18 +323,18 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprBreak(destination, ref opt_expr) => { let v = self.opt_expr(opt_expr, pred); - let loop_scope = self.find_scope(expr, destination); + let (scope_id, break_dest) = + self.find_scope_edge(expr, destination, ScopeCfKind::Break); let b = self.add_ast_node(expr.id, &[v]); - self.add_exiting_edge(expr, b, - loop_scope, loop_scope.break_index); + self.add_exiting_edge(expr, b, scope_id, break_dest); self.add_unreachable_node() } hir::ExprAgain(destination) => { - let loop_scope = self.find_scope(expr, destination); + let (scope_id, cont_dest) = + self.find_scope_edge(expr, destination, ScopeCfKind::Continue); let a = self.add_ast_node(expr.id, &[pred]); - self.add_exiting_edge(expr, a, - loop_scope, loop_scope.continue_index); + self.add_exiting_edge(expr, a, scope_id, cont_dest); self.add_unreachable_node() } @@ -552,11 +580,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn add_exiting_edge(&mut self, from_expr: &hir::Expr, from_index: CFGIndex, - to_loop: LoopScope, + scope_id: ast::NodeId, to_index: CFGIndex) { let mut data = CFGEdgeData { exiting_scopes: vec![] }; let mut scope = self.tcx.region_maps.node_extent(from_expr.id); - let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id); + let target_scope = self.tcx.region_maps.node_extent(scope_id); while scope != target_scope { data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps)); scope = self.tcx.region_maps.encl_scope(scope); @@ -576,20 +604,42 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.graph.add_edge(from_index, self.fn_exit, data); } - fn find_scope(&self, + fn find_scope_edge(&self, expr: &hir::Expr, - destination: hir::Destination) -> LoopScope { - - match destination.loop_id.into() { - Ok(loop_id) => { + destination: hir::Destination, + scope_cf_kind: ScopeCfKind) -> (ast::NodeId, CFGIndex) { + + match destination.target_id { + hir::ScopeTarget::Block(block_expr_id) => { + for b in &self.breakable_block_scopes { + if b.block_expr_id == block_expr_id { + return (block_expr_id, match scope_cf_kind { + ScopeCfKind::Break => b.break_index, + ScopeCfKind::Continue => bug!("can't continue to block"), + }); + } + } + span_bug!(expr.span, "no block expr for id {}", block_expr_id); + } + hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => { for l in &self.loop_scopes { if l.loop_id == loop_id { - return *l; + return (loop_id, match scope_cf_kind { + ScopeCfKind::Break => l.break_index, + ScopeCfKind::Continue => l.continue_index, + }); } } span_bug!(expr.span, "no loop scope for id {}", loop_id); } - Err(err) => span_bug!(expr.span, "loop scope error: {}", err), + hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => + span_bug!(expr.span, "loop scope error: {}", err), } } } + +#[derive(Copy, Clone, Eq, PartialEq)] +enum ScopeCfKind { + Break, + Continue, +} diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index fd6796ccc0bf2..f59b8b757f5cc 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1008,18 +1008,24 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } ExprBreak(label, ref opt_expr) => { label.ident.map(|ident| { - if let Ok(loop_id) = label.loop_id.into() { - visitor.visit_def_mention(Def::Label(loop_id)); - } + match label.target_id { + ScopeTarget::Block(node_id) | + ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => + visitor.visit_def_mention(Def::Label(node_id)), + ScopeTarget::Loop(LoopIdResult::Err(_)) => {}, + }; visitor.visit_name(ident.span, ident.node.name); }); walk_list!(visitor, visit_expr, opt_expr); } ExprAgain(label) => { label.ident.map(|ident| { - if let Ok(loop_id) = label.loop_id.into() { - visitor.visit_def_mention(Def::Label(loop_id)); - } + match label.target_id { + ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"), + ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => + visitor.visit_def_mention(Def::Label(node_id)), + ScopeTarget::Loop(LoopIdResult::Err(_)) => {}, + }; visitor.visit_name(ident.span, ident.node.name); }); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d92eaee6f0c8e..4a927261bdafb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -356,22 +356,26 @@ impl<'a> LoweringContext<'a> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } - fn lower_destination(&mut self, destination: Option<(NodeId, Spanned)>) + fn lower_loop_destination(&mut self, destination: Option<(NodeId, Spanned)>) -> hir::Destination { match destination { - Some((id, label_ident)) => hir::Destination { - ident: Some(label_ident), - loop_id: if let Def::Label(loop_id) = self.expect_full_def(id) { + Some((id, label_ident)) => { + let target = if let Def::Label(loop_id) = self.expect_full_def(id) { hir::LoopIdResult::Ok(loop_id) } else { hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel) + }; + hir::Destination { + ident: Some(label_ident), + target_id: hir::ScopeTarget::Loop(target), } }, None => hir::Destination { ident: None, - loop_id: self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id)) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into() + target_id: hir::ScopeTarget::Loop( + self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id)) + .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into()) } } } @@ -990,7 +994,7 @@ impl<'a> LoweringContext<'a> { bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() } - fn lower_block(&mut self, b: &Block) -> P { + fn lower_block(&mut self, b: &Block, break_to: Option) -> P { let mut expr = None; let mut stmts = b.stmts.iter().flat_map(|s| self.lower_stmt(s)).collect::>(); @@ -1008,6 +1012,7 @@ impl<'a> LoweringContext<'a> { expr: expr, rules: self.lower_block_check_mode(&b.rules), span: b.span, + break_to_expr_id: break_to, }) } @@ -1085,7 +1090,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { self.with_new_scopes(|this| { - let body = this.lower_block(body); + let body = this.lower_block(body, None); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); hir::ItemFn(this.lower_fn_decl(decl), @@ -1179,7 +1184,7 @@ impl<'a> LoweringContext<'a> { hir::TraitMethod::Required(names)) } TraitItemKind::Method(ref sig, Some(ref body)) => { - let body = this.lower_block(body); + let body = this.lower_block(body, None); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::TraitItemKind::Method(this.lower_method_sig(sig), @@ -1235,7 +1240,7 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), body_id) } ImplItemKind::Method(ref sig, ref body) => { - let body = this.lower_block(body); + let body = this.lower_block(body, None); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) @@ -1662,6 +1667,7 @@ impl<'a> LoweringContext<'a> { id: id, rules: hir::DefaultBlock, span: span, + break_to_expr_id: None, }); P(self.expr_block(blk, ThinVec::new())) } @@ -1669,24 +1675,24 @@ impl<'a> LoweringContext<'a> { } }); - hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt) + hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) } ExprKind::While(ref cond, ref body, opt_ident) => { self.with_loop_scope(e.id, |this| hir::ExprWhile( this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body), + this.lower_block(body, None), this.lower_opt_sp_ident(opt_ident))) } ExprKind::Loop(ref body, opt_ident) => { self.with_loop_scope(e.id, |this| - hir::ExprLoop(this.lower_block(body), + hir::ExprLoop(this.lower_block(body, None), this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } ExprKind::Catch(ref body) => { - // FIXME(cramertj): Add catch to HIR - self.with_catch_scope(e.id, |this| hir::ExprBlock(this.lower_block(body))) + self.with_catch_scope(e.id, |this| + hir::ExprBlock(this.lower_block(body, Some(e.id)))) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), @@ -1704,7 +1710,7 @@ impl<'a> LoweringContext<'a> { }) }) } - ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)), + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), ExprKind::Assign(ref el, ref er) => { hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) } @@ -1783,10 +1789,11 @@ impl<'a> LoweringContext<'a> { let label_result = if self.is_in_loop_condition && opt_ident.is_none() { hir::Destination { ident: opt_ident, - loop_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(), + target_id: hir::ScopeTarget::Loop( + Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()), } } else { - self.lower_destination(opt_ident.map(|ident| (e.id, ident))) + self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident))) }; hir::ExprBreak( label_result, @@ -1797,11 +1804,11 @@ impl<'a> LoweringContext<'a> { if self.is_in_loop_condition && opt_ident.is_none() { hir::Destination { ident: opt_ident, - loop_id: Err( - hir::LoopIdError::UnlabeledCfInWhileCondition).into(), + target_id: hir::ScopeTarget::Loop(Err( + hir::LoopIdError::UnlabeledCfInWhileCondition).into()), } } else { - self.lower_destination(opt_ident.map( |ident| (e.id, ident))) + self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident))) }), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), ExprKind::InlineAsm(ref asm) => { @@ -1859,7 +1866,7 @@ impl<'a> LoweringContext<'a> { // ` => ` let pat_arm = { - let body = self.lower_block(body); + let body = self.lower_block(body, None); let body_expr = P(self.expr_block(body, ThinVec::new())); let pat = self.lower_pat(pat); self.arm(hir_vec![pat], body_expr) @@ -1946,7 +1953,7 @@ impl<'a> LoweringContext<'a> { // Note that the block AND the condition are evaluated in the loop scope. // This is done to allow `break` from inside the condition of the loop. let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( - this.lower_block(body), + this.lower_block(body, None), this.expr_break(e.span, ThinVec::new()), this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), )); @@ -2007,7 +2014,8 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::Some() => ` let pat_arm = { - let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body)); + let body_block = self.with_loop_scope(e.id, + |this| this.lower_block(body, None)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); let pat = self.lower_pat(pat); let some_pat = self.pat_some(e.span, pat); @@ -2090,14 +2098,12 @@ impl<'a> LoweringContext<'a> { // match Carrier::translate() { // Ok(val) => #[allow(unreachable_code)] val, // Err(err) => #[allow(unreachable_code)] + // // If there is an enclosing `catch {...}` + // break 'catch_target Carrier::from_error(From::from(err)), + // // Otherwise // return Carrier::from_error(From::from(err)), // } - // FIXME(cramertj): implement breaking to catch - if !self.catch_scopes.is_empty() { - bug!("`?` in catch scopes is unimplemented") - } - let unstable_span = self.allow_internal_unstable("?", e.span); // Carrier::translate() @@ -2157,9 +2163,24 @@ impl<'a> LoweringContext<'a> { P(self.expr_call(e.span, from_err, hir_vec![from_expr])) }; - let ret_expr = P(self.expr(e.span, - hir::Expr_::ExprRet(Some(from_err_expr)), - ThinVec::from(attrs))); + let thin_attrs = ThinVec::from(attrs); + let catch_scope = self.catch_scopes.last().map(|x| *x); + let ret_expr = if let Some(catch_node) = catch_scope { + P(self.expr( + e.span, + hir::ExprBreak( + hir::Destination { + ident: None, + target_id: hir::ScopeTarget::Block(catch_node), + }, + Some(from_err_expr) + ), + thin_attrs)) + } else { + P(self.expr(e.span, + hir::Expr_::ExprRet(Some(from_err_expr)), + thin_attrs)) + }; let err_pat = self.pat_err(e.span, err_local); self.arm(hir_vec![err_pat], ret_expr) @@ -2302,7 +2323,7 @@ impl<'a> LoweringContext<'a> { } fn expr_break(&mut self, span: Span, attrs: ThinVec) -> P { - let expr_break = hir::ExprBreak(self.lower_destination(None), None); + let expr_break = hir::ExprBreak(self.lower_loop_destination(None), None); P(self.expr(span, expr_break, attrs)) } @@ -2415,6 +2436,7 @@ impl<'a> LoweringContext<'a> { id: self.next_id(), rules: hir::DefaultBlock, span: span, + break_to_expr_id: None, } } @@ -2519,6 +2541,7 @@ impl<'a> LoweringContext<'a> { id: id, stmts: stmts, expr: Some(expr), + break_to_expr_id: None, }); self.expr_block(block, attrs) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 22bc28eb3fec0..d5f496b90035d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -485,6 +485,9 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, + /// The id of the expression that `break` breaks to if the block can be broken out of. + /// Currently only `Some(_)` for `catch {}` blocks + pub break_to_expr_id: Option, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] @@ -1080,6 +1083,22 @@ impl From> for LoopIdResult { } } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum ScopeTarget { + Block(NodeId), + Loop(LoopIdResult), +} + +impl ScopeTarget { + pub fn opt_id(self) -> Option { + match self { + ScopeTarget::Block(node_id) | + ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => Some(node_id), + ScopeTarget::Loop(LoopIdResult::Err(_)) => None, + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub struct Destination { // This is `Some(_)` iff there is an explicit user-specified `label @@ -1087,7 +1106,7 @@ pub struct Destination { // These errors are caught and then reported during the diagnostics pass in // librustc_passes/loops.rs - pub loop_id: LoopIdResult, + pub target_id: ScopeTarget, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index a8c1559ae2373..769dc8aeb54dd 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -516,14 +516,15 @@ struct Liveness<'a, 'tcx: 'a> { s: Specials, successors: Vec, users: Vec, - // The list of node IDs for the nested loop scopes - // we're in. - loop_scope: Vec, + // mappings from loop node ID to LiveNode // ("break" label should map to loop node ID, // it probably doesn't now) break_ln: NodeMap, - cont_ln: NodeMap + cont_ln: NodeMap, + + // mappings from node ID to LiveNode for "breakable" blocks-- currently only `catch {...}` + breakable_block_ln: NodeMap, } impl<'a, 'tcx> Liveness<'a, 'tcx> { @@ -550,9 +551,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { s: specials, successors: vec![invalid_node(); num_live_nodes], users: vec![invalid_users(); num_live_nodes * num_vars], - loop_scope: Vec::new(), break_ln: NodeMap(), cont_ln: NodeMap(), + breakable_block_ln: NodeMap(), } } @@ -793,15 +794,17 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!("compute: using id for body, {}", self.ir.tcx.hir.node_to_pretty_string(body.id)); let exit_ln = self.s.exit_ln; - let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| { - // the fallthrough exit is only for those cases where we do not - // explicitly return: - let s = this.s; - this.init_from_succ(s.fallthrough_ln, s.exit_ln); - this.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); - - this.propagate_through_expr(body, s.fallthrough_ln) - }); + + self.break_ln.insert(body.id, exit_ln); + self.cont_ln.insert(body.id, exit_ln); + + // the fallthrough exit is only for those cases where we do not + // explicitly return: + let s = self.s; + self.init_from_succ(s.fallthrough_ln, s.exit_ln); + self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); + + let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln); // hack to skip the loop unless debug! is enabled: debug!("^^ liveness computation results for body {} (entry={:?})", @@ -818,6 +821,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { + if let Some(break_to_expr_id) = blk.break_to_expr_id { + self.breakable_block_ln.insert(break_to_expr_id, succ); + } let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); blk.stmts.iter().rev().fold(succ, |succ, stmt| { self.propagate_through_stmt(stmt, succ) @@ -901,30 +907,32 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprClosure(.., blk_id, _) => { - debug!("{} is an ExprClosure", - self.ir.tcx.hir.node_to_pretty_string(expr.id)); + debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id)); /* The next-node for a break is the successor of the entire loop. The next-node for a continue is the top of this loop. */ let node = self.live_node(expr.id, expr.span); - self.with_loop_nodes(blk_id.node_id, succ, node, |this| { - - // the construction of a closure itself is not important, - // but we have to consider the closed over variables. - let caps = match this.ir.capture_info_map.get(&expr.id) { - Some(caps) => caps.clone(), - None => { - span_bug!(expr.span, "no registered caps"); - } - }; - caps.iter().rev().fold(succ, |succ, cap| { - this.init_from_succ(cap.ln, succ); - let var = this.variable(cap.var_nid, expr.span); - this.acc(cap.ln, var, ACC_READ | ACC_USE); - cap.ln - }) + + let break_ln = succ; + let cont_ln = node; + self.break_ln.insert(blk_id.node_id, break_ln); + self.cont_ln.insert(blk_id.node_id, cont_ln); + + // the construction of a closure itself is not important, + // but we have to consider the closed over variables. + let caps = match self.ir.capture_info_map.get(&expr.id) { + Some(caps) => caps.clone(), + None => { + span_bug!(expr.span, "no registered caps"); + } + }; + caps.iter().rev().fold(succ, |succ, cap| { + self.init_from_succ(cap.ln, succ); + let var = self.variable(cap.var_nid, expr.span); + self.acc(cap.ln, var, ACC_READ | ACC_USE); + cap.ln }) } @@ -1003,28 +1011,33 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprBreak(label, ref opt_expr) => { // Find which label this break jumps to - let sc = match label.loop_id.into() { - Ok(loop_id) => loop_id, - Err(err) => span_bug!(expr.span, "loop scope error: {}", err), - }; + let target = match label.target_id { + hir::ScopeTarget::Block(node_id) => + self.breakable_block_ln.get(&node_id), + hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) => + self.break_ln.get(&node_id), + hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => + span_bug!(expr.span, "loop scope error: {}", err), + }.map(|x| *x); // Now that we know the label we're going to, // look it up in the break loop nodes table - match self.break_ln.get(&sc) { - Some(&b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b), + match target { + Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b), None => span_bug!(expr.span, "break to unknown label") } } hir::ExprAgain(label) => { // Find which label this expr continues to - let sc = match label.loop_id.into() { - Ok(loop_id) => loop_id, - Err(err) => span_bug!(expr.span, "loop scope error: {}", err), + let sc = match label.target_id { + hir::ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"), + hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) => node_id, + hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => + span_bug!(expr.span, "loop scope error: {}", err), }; - // Now that we know the label we're going to, // look it up in the continue loop nodes table @@ -1287,14 +1300,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!("propagate_through_loop: using id for loop body {} {}", expr.id, self.ir.tcx.hir.node_to_pretty_string(body.id)); - let (cond_ln, body_ln) = self.with_loop_nodes(expr.id, succ, ln, |this| { - let cond_ln = match kind { - LoopLoop => ln, - WhileLoop(ref cond) => this.propagate_through_expr(&cond, ln), - }; - let body_ln = this.propagate_through_block(body, cond_ln); - (cond_ln, body_ln) - }); + let break_ln = succ; + let cont_ln = ln; + self.break_ln.insert(expr.id, break_ln); + self.cont_ln.insert(expr.id, cont_ln); + + let cond_ln = match kind { + LoopLoop => ln, + WhileLoop(ref cond) => self.propagate_through_expr(&cond, ln), + }; + let body_ln = self.propagate_through_block(body, cond_ln); // repeat until fixed point is reached: while self.merge_from_succ(ln, body_ln, first_merge) { @@ -1307,29 +1322,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } }; assert!(cond_ln == new_cond_ln); - assert!(body_ln == self.with_loop_nodes(expr.id, succ, ln, - |this| this.propagate_through_block(body, cond_ln))); + assert!(body_ln == self.propagate_through_block(body, cond_ln)); } cond_ln } - - fn with_loop_nodes(&mut self, - loop_node_id: NodeId, - break_ln: LiveNode, - cont_ln: LiveNode, - f: F) - -> R where - F: FnOnce(&mut Liveness<'a, 'tcx>) -> R, - { - debug!("with_loop_nodes: {} {}", loop_node_id, break_ln.get()); - self.loop_scope.push(loop_node_id); - self.break_ln.insert(loop_node_id, break_ln); - self.cont_ln.insert(loop_node_id, cont_ln); - let r = f(self); - self.loop_scope.pop(); - r - } } // _______________________________________________________________________ diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index dab8510687329..e1b0c6a6f042e 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -40,7 +40,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, block, ast_block) + if let Some(_) = ast_block.break_to_expr_id { + // This is a `break`-able block (currently only `catch { ... }`) + let exit_block = this.cfg.start_new_block(); + let block_exit = this.in_breakable_scope(None, exit_block, + destination.clone(), |this| { + this.ast_block(destination, block, ast_block) + }); + this.cfg.terminate(unpack!(block_exit), source_info, + TerminatorKind::Goto { target: exit_block }); + exit_block.unit() + } else { + this.ast_block(destination, block, ast_block) + } } ExprKind::Match { discriminant, arms } => { this.match_expr(destination, expr_span, block, discriminant, arms) @@ -165,8 +177,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.terminate(block, source_info, TerminatorKind::Goto { target: loop_block }); - this.in_loop_scope( - loop_block, exit_block, destination.clone(), + this.in_breakable_scope( + Some(loop_block), exit_block, destination.clone(), move |this| { // conduct the test, if necessary let body_block; diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index be39dcbf6d08d..7336da654c184 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -9,7 +9,7 @@ // except according to those terms. use build::{BlockAnd, BlockAndExtension, Builder}; -use build::scope::LoopScope; +use build::scope::BreakableScope; use hair::*; use rustc::mir::*; @@ -77,19 +77,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.unit() } ExprKind::Continue { label } => { - let LoopScope { continue_block, extent, .. } = - *this.find_loop_scope(expr_span, label); + let BreakableScope { continue_block, extent, .. } = + *this.find_breakable_scope(expr_span, label); + let continue_block = continue_block.expect( + "Attempted to continue in non-continuable breakable block"); this.exit_scope(expr_span, extent, block, continue_block); this.cfg.start_new_block().unit() } ExprKind::Break { label, value } => { let (break_block, extent, destination) = { - let LoopScope { + let BreakableScope { break_block, extent, ref break_destination, .. - } = *this.find_loop_scope(expr_span, label); + } = *this.find_breakable_scope(expr_span, label); (break_block, extent, break_destination.clone()) }; if let Some(value) = value { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 41374a0012327..db03a1c68f715 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -36,9 +36,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// see the `scope` module for more details scopes: Vec>, - /// the current set of loops; see the `scope` module for more + /// the current set of breakables; see the `scope` module for more /// details - loop_scopes: Vec>, + breakable_scopes: Vec>, /// the vector of all scopes that we have created thus far; /// we track this for debuginfo later @@ -248,7 +248,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, - loop_scopes: vec![], + breakable_scopes: vec![], local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), var_indices: NodeMap(), unit_temp: None, diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 3dab1717f6b2e..1de5b9218564f 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -177,16 +177,16 @@ struct FreeData<'tcx> { } #[derive(Clone, Debug)] -pub struct LoopScope<'tcx> { +pub struct BreakableScope<'tcx> { /// Extent of the loop pub extent: CodeExtent, - /// Where the body of the loop begins - pub continue_block: BasicBlock, - /// Block to branch into when the loop terminates (either by being `break`-en out from, or by - /// having its condition to become false) + /// Where the body of the loop begins. `None` if block + pub continue_block: Option, + /// Block to branch into when the loop or block terminates (either by being `break`-en out + /// from, or by having its condition to become false) pub break_block: BasicBlock, - /// The destination of the loop expression itself (i.e. where to put the result of a `break` - /// expression) + /// The destination of the loop/block expression itself (i.e. where to put the result of a + /// `break` expression) pub break_destination: Lvalue<'tcx>, } @@ -242,28 +242,29 @@ impl<'tcx> Scope<'tcx> { impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Adding and removing scopes // ========================== - /// Start a loop scope, which tracks where `continue` and `break` + /// Start a breakable scope, which tracks where `continue` and `break` /// should branch to. See module comment for more details. /// - /// Returns the might_break attribute of the LoopScope used. - pub fn in_loop_scope(&mut self, - loop_block: BasicBlock, + /// Returns the might_break attribute of the BreakableScope used. + pub fn in_breakable_scope(&mut self, + loop_block: Option, break_block: BasicBlock, break_destination: Lvalue<'tcx>, - f: F) - where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) + f: F) -> R + where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> R { let extent = self.topmost_scope(); - let loop_scope = LoopScope { + let scope = BreakableScope { extent: extent, continue_block: loop_block, break_block: break_block, break_destination: break_destination, }; - self.loop_scopes.push(loop_scope); - f(self); - let loop_scope = self.loop_scopes.pop().unwrap(); - assert!(loop_scope.extent == extent); + self.breakable_scopes.push(scope); + let res = f(self); + let breakable_scope = self.breakable_scopes.pop().unwrap(); + assert!(breakable_scope.extent == extent); + res } /// Convenience wrapper that pushes a scope and then executes `f` @@ -381,18 +382,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Finding scopes // ============== - /// Finds the loop scope for a given label. This is used for + /// Finds the breakable scope for a given label. This is used for /// resolving `break` and `continue`. - pub fn find_loop_scope(&mut self, + pub fn find_breakable_scope(&mut self, span: Span, label: CodeExtent) - -> &mut LoopScope<'tcx> { + -> &mut BreakableScope<'tcx> { // find the loop-scope with the correct id - self.loop_scopes.iter_mut() + self.breakable_scopes.iter_mut() .rev() - .filter(|loop_scope| loop_scope.extent == label) + .filter(|breakable_scope| breakable_scope.extent == label) .next() - .unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?")) + .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) } /// Given a span and the current visibility scope, make a SourceInfo. diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index c67bb8ec6c585..da58a1ed1f49b 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -606,22 +606,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() }, - hir::ExprBreak(label, ref value) => { - match label.loop_id.into() { - Ok(loop_id) => ExprKind::Break { - label: cx.tcx.region_maps.node_extent(loop_id), + hir::ExprBreak(dest, ref value) => { + match dest.target_id { + hir::ScopeTarget::Block(target_id) | + hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break { + label: cx.tcx.region_maps.node_extent(target_id), value: value.to_ref(), }, - Err(err) => bug!("invalid loop id for break: {}", err) + hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => + bug!("invalid loop id for break: {}", err) } - } - hir::ExprAgain(label) => { - match label.loop_id.into() { - Ok(loop_id) => ExprKind::Continue { + hir::ExprAgain(dest) => { + match dest.target_id { + hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"), + hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue { label: cx.tcx.region_maps.node_extent(loop_id), }, - Err(err) => bug!("invalid loop id for continue: {}", err) + hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => + bug!("invalid loop id for continue: {}", err) } } hir::ExprMatch(ref discr, ref arms, _) => { diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index b2d51be5bf720..421181c68c4cd 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -87,14 +87,19 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Closure, |v| v.visit_nested_body(b)); } hir::ExprBreak(label, ref opt_expr) => { - let loop_id = match label.loop_id.into() { - Ok(loop_id) => loop_id, - Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID, - Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.emit_unlabled_cf_in_while_condition(e.span, "break"); - ast::DUMMY_NODE_ID - }, - Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID, + let loop_id = match label.target_id { + hir::ScopeTarget::Block(_) => return, + hir::ScopeTarget::Loop(loop_res) => { + match loop_res.into() { + Ok(loop_id) => loop_id, + Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID, + Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { + self.emit_unlabled_cf_in_while_condition(e.span, "break"); + ast::DUMMY_NODE_ID + }, + Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID, + } + } }; if opt_expr.is_some() { @@ -124,7 +129,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.require_loop("break", e.span); } hir::ExprAgain(label) => { - if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.loop_id.into() { + if let hir::ScopeTarget::Loop( + hir::LoopIdResult::Err( + hir::LoopIdError::UnlabeledCfInWhileCondition)) = label.target_id { self.emit_unlabled_cf_in_while_condition(e.span, "continue"); } self.require_loop("continue", e.span) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5a582a523ea1c..894c5f12297a0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -402,7 +402,7 @@ impl Diverges { } #[derive(Clone)] -pub struct LoopCtxt<'gcx, 'tcx> { +pub struct BreakableCtxt<'gcx, 'tcx> { unified: Ty<'tcx>, coerce_to: Ty<'tcx>, break_exprs: Vec<&'gcx hir::Expr>, @@ -410,15 +410,17 @@ pub struct LoopCtxt<'gcx, 'tcx> { } #[derive(Clone)] -pub struct EnclosingLoops<'gcx, 'tcx> { - stack: Vec>, +pub struct EnclosingBreakables<'gcx, 'tcx> { + stack: Vec>, by_id: NodeMap, } -impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> { - fn find_loop(&mut self, id: hir::LoopIdResult) -> Option<&mut LoopCtxt<'gcx, 'tcx>> { - let id_res: Result<_,_> = id.into(); - if let Some(ix) = id_res.ok().and_then(|id| self.by_id.get(&id).cloned()) { +impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { + fn find_breakable(&mut self, target: hir::ScopeTarget) + -> Option<&mut BreakableCtxt<'gcx, 'tcx>> + { + let opt_index = target.opt_id().and_then(|id| self.by_id.get(&id).cloned()); + if let Some(ix) = opt_index { Some(&mut self.stack[ix]) } else { None @@ -448,7 +450,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// Whether any child nodes have any type errors. has_errors: Cell, - enclosing_loops: RefCell>, + enclosing_breakables: RefCell>, inh: &'a Inherited<'a, 'gcx, 'tcx>, } @@ -1429,7 +1431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), has_errors: Cell::new(false), - enclosing_loops: RefCell::new(EnclosingLoops { + enclosing_breakables: RefCell::new(EnclosingBreakables { stack: Vec::new(), by_id: NodeMap(), }), @@ -3467,10 +3469,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } tcx.mk_nil() } - hir::ExprBreak(label, ref expr_opt) => { + hir::ExprBreak(destination, ref expr_opt) => { let coerce_to = { - let mut enclosing_loops = self.enclosing_loops.borrow_mut(); - enclosing_loops.find_loop(label.loop_id).map(|ctxt| ctxt.coerce_to) + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables + .find_breakable(destination.target_id).map(|ctxt| ctxt.coerce_to) }; if let Some(coerce_to) = coerce_to { let e_ty; @@ -3486,8 +3489,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause = self.misc(expr.span); } - let mut enclosing_loops = self.enclosing_loops.borrow_mut(); - let ctxt = enclosing_loops.find_loop(label.loop_id).unwrap(); + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(destination.target_id).unwrap(); let result = if let Some(ref e) = *expr_opt { // Special-case the first element, as it has no "previous expressions". @@ -3517,8 +3520,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ctxt.may_break = true; } - // Otherwise, we failed to find the enclosing loop; this can only happen if the - // `break` was not inside a loop at all, which is caught by the loop-checking pass. + // Otherwise, we failed to find the enclosing breakable; this can only happen if the + // `break` target was not found, which is caught in HIR lowering and reported by the + // loop-checking pass. tcx.types.never } hir::ExprAgain(_) => { tcx.types.never } @@ -3575,13 +3579,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprWhile(ref cond, ref body, _) => { let unified = self.tcx.mk_nil(); let coerce_to = unified; - let ctxt = LoopCtxt { + let ctxt = BreakableCtxt { unified: unified, coerce_to: coerce_to, break_exprs: vec![], may_break: true, }; - self.with_loop_ctxt(expr.id, ctxt, || { + self.with_breakable_ctxt(expr.id, ctxt, || { self.check_expr_has_type(&cond, tcx.types.bool); let cond_diverging = self.diverges.get(); self.check_block_no_value(&body); @@ -3599,14 +3603,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprLoop(ref body, _, _) => { let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(body.span)); let coerce_to = expected.only_has_type(self).unwrap_or(unified); - let ctxt = LoopCtxt { + let ctxt = BreakableCtxt { unified: unified, coerce_to: coerce_to, break_exprs: vec![], may_break: false, }; - let ctxt = self.with_loop_ctxt(expr.id, ctxt, || { + let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { self.check_block_no_value(&body); }); if ctxt.may_break { @@ -3625,8 +3629,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprClosure(capture, ref decl, body_id, _) => { self.check_expr_closure(expr, capture, &decl, body_id, expected) } - hir::ExprBlock(ref b) => { - self.check_block_with_expected(&b, expected) + hir::ExprBlock(ref body) => { + self.check_block_with_expected(&body, expected) } hir::ExprCall(ref callee, ref args) => { self.check_call(expr, &callee, args, expected) @@ -4018,65 +4022,85 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - for s in &blk.stmts { - self.check_stmt(s); - } + let mut ty = if let Some(break_to_expr_id) = blk.break_to_expr_id { + let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(blk.span)); + let coerce_to = expected.only_has_type(self).unwrap_or(unified); + let ctxt = BreakableCtxt { + unified: unified, + coerce_to: coerce_to, + break_exprs: vec![], + may_break: false, + }; - let mut ty = match blk.expr { - Some(ref e) => self.check_expr_with_expectation(e, expected), - None => self.tcx.mk_nil() - }; + let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(break_to_expr_id, ctxt, || { + for s in &blk.stmts { + self.check_stmt(s); + } + let coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable( + hir::ScopeTarget::Block(break_to_expr_id) + ).unwrap().coerce_to + }; + let e_ty; + let cause; + match blk.expr { + Some(ref e) => { + e_ty = self.check_expr_with_hint(e, coerce_to); + cause = self.misc(e.span); + }, + None => { + e_ty = self.tcx.mk_nil(); + cause = self.misc(blk.span); + } + }; + + (e_ty, cause) + }); - if self.diverges.get().always() { - ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); - } else if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { - // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); + let result = if !ctxt.may_break { + self.try_coerce(e, e_ty, ctxt.coerce_to) + } else { + self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(), + ctxt.unified, e, e_ty) + }; + match result { + Ok(ty) => ctxt.unified = ty, + Err(err) => + self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(), + } } else { - // We're not diverging and there's an expected type, which, - // in case it's not `()`, could result in an error higher-up. - // We have a chance to error here early and be more helpful. - let cause = self.misc(blk.span); - let trace = TypeTrace::types(&cause, false, ty, ety); - match self.sub_types(false, &cause, ty, ety) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }, - Err(err) => { - let mut err = self.report_and_explain_type_error(trace, &err); - - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let mut extra_semi = None; - if let Some(stmt) = blk.stmts.last() { - if let hir::StmtSemi(ref e, _) = stmt.node { - if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { - extra_semi = Some(stmt); - } - } - } - if let Some(last_stmt) = extra_semi { - let original_span = original_sp(self.tcx.sess.codemap(), - last_stmt.span, blk.span); - let span_semi = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - expn_id: original_span.expn_id - }; - err.span_help(span_semi, "consider removing this semicolon:"); - } + self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty); + }; - err.emit(); - } - } + ctxt.unified + } else { + for s in &blk.stmts { + self.check_stmt(s); } - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; - } + let mut ty = match blk.expr { + Some(ref e) => self.check_expr_with_expectation(e, expected), + None => self.tcx.mk_nil() + }; + + if self.diverges.get().always() { + ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); + } else if let ExpectHasType(ety) = expected { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); + } else { + self.check_block_no_expr(blk, ty, ety); + } + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } + ty + }; if self.has_errors.get() || ty.references_error() { ty = self.tcx.types.err @@ -4088,6 +4112,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } + pub fn check_block_no_expr(&self, blk: &'gcx hir::Block, ty: Ty<'tcx>, ety: Ty<'tcx>) { + // We're not diverging and there's an expected type, which, + // in case it's not `()`, could result in an error higher-up. + // We have a chance to error here early and be more helpful. + let cause = self.misc(blk.span); + let trace = TypeTrace::types(&cause, false, ty, ety); + match self.sub_types(false, &cause, ty, ety) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }, + Err(err) => { + let mut err = self.report_and_explain_type_error(trace, &err); + + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let mut extra_semi = None; + if let Some(stmt) = blk.stmts.last() { + if let hir::StmtSemi(ref e, _) = stmt.node { + if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { + extra_semi = Some(stmt); + } + } + } + if let Some(last_stmt) = extra_semi { + let original_span = original_sp(self.tcx.sess.codemap(), + last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + expn_id: original_span.expn_id + }; + err.span_help(span_semi, "consider removing this semicolon:"); + } + + err.emit(); + } + } + } + // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_value_path(&self, @@ -4485,22 +4549,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } - fn with_loop_ctxt(&self, id: ast::NodeId, ctxt: LoopCtxt<'gcx, 'tcx>, f: F) - -> LoopCtxt<'gcx, 'tcx> { + fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, + ctxt: BreakableCtxt<'gcx, 'tcx>, f: F) + -> (BreakableCtxt<'gcx, 'tcx>, R) { let index; { - let mut enclosing_loops = self.enclosing_loops.borrow_mut(); - index = enclosing_loops.stack.len(); - enclosing_loops.by_id.insert(id, index); - enclosing_loops.stack.push(ctxt); - } - f(); - { - let mut enclosing_loops = self.enclosing_loops.borrow_mut(); - debug_assert!(enclosing_loops.stack.len() == index + 1); - enclosing_loops.by_id.remove(&id).expect("missing loop context"); - (enclosing_loops.stack.pop().expect("missing loop context")) + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + index = enclosing_breakables.stack.len(); + enclosing_breakables.by_id.insert(id, index); + enclosing_breakables.stack.push(ctxt); } + let result = f(); + let ctxt = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + debug_assert!(enclosing_breakables.stack.len() == index + 1); + enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); + enclosing_breakables.stack.pop().expect("missing breakable context") + }; + (ctxt, result) } } diff --git a/src/test/compile-fail/catch-bad-lifetime.rs b/src/test/compile-fail/catch-bad-lifetime.rs new file mode 100644 index 0000000000000..d8de419df6d05 --- /dev/null +++ b/src/test/compile-fail/catch-bad-lifetime.rs @@ -0,0 +1,35 @@ +// Copyright 2017 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(catch_expr)] + +pub fn main() { + let _: Result<(), &str> = do catch { + let my_string = String::from(""); + let my_str: &str = &my_string; + Err(my_str)?; + Err("")?; + Ok(()) + }; //~ ERROR `my_string` does not live long enough + + let mut i = 5; + let k = &mut i; + let mut j: Result<(), &mut i32> = do catch { + Err(k)?; + i = 10; //~ ERROR cannot assign to `i` because it is borrowed + Ok(()) + }; + ::std::mem::drop(k); //~ ERROR use of moved value: `k` + i = 40; //~ ERROR cannot assign to `i` because it is borrowed + + let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic!("") }; + *i_ptr = 50; +} + diff --git a/src/test/compile-fail/catch-bad-type.rs b/src/test/compile-fail/catch-bad-type.rs new file mode 100644 index 0000000000000..cff9f508275b6 --- /dev/null +++ b/src/test/compile-fail/catch-bad-type.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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(catch_expr)] + +pub fn main() { + let res: Result = do catch { + Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied + Ok(5) + }; + let res: Result = do catch { + Ok("") //~ mismatched types + }; +} diff --git a/src/test/compile-fail/catch-opt-init.rs b/src/test/compile-fail/catch-opt-init.rs new file mode 100644 index 0000000000000..c5d116c82ddf8 --- /dev/null +++ b/src/test/compile-fail/catch-opt-init.rs @@ -0,0 +1,22 @@ +// Copyright 2017 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(catch_expr)] + +pub fn main() { + let cfg_res; + let _: Result<(), ()> = do catch { + Err(())?; + cfg_res = 5; + Ok(()) + }; + assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable +} + diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index a9b28a534a348..f2852bac27ae8 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -29,4 +29,38 @@ pub fn main() { match catch { _ => {} }; + + let catch_err = do catch { + Err(22)?; + Ok(1) + }; + assert_eq!(catch_err, Err(22)); + + let catch_okay: Result = do catch { + if false { Err(25)?; } + Ok::<(), i32>(())?; + Ok(28) + }; + assert_eq!(catch_okay, Ok(28)); + + let catch_from_loop: Result = do catch { + for i in 0..10 { + if i < 5 { Ok::(i)?; } else { Err(i)?; } + } + Ok(22) + }; + assert_eq!(catch_from_loop, Err(5)); + + let cfg_init; + let _res: Result<(), ()> = do catch { + cfg_init = 5; + Ok(()) + }; + assert_eq!(cfg_init, 5); + + let my_string = "test".to_string(); + let res: Result<&str, ()> = do catch { + Ok(&my_string) + }; + assert_eq!(res, Ok("test")); } From 1f43731772d7ec70cade48faf4af2b1a88375bfd Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 14 Mar 2017 16:48:01 -0700 Subject: [PATCH 123/662] Add more catch-related CFG and lifetime tests and fix CFG bug --- src/librustc/cfg/construct.rs | 2 +- src/test/compile-fail/catch-bad-lifetime.rs | 44 +++++++++------- .../compile-fail/catch-maybe-bad-lifetime.rs | 51 +++++++++++++++++++ src/test/compile-fail/catch-opt-init.rs | 4 ++ src/test/run-pass/catch-expr.rs | 8 +++ 5 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 src/test/compile-fail/catch-maybe-bad-lifetime.rs diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 777408457d1f6..189a7344c3130 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { stmts_exit = self.stmt(stmt, stmts_exit); } let blk_expr_exit = self.opt_expr(&blk.expr, stmts_exit); - self.add_contained_edge(blk_expr_exit, blk_expr_exit); + self.add_contained_edge(blk_expr_exit, expr_exit); self.breakable_block_scopes.pop(); diff --git a/src/test/compile-fail/catch-bad-lifetime.rs b/src/test/compile-fail/catch-bad-lifetime.rs index d8de419df6d05..57242dad6e31e 100644 --- a/src/test/compile-fail/catch-bad-lifetime.rs +++ b/src/test/compile-fail/catch-bad-lifetime.rs @@ -10,26 +10,34 @@ #![feature(catch_expr)] +// This test checks that borrows made and returned inside catch blocks are properly constrained pub fn main() { - let _: Result<(), &str> = do catch { - let my_string = String::from(""); - let my_str: &str = &my_string; - Err(my_str)?; - Err("")?; - Ok(()) - }; //~ ERROR `my_string` does not live long enough + { + // Test that borrows returned from a catch block must be valid for the lifetime of the + // result variable + let _result: Result<(), &str> = do catch { + let my_string = String::from(""); + let my_str: & str = & my_string; + Err(my_str) ?; + Err("") ?; + Ok(()) + }; //~ ERROR `my_string` does not live long enough + } - let mut i = 5; - let k = &mut i; - let mut j: Result<(), &mut i32> = do catch { - Err(k)?; - i = 10; //~ ERROR cannot assign to `i` because it is borrowed - Ok(()) - }; - ::std::mem::drop(k); //~ ERROR use of moved value: `k` - i = 40; //~ ERROR cannot assign to `i` because it is borrowed + { + // Test that borrows returned from catch blocks freeze their referent + let mut i = 5; + let k = &mut i; + let mut j: Result<(), &mut i32> = do catch { + Err(k) ?; + i = 10; //~ ERROR cannot assign to `i` because it is borrowed + Ok(()) + }; + ::std::mem::drop(k); //~ ERROR use of moved value: `k` + i = 40; //~ ERROR cannot assign to `i` because it is borrowed - let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic!("") }; - *i_ptr = 50; + let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") }; + *i_ptr = 50; + } } diff --git a/src/test/compile-fail/catch-maybe-bad-lifetime.rs b/src/test/compile-fail/catch-maybe-bad-lifetime.rs new file mode 100644 index 0000000000000..b783a3dd7860f --- /dev/null +++ b/src/test/compile-fail/catch-maybe-bad-lifetime.rs @@ -0,0 +1,51 @@ +// Copyright 2017 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(catch_expr)] + +// This test checks that borrows made and returned inside catch blocks are properly constrained +pub fn main() { + { + // Test that a borrow which *might* be returned still freezes its referent + let mut i = 222; + let x: Result<&i32, ()> = do catch { + Err(())?; + Ok(&i) + }; + x.ok().cloned(); + i = 0; //~ ERROR cannot assign to `i` because it is borrowed + let _ = i; + } + + { + let x = String::new(); + let _y: Result<(), ()> = do catch { + Err(())?; + ::std::mem::drop(x); + Ok(()) + }; + println!("{}", x); //~ ERROR use of moved value: `x` + } + + { + // Test that a borrow which *might* be assigned to an outer variable still freezes + // its referent + let mut i = 222; + let j; + let x: Result<(), ()> = do catch { + Err(())?; + j = &i; + Ok(()) + }; + i = 0; //~ ERROR cannot assign to `i` because it is borrowed + let _ = i; + } +} + diff --git a/src/test/compile-fail/catch-opt-init.rs b/src/test/compile-fail/catch-opt-init.rs index c5d116c82ddf8..48284b4cb90b2 100644 --- a/src/test/compile-fail/catch-opt-init.rs +++ b/src/test/compile-fail/catch-opt-init.rs @@ -10,11 +10,15 @@ #![feature(catch_expr)] +fn use_val(_x: T) {} + pub fn main() { let cfg_res; let _: Result<(), ()> = do catch { Err(())?; cfg_res = 5; + Ok::<(), ()>(())?; + use_val(cfg_res); Ok(()) }; assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index f2852bac27ae8..5a757161a78a4 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -58,6 +58,14 @@ pub fn main() { }; assert_eq!(cfg_init, 5); + let cfg_init_2; + let _res: Result<(), ()> = do catch { + cfg_init_2 = 6; + Err(())?; + Ok(()) + }; + assert_eq!(cfg_init_2, 6); + let my_string = "test".to_string(); let res: Result<&str, ()> = do catch { Ok(&my_string) From 8eaac0843eb206c37b52db9d96094503487cd076 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Fri, 17 Mar 2017 09:03:52 +0900 Subject: [PATCH 124/662] Parse 0e+10 as a valid floating-point literal Fixes issue #40408. --- src/libsyntax/parse/lexer/mod.rs | 2 +- src/test/run-pass/issue-40408.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-40408.rs diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index de8a87e3a2b32..d48cf6911ed37 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -725,7 +725,7 @@ impl<'a> StringReader<'a> { base = 16; num_digits = self.scan_digits(16, 16); } - '0'...'9' | '_' | '.' => { + '0'...'9' | '_' | '.' | 'e' | 'E' => { num_digits = self.scan_digits(10, 10) + 1; } _ => { diff --git a/src/test/run-pass/issue-40408.rs b/src/test/run-pass/issue-40408.rs new file mode 100644 index 0000000000000..a73dc1966b4be --- /dev/null +++ b/src/test/run-pass/issue-40408.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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() { + println!("{}", 0E+10); + println!("{}", 0e+10); + println!("{}", 00e+10); + println!("{}", 00E+10); +} From e16d286b8170e76f8a725b507c6c8fa91c3a28bf Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 18 Mar 2017 14:52:35 +0100 Subject: [PATCH 125/662] add inline attributes to stage 0 methods --- src/libcore/num/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index d12002fdfa7f2..0411fb7741f70 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -859,6 +859,7 @@ macro_rules! int_impl { /// Stage 0 #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline(always)] #[cfg(stage0)] pub fn wrapping_shl(self, rhs: u32) -> Self { self.overflowing_shl(rhs).0 @@ -894,6 +895,7 @@ macro_rules! int_impl { /// Stage 0 #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline(always)] #[cfg(stage0)] pub fn wrapping_shr(self, rhs: u32) -> Self { self.overflowing_shr(rhs).0 @@ -2025,6 +2027,7 @@ macro_rules! uint_impl { /// Stage 0 #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline(always)] #[cfg(stage0)] pub fn wrapping_shl(self, rhs: u32) -> Self { self.overflowing_shl(rhs).0 @@ -2060,6 +2063,7 @@ macro_rules! uint_impl { /// Stage 0 #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline(always)] #[cfg(stage0)] pub fn wrapping_shr(self, rhs: u32) -> Self { self.overflowing_shr(rhs).0 From b77d31ac61d1772ccfab6f37cb19559adc843466 Mon Sep 17 00:00:00 2001 From: Russell Mackenzie Date: Sun, 19 Mar 2017 01:39:11 +0000 Subject: [PATCH 126/662] Add mention of None as possible return. Closes #40435. --- src/libcollections/slice.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 11fc1d553f28e..8147b83cf0487 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -230,7 +230,7 @@ impl [T] { core_slice::SliceExt::first_mut(self) } - /// Returns the first and all the rest of the elements of a slice. + /// Returns the first and all the rest of the elements of a slice, or `None` if it is empty. /// /// # Examples /// @@ -248,7 +248,7 @@ impl [T] { core_slice::SliceExt::split_first(self) } - /// Returns the first and all the rest of the elements of a slice. + /// Returns the first and all the rest of the elements of a slice, or `None` if it is empty. /// /// # Examples /// @@ -268,7 +268,7 @@ impl [T] { core_slice::SliceExt::split_first_mut(self) } - /// Returns the last and all the rest of the elements of a slice. + /// Returns the last and all the rest of the elements of a slice, or `None` if it is empty. /// /// # Examples /// @@ -287,7 +287,7 @@ impl [T] { } - /// Returns the last and all the rest of the elements of a slice. + /// Returns the last and all the rest of the elements of a slice, or `None` if it is empty. /// /// # Examples /// From 088696b98fca3c38f109ef97e17bd5403212b10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Sat, 18 Mar 2017 21:03:51 -0700 Subject: [PATCH 127/662] Fix problems left in `concurrent_recursive_mkdir` Increase lifetime of `tmpdir`, and really change the length of test path. --- src/libstd/fs.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index cc9df743ef1da..ca26dc9527c04 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2283,9 +2283,10 @@ mod tests { #[test] fn concurrent_recursive_mkdir() { - for _ in 0..50 { - let mut dir = tmpdir().join("a"); - for _ in 0..100 { + for _ in 0..100 { + let dir = tmpdir(); + let mut dir = dir.join("a"); + for _ in 0..40 { dir = dir.join("a"); } let mut join = vec!(); From 7add53e47e6713a66400a5b27c98f4620ab39525 Mon Sep 17 00:00:00 2001 From: Petr Zemek Date: Sun, 19 Mar 2017 07:02:20 +0100 Subject: [PATCH 128/662] Fix a typo in path.rs docs The name of the variable used in the example is `path`, not `os_str`. --- src/libstd/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index a744407903b1e..db446d88900c1 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1501,7 +1501,7 @@ impl Path { /// assert_eq!(path.to_string_lossy(), "foo.txt"); /// ``` /// - /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might + /// Had `path` contained invalid unicode, the `to_string_lossy` call might /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow { From 5dc8548050514b0781af7b21a4706552da18dd50 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 19 Mar 2017 17:51:27 +0200 Subject: [PATCH 129/662] update LLVM pick up a fix to LLVM PR29151. --- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 859fb26936462..d5ef27a79661d 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 859fb269364623b17e092efaba3f94e70ce97c5e +Subproject commit d5ef27a79661d4f0d57d7b7d2cdbe9204f790a4a diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index aeabf4a1dd376..be6d535dc732b 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-03-04 +2017-03-19 From c50a6ec7389e24b00d46232a4a2b13ae0b4c1bc3 Mon Sep 17 00:00:00 2001 From: Luxko Date: Mon, 20 Mar 2017 17:17:10 +0800 Subject: [PATCH 130/662] Fix typo in `ptr` doc `sizeof` should be `size_of` --- src/libcore/ptr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 909e44df20abb..07a7d2f95b1f2 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -405,7 +405,7 @@ impl *const T { } /// Calculates the offset from a pointer. `count` is in units of T; e.g. a - /// `count` of 3 represents a pointer offset of `3 * sizeof::()` bytes. + /// `count` of 3 represents a pointer offset of `3 * size_of::()` bytes. /// /// # Safety /// @@ -435,7 +435,7 @@ impl *const T { /// Calculates the offset from a pointer using wrapping arithmetic. /// `count` is in units of T; e.g. a `count` of 3 represents a pointer - /// offset of `3 * sizeof::()` bytes. + /// offset of `3 * size_of::()` bytes. /// /// # Safety /// @@ -529,7 +529,7 @@ impl *mut T { } /// Calculates the offset from a pointer. `count` is in units of T; e.g. a - /// `count` of 3 represents a pointer offset of `3 * sizeof::()` bytes. + /// `count` of 3 represents a pointer offset of `3 * size_of::()` bytes. /// /// # Safety /// @@ -558,7 +558,7 @@ impl *mut T { /// Calculates the offset from a pointer using wrapping arithmetic. /// `count` is in units of T; e.g. a `count` of 3 represents a pointer - /// offset of `3 * sizeof::()` bytes. + /// offset of `3 * size_of::()` bytes. /// /// # Safety /// From 4cd28a73878a00bd1c8242919236f491a47cc1f0 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 20 Mar 2017 02:37:52 -0700 Subject: [PATCH 131/662] On-demandify associated item retrieval --- src/librustc/ty/mod.rs | 94 +++++++++++++++++------------------ src/librustc_driver/driver.rs | 1 + 2 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3c37c7353d683..610a6d6d8eeaf 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2049,55 +2049,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn associated_item(self, def_id: DefId) -> AssociatedItem { - if !def_id.is_local() { - return queries::associated_item::get(self, DUMMY_SP, def_id); - } - - self.maps.associated_item.memoize(def_id, || { - // When the user asks for a given associated item, we - // always go ahead and convert all the associated items in - // the container. Note that we are also careful only to - // ever register a read on the *container* of the assoc - // item, not the assoc item itself. This prevents changes - // in the details of an item (for example, the type to - // which an associated type is bound) from contaminating - // those tasks that just need to scan the names of items - // and so forth. - - let id = self.hir.as_local_node_id(def_id).unwrap(); - let parent_id = self.hir.get_parent(id); - let parent_def_id = self.hir.local_def_id(parent_id); - let parent_item = self.hir.expect_item(parent_id); - match parent_item.node { - hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { - for impl_item_ref in impl_item_refs { - let assoc_item = - self.associated_item_from_impl_item_ref(parent_def_id, - impl_trait_ref.is_some(), - impl_item_ref); - self.maps.associated_item.borrow_mut() - .insert(assoc_item.def_id, assoc_item); - } - } - - hir::ItemTrait(.., ref trait_item_refs) => { - for trait_item_ref in trait_item_refs { - let assoc_item = - self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref); - self.maps.associated_item.borrow_mut() - .insert(assoc_item.def_id, assoc_item); - } - } - - ref r => { - panic!("unexpected container of associated items: {:?}", r) - } - } - - // memoize wants us to return something, so return - // the one we generated for this def-id - *self.maps.associated_item.borrow().get(&def_id).unwrap() - }) + queries::associated_item::get(self, DUMMY_SP, def_id) } fn associated_item_from_trait_item_ref(self, @@ -2623,3 +2575,47 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } + +fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) + -> AssociatedItem +{ + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let parent_id = tcx.hir.get_parent(id); + let parent_def_id = tcx.hir.local_def_id(parent_id); + let parent_item = tcx.hir.expect_item(parent_id); + match parent_item.node { + hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { + for impl_item_ref in impl_item_refs { + let assoc_item = + tcx.associated_item_from_impl_item_ref(parent_def_id, + impl_trait_ref.is_some(), + impl_item_ref); + if assoc_item.def_id == def_id { + return assoc_item; + } + } + } + + hir::ItemTrait(.., ref trait_item_refs) => { + for trait_item_ref in trait_item_refs { + let assoc_item = + tcx.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref); + if assoc_item.def_id == def_id { + return assoc_item; + } + } + } + + ref r => { + panic!("unexpected container of associated items: {:?}", r) + } + } + panic!("associated item not found for def_id: {:?}", def_id); +} + +pub fn provide(providers: &mut ty::maps::Providers) { + *providers = ty::maps::Providers { + associated_item, + ..*providers + }; +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2126a5a7c71bd..10980670b3148 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -882,6 +882,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut local_providers = ty::maps::Providers::default(); mir::provide(&mut local_providers); typeck::provide(&mut local_providers); + ty::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); From 17a26ee2758ddd371556f9cae6ebd407eeb59b89 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Mar 2017 15:06:05 +0100 Subject: [PATCH 132/662] Add missing urls in Option enum --- src/libcore/option.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 9df8350d90ffd..d997f3592fd76 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -219,12 +219,14 @@ impl Option { /// /// # Examples /// - /// Convert an `Option` into an `Option`, preserving the original. + /// Convert an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. /// The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. /// /// [`map`]: enum.Option.html#method.map + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html /// /// ``` /// let num_as_str: Option = Some("10".to_string()); @@ -271,9 +273,11 @@ impl Option { /// /// # Panics /// - /// Panics if the value is a `None` with a custom panic message provided by + /// Panics if the value is a [`None`] with a custom panic message provided by /// `msg`. /// + /// [`None`]: #variant.None + /// /// # Examples /// /// ``` @@ -302,7 +306,9 @@ impl Option { /// /// # Panics /// - /// Panics if the self value equals `None`. + /// Panics if the self value equals [`None`]. + /// + /// [`None`]: #variant.None /// /// # Examples /// @@ -367,7 +373,10 @@ impl Option { /// /// # Examples /// - /// Convert an `Option` into an `Option`, consuming the original: + /// Convert an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original: + /// + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html /// /// ``` /// let maybe_some_string = Some(String::from("Hello, World!")); From e4628fb0dbfd771662cf2fcb61c838fc2738e083 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 14:42:33 -0500 Subject: [PATCH 133/662] Remove the existing book We'll bring this back in with the next commit, as a submodule. --- src/doc/book/src/README.md | 39 - src/doc/book/src/SUMMARY.md | 60 - src/doc/book/src/associated-types.md | 202 -- src/doc/book/src/attributes.md | 70 - src/doc/book/src/bibliography.md | 83 - src/doc/book/src/borrow-and-asref.md | 93 - src/doc/book/src/casting-between-types.md | 204 -- src/doc/book/src/chapter_1.md | 1 - src/doc/book/src/choosing-your-guarantees.md | 360 --- src/doc/book/src/closures.md | 552 ---- src/doc/book/src/comments.md | 59 - src/doc/book/src/compiler-plugins.md | 253 -- src/doc/book/src/concurrency.md | 465 ---- src/doc/book/src/conditional-compilation.md | 91 - src/doc/book/src/const-and-static.md | 83 - src/doc/book/src/crates-and-modules.md | 593 ----- src/doc/book/src/deref-coercions.md | 119 - src/doc/book/src/documentation.md | 655 ----- src/doc/book/src/drop.md | 67 - src/doc/book/src/effective-rust.md | 8 - src/doc/book/src/enums.md | 107 - src/doc/book/src/error-handling.md | 2213 ----------------- src/doc/book/src/ffi.md | 767 ------ src/doc/book/src/functions.md | 336 --- src/doc/book/src/generics.md | 190 -- src/doc/book/src/getting-started.md | 550 ---- src/doc/book/src/glossary.md | 85 - src/doc/book/src/guessing-game.md | 1010 -------- src/doc/book/src/if-let.md | 84 - src/doc/book/src/if.md | 73 - src/doc/book/src/iterators.md | 344 --- src/doc/book/src/lifetimes.md | 428 ---- src/doc/book/src/loops.md | 211 -- src/doc/book/src/macros.md | 763 ------ src/doc/book/src/match.md | 100 - src/doc/book/src/method-syntax.md | 259 -- src/doc/book/src/mutability.md | 181 -- src/doc/book/src/operators-and-overloading.md | 135 - src/doc/book/src/ownership.md | 295 --- src/doc/book/src/patterns.md | 411 --- src/doc/book/src/primitive-types.md | 305 --- src/doc/book/src/procedural-macros.md | 286 --- src/doc/book/src/raw-pointers.md | 121 - src/doc/book/src/references-and-borrowing.md | 411 --- src/doc/book/src/release-channels.md | 68 - src/doc/book/src/strings.md | 195 -- src/doc/book/src/structs.md | 279 --- src/doc/book/src/syntax-and-semantics.md | 10 - src/doc/book/src/syntax-index.md | 253 -- src/doc/book/src/testing.md | 633 ----- src/doc/book/src/the-stack-and-the-heap.md | 583 ----- src/doc/book/src/trait-objects.md | 335 --- src/doc/book/src/traits.md | 551 ---- src/doc/book/src/type-aliases.md | 78 - src/doc/book/src/ufcs.md | 136 - src/doc/book/src/unsafe.md | 142 -- src/doc/book/src/unsized-types.md | 61 - ...using-rust-without-the-standard-library.md | 42 - src/doc/book/src/variable-bindings.md | 256 -- src/doc/book/src/vectors.md | 156 -- 60 files changed, 17500 deletions(-) delete mode 100644 src/doc/book/src/README.md delete mode 100644 src/doc/book/src/SUMMARY.md delete mode 100644 src/doc/book/src/associated-types.md delete mode 100644 src/doc/book/src/attributes.md delete mode 100644 src/doc/book/src/bibliography.md delete mode 100644 src/doc/book/src/borrow-and-asref.md delete mode 100644 src/doc/book/src/casting-between-types.md delete mode 100644 src/doc/book/src/chapter_1.md delete mode 100644 src/doc/book/src/choosing-your-guarantees.md delete mode 100644 src/doc/book/src/closures.md delete mode 100644 src/doc/book/src/comments.md delete mode 100644 src/doc/book/src/compiler-plugins.md delete mode 100644 src/doc/book/src/concurrency.md delete mode 100644 src/doc/book/src/conditional-compilation.md delete mode 100644 src/doc/book/src/const-and-static.md delete mode 100644 src/doc/book/src/crates-and-modules.md delete mode 100644 src/doc/book/src/deref-coercions.md delete mode 100644 src/doc/book/src/documentation.md delete mode 100644 src/doc/book/src/drop.md delete mode 100644 src/doc/book/src/effective-rust.md delete mode 100644 src/doc/book/src/enums.md delete mode 100644 src/doc/book/src/error-handling.md delete mode 100644 src/doc/book/src/ffi.md delete mode 100644 src/doc/book/src/functions.md delete mode 100644 src/doc/book/src/generics.md delete mode 100644 src/doc/book/src/getting-started.md delete mode 100644 src/doc/book/src/glossary.md delete mode 100644 src/doc/book/src/guessing-game.md delete mode 100644 src/doc/book/src/if-let.md delete mode 100644 src/doc/book/src/if.md delete mode 100644 src/doc/book/src/iterators.md delete mode 100644 src/doc/book/src/lifetimes.md delete mode 100644 src/doc/book/src/loops.md delete mode 100644 src/doc/book/src/macros.md delete mode 100644 src/doc/book/src/match.md delete mode 100644 src/doc/book/src/method-syntax.md delete mode 100644 src/doc/book/src/mutability.md delete mode 100644 src/doc/book/src/operators-and-overloading.md delete mode 100644 src/doc/book/src/ownership.md delete mode 100644 src/doc/book/src/patterns.md delete mode 100644 src/doc/book/src/primitive-types.md delete mode 100644 src/doc/book/src/procedural-macros.md delete mode 100644 src/doc/book/src/raw-pointers.md delete mode 100644 src/doc/book/src/references-and-borrowing.md delete mode 100644 src/doc/book/src/release-channels.md delete mode 100644 src/doc/book/src/strings.md delete mode 100644 src/doc/book/src/structs.md delete mode 100644 src/doc/book/src/syntax-and-semantics.md delete mode 100644 src/doc/book/src/syntax-index.md delete mode 100644 src/doc/book/src/testing.md delete mode 100644 src/doc/book/src/the-stack-and-the-heap.md delete mode 100644 src/doc/book/src/trait-objects.md delete mode 100644 src/doc/book/src/traits.md delete mode 100644 src/doc/book/src/type-aliases.md delete mode 100644 src/doc/book/src/ufcs.md delete mode 100644 src/doc/book/src/unsafe.md delete mode 100644 src/doc/book/src/unsized-types.md delete mode 100644 src/doc/book/src/using-rust-without-the-standard-library.md delete mode 100644 src/doc/book/src/variable-bindings.md delete mode 100644 src/doc/book/src/vectors.md diff --git a/src/doc/book/src/README.md b/src/doc/book/src/README.md deleted file mode 100644 index ade4d52c1eb31..0000000000000 --- a/src/doc/book/src/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# The Rust Programming Language - -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 abstractions’ -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. - -[rust]: https://www.rust-lang.org - -“The Rust Programming Language” is split into chapters. This introduction -is the first. After this: - -* [Getting started][gs] - Set up your computer for Rust development. -* [Tutorial: Guessing Game][gg] - Learn some Rust with a small project. -* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks. -* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code. -* [Glossary][gl] - A reference of terms used in the book. -* [Bibliography][bi] - Background on Rust's influences, papers about Rust. - -[gs]: getting-started.html -[gg]: guessing-game.html -[er]: effective-rust.html -[ss]: syntax-and-semantics.html -[gl]: glossary.html -[bi]: bibliography.html - -### Contributing - -The source files from which this book is generated can be found on -[GitHub][book]. - -[book]: https://github.com/rust-lang/rust/tree/master/src/doc/book diff --git a/src/doc/book/src/SUMMARY.md b/src/doc/book/src/SUMMARY.md deleted file mode 100644 index c3763cdf9d6d7..0000000000000 --- a/src/doc/book/src/SUMMARY.md +++ /dev/null @@ -1,60 +0,0 @@ -# Summary - -[Introduction](README.md) - -* [Getting Started](getting-started.md) -* [Tutorial: Guessing Game](guessing-game.md) -* [Syntax and Semantics](syntax-and-semantics.md) - * [Variable Bindings](variable-bindings.md) - * [Functions](functions.md) - * [Primitive Types](primitive-types.md) - * [Comments](comments.md) - * [if](if.md) - * [Loops](loops.md) - * [Vectors](vectors.md) - * [Ownership](ownership.md) - * [References and Borrowing](references-and-borrowing.md) - * [Lifetimes](lifetimes.md) - * [Mutability](mutability.md) - * [Structs](structs.md) - * [Enums](enums.md) - * [Match](match.md) - * [Patterns](patterns.md) - * [Method Syntax](method-syntax.md) - * [Strings](strings.md) - * [Generics](generics.md) - * [Traits](traits.md) - * [Drop](drop.md) - * [if let](if-let.md) - * [Trait Objects](trait-objects.md) - * [Closures](closures.md) - * [Universal Function Call Syntax](ufcs.md) - * [Crates and Modules](crates-and-modules.md) - * [`const` and `static`](const-and-static.md) - * [Attributes](attributes.md) - * [`type` aliases](type-aliases.md) - * [Casting between types](casting-between-types.md) - * [Associated Types](associated-types.md) - * [Unsized Types](unsized-types.md) - * [Operators and Overloading](operators-and-overloading.md) - * [Deref coercions](deref-coercions.md) - * [Macros](macros.md) - * [Raw Pointers](raw-pointers.md) - * [`unsafe`](unsafe.md) -* [Effective Rust](effective-rust.md) - * [The Stack and the Heap](the-stack-and-the-heap.md) - * [Testing](testing.md) - * [Conditional Compilation](conditional-compilation.md) - * [Documentation](documentation.md) - * [Iterators](iterators.md) - * [Concurrency](concurrency.md) - * [Error Handling](error-handling.md) - * [Choosing your Guarantees](choosing-your-guarantees.md) - * [FFI](ffi.md) - * [Borrow and AsRef](borrow-and-asref.md) - * [Release Channels](release-channels.md) - * [Using Rust without the standard library](using-rust-without-the-standard-library.md) - * [Procedural Macros (and custom derive)](procedural-macros.md) -* [Glossary](glossary.md) -* [Syntax Index](syntax-index.md) -* [Bibliography](bibliography.md) diff --git a/src/doc/book/src/associated-types.md b/src/doc/book/src/associated-types.md deleted file mode 100644 index 4db2b9e5eec20..0000000000000 --- a/src/doc/book/src/associated-types.md +++ /dev/null @@ -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 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) -> u32 { ... } -``` - -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 work the same way as those for functions. 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 going to -use `struct`s for all three here. - -Next is the `impl` line, which is an implementation like 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 a trait with 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 provide this constraint, we -couldn’t be sure which `impl` to match this trait object to. diff --git a/src/doc/book/src/attributes.md b/src/doc/book/src/attributes.md deleted file mode 100644 index 103ec39aa38a5..0000000000000 --- a/src/doc/book/src/attributes.md +++ /dev/null @@ -1,70 +0,0 @@ -# Attributes - -Declarations can be annotated with ‘attributes’ in Rust. They look like this: - -```rust -#[test] -# fn foo() {} -``` - -or like this: - -```rust -# mod foo { -#![test] -# } -``` - -The difference between the two is the `!`, which changes what the attribute -applies to: - -```rust,ignore -#[foo] -struct Foo; - -mod bar { - #![bar] -} -``` - -The `#[foo]` attribute applies to the next item, which is the `struct` -declaration. The `#![bar]` attribute applies to the item enclosing it, which is -the `mod` declaration. Otherwise, they’re the same. Both change the meaning of -the item they’re attached to somehow. - -For example, consider a function like this: - -```rust -#[test] -fn check() { - assert_eq!(2, 1 + 1); -} -``` - -It is marked with `#[test]`. This means it’s special: when you run -[tests][tests], this function will execute. When you compile as usual, it won’t -even be included. This function is now a test function. - -[tests]: testing.html - -Attributes may also have additional data: - -```rust -#[inline(always)] -fn super_fast_fn() { -# } -``` - -Or even keys and values: - -```rust -#[cfg(target_os = "macos")] -mod macos_only { -# } -``` - -Rust attributes are used for a number of different things. There is a full list -of attributes [in the reference][reference]. Currently, you are not allowed to -create your own attributes, the Rust compiler defines them. - -[reference]: ../reference/attributes.html diff --git a/src/doc/book/src/bibliography.md b/src/doc/book/src/bibliography.md deleted file mode 100644 index 07b2aa94a7746..0000000000000 --- a/src/doc/book/src/bibliography.md +++ /dev/null @@ -1,83 +0,0 @@ -# Bibliography - -This is a reading list of material relevant to Rust. It includes prior -research that has - at one time or another - influenced the design of -Rust, as well as publications about Rust. - -### 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.cs.uu.nl/research/techreps/UU-CS-2002-048.html) -* [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.stanford.edu/~ouster/cgi-bin/papers/coscheduling.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 for shared-memory programming](http://dl.acm.org/citation.cfm?id=1953616&dl=ACM&coll=DL&CFID=524387192&CFTOKEN=44362705) -* [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) -* [Epoch-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.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: Implementing High Level Abstractions in a -Systems Level -Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work by Eric Holk. -* [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 -* [Patina: A Formalization of the Rust Programming - Language](ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf). Early - formalization of a subset of the type system, by Eric Reed. -* [Experience Report: Developing the Servo Web Browser Engine using - Rust](http://arxiv.org/abs/1505.07383). By Lars Bergstrom. -* [Implementing a Generic Radix Trie in - Rust](https://michaelsproul.github.io/rust_radix_paper/rust-radix-sproul.pdf). Undergrad - paper by Michael Sproul. -* [Reenix: Implementing a Unix-Like Operating System in - Rust](http://scialex.github.io/reenix.pdf). Undergrad paper by Alex - Light. -* [Evaluation of performance and productivity metrics of potential - programming languages in the HPC environment] - (http://octarineparrot.com/assets/mrfloya-thesis-ba.pdf). - Bachelor's thesis by Florian Wilkens. Compares C, Go and Rust. -* [Nom, a byte oriented, streaming, zero copy, parser combinators library - in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By - Geoffroy Couprie, research for VLC. -* [Graph-Based Higher-Order Intermediate - Representation](http://compilers.cs.uni-saarland.de/papers/lkh15_cgo.pdf). An - experimental IR implemented in Impala, a Rust-like language. -* [Code Refinement of Stencil - Codes](http://compilers.cs.uni-saarland.de/papers/ppl14_web.pdf). Another - paper using Impala. -* [Parallelization in Rust with fork-join and - friends](http://publications.lib.chalmers.se/records/fulltext/219016/219016.pdf). Linus - Farnstrand's master's thesis. -* [Session Types for - Rust](http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip - Munksgaard's master's thesis. Research for Servo. -* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf) -* [You can't spell trust without Rust](https://raw.githubusercontent.com/Gankro/thesis/master/thesis.pdf). Alexis Beingessner's master's thesis. diff --git a/src/doc/book/src/borrow-and-asref.md b/src/doc/book/src/borrow-and-asref.md deleted file mode 100644 index a6e396571c685..0000000000000 --- a/src/doc/book/src/borrow-and-asref.md +++ /dev/null @@ -1,93 +0,0 @@ -# Borrow and AsRef - -The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but -different. Here’s a quick refresher on what these two traits mean. - -[borrow]: ../std/borrow/trait.Borrow.html -[asref]: ../std/convert/trait.AsRef.html - -# Borrow - -The `Borrow` trait is used when you’re writing a data structure, and you want to -use either an owned or borrowed type as synonymous for some purpose. - -For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: - -```rust,ignore -fn get(&self, k: &Q) -> Option<&V> - where K: Borrow, - Q: Hash + Eq -``` - -[hashmap]: ../std/collections/struct.HashMap.html -[get]: ../std/collections/struct.HashMap.html#method.get - -This signature is pretty complicated. The `K` parameter is what we’re interested -in here. It refers to a parameter of the `HashMap` itself: - -```rust,ignore -struct HashMap { -``` - -The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at -the signature of `get()` again, we can use `get()` when the key implements -`Borrow`. That way, we can make a `HashMap` which uses `String` keys, -but use `&str`s when we’re searching: - -```rust -use std::collections::HashMap; - -let mut map = HashMap::new(); -map.insert("Foo".to_string(), 42); - -assert_eq!(map.get("Foo"), Some(&42)); -``` - -This is because the standard library has `impl Borrow for String`. - -For most types, when you want to take an owned or borrowed type, a `&T` is -enough. But one area where `Borrow` is effective is when there’s more than one -kind of borrowed value. This is especially true of references and slices: you -can have both an `&T` or a `&mut T`. If we wanted to accept both of these types, -`Borrow` is up for it: - -```rust -use std::borrow::Borrow; -use std::fmt::Display; - -fn foo + Display>(a: T) { - println!("a is borrowed: {}", a); -} - -let mut i = 5; - -foo(&i); -foo(&mut i); -``` - -This will print out `a is borrowed: 5` twice. - -# AsRef - -The `AsRef` trait is a conversion trait. It’s used for converting some value to -a reference in generic code. Like this: - -```rust -let s = "Hello".to_string(); - -fn foo>(s: T) { - let slice = s.as_ref(); -} -``` - -# Which should I use? - -We can see how they’re kind of the same: they both deal with owned and borrowed -versions of some type. However, they’re a bit different. - -Choose `Borrow` when you want to abstract over different kinds of borrowing, or -when you’re building a data structure that treats owned and borrowed values in -equivalent ways, such as hashing and comparison. - -Choose `AsRef` when you want to convert something to a reference directly, and -you’re writing generic code. diff --git a/src/doc/book/src/casting-between-types.md b/src/doc/book/src/casting-between-types.md deleted file mode 100644 index 26cd718475eab..0000000000000 --- a/src/doc/book/src/casting-between-types.md +++ /dev/null @@ -1,204 +0,0 @@ -# Casting Between Types - -Rust, with its focus on safety, provides two different ways of casting -different types between each other. The first, `as`, is for safe casts. -In contrast, `transmute` allows for arbitrary casting, and is one of the -most dangerous features of Rust! - -# Coercion - -Coercion between types is implicit and has no syntax of its own, but can -be spelled out with [`as`](#explicit-coercions). - -Coercion occurs in `let`, `const`, and `static` statements; in -function call arguments; in field values in struct initialization; and in a -function result. - -The most common case of coercion is removing mutability from a reference: - -* `&mut T` to `&T` - -An analogous conversion is to remove mutability from a -[raw pointer](raw-pointers.html): - -* `*mut T` to `*const T` - -References can also be coerced to raw pointers: - -* `&T` to `*const T` - -* `&mut T` to `*mut T` - -Custom coercions may be defined using [`Deref`](deref-coercions.html). - -Coercion is transitive. - -# `as` - -The `as` keyword does safe casting: - -```rust -let x: i32 = 5; - -let y = x as i64; -``` - -There are three major categories of safe cast: explicit coercions, casts -between numeric types, and pointer casts. - -Casting is not transitive: even if `e as U1 as U2` is a valid -expression, `e as U2` is not necessarily so (in fact it will only be valid if -`U1` coerces to `U2`). - - -## Explicit coercions - -A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`. - -## Numeric casts - -A cast `e as U` is also valid in any of the following cases: - -* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* -* `e` is a C-like enum (with no data attached to the variants), - and `U` is an integer type; *enum-cast* -* `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast* -* `e` has type `u8` and `U` is `char`; *u8-char-cast* - -For example - -```rust -let one = true as u8; -let at_sign = 64 as char; -let two_hundred = -56i8 as u8; -``` - -The semantics of numeric casts are: - -* Casting between two integers of the same size (e.g. i32 -> u32) is a no-op -* Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will - truncate -* Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will - * zero-extend if the source is unsigned - * sign-extend if the source is signed -* Casting from a float to an integer will round the float towards zero - * **[NOTE: currently this will cause Undefined Behavior if the rounded - value cannot be represented by the target integer type][float-int]**. - This includes Inf and NaN. This is a bug and will be fixed. -* Casting from an integer to float will produce the floating point - representation of the integer, rounded if necessary (rounding strategy - unspecified) -* Casting from an f32 to an f64 is perfect and lossless -* Casting from an f64 to an f32 will produce the closest possible value - (rounding strategy unspecified) - * **[NOTE: currently this will cause Undefined Behavior if the value - is finite but larger or smaller than the largest or smallest finite - value representable by f32][float-float]**. This is a bug and will - be fixed. - -[float-int]: https://github.com/rust-lang/rust/issues/10184 -[float-float]: https://github.com/rust-lang/rust/issues/15536 - -## Pointer casts - -Perhaps surprisingly, it is safe to cast [raw pointers](raw-pointers.html) to and -from integers, and to cast between pointers to different types subject to -some constraints. It is only unsafe to dereference the pointer: - -```rust -let a = 300 as *const char; // `a` is a pointer to location 300. -let b = a as u32; -``` - -`e as U` is a valid pointer cast in any of the following cases: - -* `e` has type `*T`, `U` has type `*U_0`, and either `U_0: Sized` or - `unsize_kind(T) == unsize_kind(U_0)`; a *ptr-ptr-cast* - -* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast* - -* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* - -* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* - -* `e` is a function pointer type and `U` has type `*T`, - while `T: Sized`; *fptr-ptr-cast* - -* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* - - -# `transmute` - -`as` only allows safe casting, and will for example reject an attempt to -cast four bytes into a `u32`: - -```rust,ignore -let a = [0u8, 0u8, 0u8, 0u8]; - -let b = a as u32; // Four u8s makes a u32. -``` - -This errors with: - -```text -error: non-scalar cast: `[u8; 4]` as `u32` -let b = a as u32; // Four u8s makes a u32. - ^~~~~~~~ -``` - -This is a ‘non-scalar cast’ because we have multiple values here: the four -elements of the array. These kinds of casts are very dangerous, because they -make assumptions about the way that multiple underlying structures are -implemented. For this, we need something more dangerous. - -The `transmute` function is very simple, but very scary. It tells Rust to treat -a value of one type as though it were another type. It does this regardless of -the typechecking system, and completely trusts you. - -In our previous example, we know that an array of four `u8`s represents a `u32` -properly, and so we want to do the cast. Using `transmute` instead of `as`, -Rust lets us: - -```rust -use std::mem; - -fn main() { - unsafe { - let a = [0u8, 1u8, 0u8, 0u8]; - let b = mem::transmute::<[u8; 4], u32>(a); - println!("{}", b); // 256 - // Or, more concisely: - let c: u32 = mem::transmute(a); - println!("{}", c); // 256 - } -} -``` - -We have to wrap the operation in an `unsafe` block for this to compile -successfully. Technically, only the `mem::transmute` call itself needs to be in -the block, but it's nice in this case to enclose everything related, so you -know where to look. In this case, the details about `a` are also important, and -so they're in the block. You'll see code in either style, sometimes the context -is too far away, and wrapping all of the code in `unsafe` isn't a great idea. - -While `transmute` does very little checking, it will at least make sure that -the types are the same size. This errors: - -```rust,ignore -use std::mem; - -unsafe { - let a = [0u8, 0u8, 0u8, 0u8]; - - let b = mem::transmute::<[u8; 4], u64>(a); -} -``` - -with: - -```text -error: transmute called with differently sized types: [u8; 4] (32 bits) to u64 -(64 bits) -``` - -Other than that, you're on your own! diff --git a/src/doc/book/src/chapter_1.md b/src/doc/book/src/chapter_1.md deleted file mode 100644 index b743fda354692..0000000000000 --- a/src/doc/book/src/chapter_1.md +++ /dev/null @@ -1 +0,0 @@ -# Chapter 1 diff --git a/src/doc/book/src/choosing-your-guarantees.md b/src/doc/book/src/choosing-your-guarantees.md deleted file mode 100644 index 89dd09e670481..0000000000000 --- a/src/doc/book/src/choosing-your-guarantees.md +++ /dev/null @@ -1,360 +0,0 @@ -# Choosing your Guarantees - -One important feature of Rust is that it lets us control the costs and guarantees -of a program. - -There are various “wrapper type” abstractions in the Rust standard library which embody -a multitude of tradeoffs between cost, ergonomics, and guarantees. Many let one choose between -run time and compile time enforcement. This section will explain a few selected abstractions in -detail. - -Before proceeding, it is highly recommended that one reads about [ownership][ownership] and -[borrowing][borrowing] in Rust. - -[ownership]: ownership.html -[borrowing]: references-and-borrowing.html - -# Basic pointer types - -## `Box` - -[`Box`][box] is an “owned” pointer, or a “box”. While it can hand -out references to the contained data, it is the only owner of the data. In particular, consider -the following: - -```rust -let x = Box::new(1); -let y = x; -// `x` is no longer accessible here. -``` - -Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the -programmer to use `x` after this. A box can similarly be moved _out_ of a function by returning it. - -When a box (that hasn't been moved) goes out of scope, destructors are run. These destructors take -care of deallocating the inner data. - -This is a zero-cost abstraction for dynamic allocation. If you want to allocate some memory on the -heap and safely pass around a pointer to that memory, this is ideal. Note that you will only be -allowed to share references to this by the regular borrowing rules, checked at compile time. - -[box]: ../std/boxed/struct.Box.html - -## `&T` and `&mut T` - -These are immutable and mutable references respectively. They follow the “read-write lock” -pattern, such that one may either have only one mutable reference to some data, or any number of -immutable ones, but not both. This guarantee is enforced at compile time, and has no visible cost at -runtime. In most cases these two pointer types suffice for sharing cheap references between sections -of code. - -These pointers cannot be copied in such a way that they outlive the lifetime associated with them. - -## `*const T` and `*mut T` - -These are C-like raw pointers with no lifetime or ownership attached to them. They point to -some location in memory with no other restrictions. The only guarantee that these provide is that -they cannot be dereferenced except in code marked `unsafe`. - -These are useful when building safe, low cost abstractions like `Vec`, but should be avoided in -safe code. - -## `Rc` - -This is the first wrapper we will cover that has a runtime cost. - -[`Rc`][rc] is a reference counted pointer. In other words, this lets us have multiple "owning" -pointers to the same data, and the data will be dropped (destructors will be run) when all pointers -are out of scope. - -Internally, it contains a shared “reference count” (also called “refcount”), -which is incremented each time the `Rc` is cloned, and decremented each time one of the `Rc`s goes -out of scope. The main responsibility of `Rc` is to ensure that destructors are called for shared -data. - -The internal data here is immutable, and if a cycle of references is created, the data will be -leaked. If we want data that doesn't leak when there are cycles, we need a garbage collector. - -#### Guarantees - -The main guarantee provided here is that the data will not be destroyed until all references to it -are out of scope. - -This should be used when we wish to dynamically allocate and share some data (read-only) between -various portions of your program, where it is not certain which portion will finish using the pointer -last. It's a viable alternative to `&T` when `&T` is either impossible to statically check for -correctness, or creates extremely unergonomic code where the programmer does not wish to spend the -development cost of working with. - -This pointer is _not_ thread safe, and Rust will not let it be sent or shared with other threads. -This lets one avoid the cost of atomics in situations where they are unnecessary. - -There is a sister smart pointer to this one, `Weak`. This is a non-owning, but also non-borrowed, -smart pointer. It is also similar to `&T`, but it is not restricted in lifetime—a `Weak` -can be held on to forever. However, it is possible that an attempt to access the inner data may fail -and return `None`, since this can outlive the owned `Rc`s. This is useful for cyclic -data structures and other things. - -#### Cost - -As far as memory goes, `Rc` is a single allocation, though it will allocate two extra words (i.e. -two `usize` values) as compared to a regular `Box` (for "strong" and "weak" refcounts). - -`Rc` has the computational cost of incrementing/decrementing the refcount whenever it is cloned -or goes out of scope respectively. Note that a clone will not do a deep copy, rather it will simply -increment the inner reference count and return a copy of the `Rc`. - -[rc]: ../std/rc/struct.Rc.html - -# Cell types - -`Cell`s provide interior mutability. In other words, they contain data which can be manipulated even -if the type cannot be obtained in a mutable form (for example, when it is behind an `&`-ptr or -`Rc`). - -[The documentation for the `cell` module has a pretty good explanation for these][cell-mod]. - -These types are _generally_ found in struct fields, but they may be found elsewhere too. - -## `Cell` - -[`Cell`][cell] is a type that provides zero-cost interior mutability by moving data in and -out of the cell. -Since the compiler knows that all the data owned by the contained value is on the stack, there's -no worry of leaking any data behind references (or worse!) by simply replacing the data. - -It is still possible to violate your own invariants using this wrapper, so be careful when using it. -If a field is wrapped in `Cell`, it's a nice indicator that the chunk of data is mutable and may not -stay the same between the time you first read it and when you intend to use it. - -```rust -use std::cell::Cell; - -let x = Cell::new(1); -let y = &x; -let z = &x; -x.set(2); -y.set(3); -z.set(4); -println!("{}", x.get()); -``` - -Note that here we were able to mutate the same value from various immutable references. - -This has the same runtime cost as the following: - -```rust,ignore -let mut x = 1; -let y = &mut x; -let z = &mut x; -x = 2; -*y = 3; -*z = 4; -println!("{}", x); -``` - -but it has the added benefit of actually compiling successfully. - -#### Guarantees - -This relaxes the “no aliasing with mutability” restriction in places where it's -unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your -invariants depend on data stored within `Cell`, you should be careful. - -This is useful for mutating primitives and other types when there is no easy way of -doing it in line with the static rules of `&` and `&mut`. - -`Cell` does not let you obtain interior references to the data, which makes it safe to freely -mutate. - -#### Cost - -There is no runtime cost to using `Cell`, however if you are using it to wrap larger -structs, it might be worthwhile to instead wrap individual fields in `Cell` since each write is -otherwise a full copy of the struct. - - -## `RefCell` - -[`RefCell`][refcell] also provides interior mutability, but doesn't move data in and out of the -cell. - -However, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's -like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the -`borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart -pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when -the smart pointers go out of scope. With this system, we can dynamically ensure that there are never -any other borrows active when a mutable borrow is active. If the programmer attempts to make such a -borrow, the thread will panic. - -```rust -use std::cell::RefCell; - -let x = RefCell::new(vec![1,2,3,4]); -{ - println!("{:?}", *x.borrow()) -} - -{ - let mut my_ref = x.borrow_mut(); - my_ref.push(1); -} -``` - -Similar to `Cell`, this is mainly useful for situations where it's hard or impossible to satisfy the -borrow checker. Generally we know that such mutations won't happen in a nested form, but it's good -to check. - -For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things -simpler. For example, a lot of the maps in the `ctxt` struct in the Rust compiler internals -are inside this wrapper. These are only modified once (during creation, which is not right after -initialization) or a couple of times in well-separated places. However, since this struct is -pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps -impossible) and probably form a soup of `&`-ptrs which would be hard to extend. On the other hand, -the `RefCell` provides a cheap (not zero-cost) way of safely accessing these. In the future, if -someone adds some code that attempts to modify the cell when it's already borrowed, it will cause a -(usually deterministic) panic which can be traced back to the offending borrow. - -Similarly, in Servo's DOM there is a lot of mutation, most of which is local to a DOM type, but some -of which crisscrosses the DOM and modifies various things. Using `RefCell` and `Cell` to guard all -mutation lets us avoid worrying about mutability everywhere, and it simultaneously highlights the -places where mutation is _actually_ happening. - -Note that `RefCell` should be avoided if a mostly simple solution is possible with `&` pointers. - -#### Guarantees - -`RefCell` relaxes the _static_ restrictions preventing aliased mutation, and replaces them with -_dynamic_ ones. As such the guarantees have not changed. - -#### Cost - -`RefCell` does not allocate, but it contains an additional "borrow state" -indicator (one word in size) along with the data. - -At runtime each borrow causes a modification/check of the refcount. - -[cell-mod]: ../std/cell/index.html -[cell]: ../std/cell/struct.Cell.html -[refcell]: ../std/cell/struct.RefCell.html - -# Synchronous types - -Many of the types above cannot be used in a threadsafe manner. Particularly, `Rc` and -`RefCell`, which both use non-atomic reference counts (_atomic_ reference counts are those which -can be incremented from multiple threads without causing a data race), cannot be used this way. This -makes them cheaper to use, but we need thread safe versions of these too. They exist, in the form of -`Arc` and `Mutex`/`RwLock` - -Note that the non-threadsafe types _cannot_ be sent between threads, and this is checked at compile -time. - -There are many useful wrappers for concurrent programming in the [sync][sync] module, but only the -major ones will be covered below. - -[sync]: ../std/sync/index.html - -## `Arc` - -[`Arc`][arc] is a version of `Rc` that uses an atomic reference count (hence, "Arc"). -This can be sent freely between threads. - -C++'s `shared_ptr` is similar to `Arc`, however in the case of C++ the inner data is always mutable. -For semantics similar to that from C++, we should use `Arc>`, `Arc>`, or -`Arc>`[^4] (`UnsafeCell` is a cell type that can be used to hold any data and has -no runtime cost, but accessing it requires `unsafe` blocks). The last one should only be used if we -are certain that the usage won't cause any memory unsafety. Remember that writing to a struct is not -an atomic operation, and many functions like `vec.push()` can reallocate internally and cause unsafe -behavior, so even monotonicity may not be enough to justify `UnsafeCell`. - -[^4]: `Arc>` actually won't compile since `UnsafeCell` isn't `Send` or `Sync`, but we can wrap it in a type and implement `Send`/`Sync` for it manually to get `Arc>` where `Wrapper` is `struct Wrapper(UnsafeCell)`. - -#### Guarantees - -Like `Rc`, this provides the (thread safe) guarantee that the destructor for the internal data will -be run when the last `Arc` goes out of scope (barring any cycles). - -#### Cost - -This has the added cost of using atomics for changing the refcount (which will happen whenever it is -cloned or goes out of scope). When sharing data from an `Arc` in a single thread, it is preferable -to share `&` pointers whenever possible. - -[arc]: ../std/sync/struct.Arc.html - -## `Mutex` and `RwLock` - -[`Mutex`][mutex] and [`RwLock`][rwlock] provide mutual-exclusion via RAII guards (guards are -objects which maintain some state, like a lock, until their destructor is called). For both of -these, the mutex is opaque until we call `lock()` on it, at which point the thread will block -until a lock can be acquired, and then a guard will be returned. This guard can be used to access -the inner data (mutably), and the lock will be released when the guard goes out of scope. - -```rust,ignore -{ - let guard = mutex.lock(); - // `guard` dereferences mutably to the inner type. - *guard += 1; -} // Lock is released when destructor runs. -``` - - -`RwLock` has the added benefit of being efficient for multiple reads. It is always safe to have -multiple readers to shared data as long as there are no writers; and `RwLock` lets readers acquire a -"read lock". Such locks can be acquired concurrently and are kept track of via a reference count. -Writers must obtain a "write lock" which can only be obtained when all readers have gone out of -scope. - -#### Guarantees - -Both of these provide safe shared mutability across threads, however they are prone to deadlocks. -Some level of additional protocol safety can be obtained via the type system. - -#### Costs - -These use internal atomic-like types to maintain the locks, which are pretty costly (they can block -all memory reads across processors till they're done). Waiting on these locks can also be slow when -there's a lot of concurrent access happening. - -[rwlock]: ../std/sync/struct.RwLock.html -[mutex]: ../std/sync/struct.Mutex.html -[sessions]: https://github.com/Munksgaard/rust-sessions - -# Composition - -A common gripe when reading Rust code is with types like `Rc>>` (or even more -complicated compositions of such types). It's not always clear what the composition does, or why the -author chose one like this (and when one should be using such a composition in one's own code) - -Usually, it's a case of composing together the guarantees that you need, without paying for stuff -that is unnecessary. - -For example, `Rc>` is one such composition. `Rc` itself can't be dereferenced mutably; -because `Rc` provides sharing and shared mutability can lead to unsafe behavior, so we put -`RefCell` inside to get dynamically verified shared mutability. Now we have shared mutable data, -but it's shared in a way that there can only be one mutator (and no readers) or multiple readers. - -Now, we can take this a step further, and have `Rc>>` or `Rc>>`. These -are both shareable, mutable vectors, but they're not the same. - -With the former, the `RefCell` is wrapping the `Vec`, so the `Vec` in its entirety is -mutable. At the same time, there can only be one mutable borrow of the whole `Vec` at a given time. -This means that your code cannot simultaneously work on different elements of the vector from -different `Rc` handles. However, we are able to push and pop from the `Vec` at will. This is -similar to a `&mut Vec` with the borrow checking done at runtime. - -With the latter, the borrowing is of individual elements, but the overall vector is immutable. Thus, -we can independently borrow separate elements, but we cannot push or pop from the vector. This is -similar to a `&mut [T]`[^3], but, again, the borrow checking is at runtime. - -In concurrent programs, we have a similar situation with `Arc>`, which provides shared -mutability and ownership. - -When reading code that uses these, go in step by step and look at the guarantees/costs provided. - -When choosing a composed type, we must do the reverse; figure out which guarantees we want, and at -which point of the composition we need them. For example, if there is a choice between -`Vec>` and `RefCell>`, we should figure out the tradeoffs as done above and pick -one. - -[^3]: `&[T]` and `&mut [T]` are _slices_; they consist of a pointer and a length and can refer to a portion of a vector or array. `&mut [T]` can have its elements mutated, however its length cannot be touched. diff --git a/src/doc/book/src/closures.md b/src/doc/book/src/closures.md deleted file mode 100644 index 5426ed0ff4c9c..0000000000000 --- a/src/doc/book/src/closures.md +++ /dev/null @@ -1,552 +0,0 @@ -# Closures - -Sometimes it is useful to wrap up a function and _free variables_ for better -clarity and reuse. The free variables that can be used come from the -enclosing scope and are ‘closed over’ when used in the function. From this, we -get the name ‘closures’ and Rust provides 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 from regular -named functions defined with `fn`. The first 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 full type signatures of -closures are rarely documented since they’re anonymous, and they don’t cause -the kinds of error-at-a-distance problems that inferring named function types -can. - -The second is that the syntax is similar, but a bit different. I’ve added -spaces here for easier comparison: - -```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. - -# Closures and their environment - -The environment for a closure can include bindings from its enclosing scope in -addition to parameters and local bindings. 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. This doesn’t work: - -```rust,ignore -let nums = vec![1, 2, 3]; - -let takes_nums = || nums; - -println!("{:?}", nums); -``` - -We get this error: - -```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][traits] section before this one, as well as the section on [trait -objects][trait-objects]. - -[traits]: traits.html -[trait-objects]: trait-objects.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 -# #![feature(unboxed_closures)] -# 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: the same as 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 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 an `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 use it as a bound for our generic type. In -this case, our closure takes an `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 languages, 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 `&||`. - -A quick note about closures that use explicit lifetimes. Sometimes you might have a closure -that takes a reference like so: - -```rust -fn call_with_ref(some_closure:F) -> i32 - where F: Fn(&i32) -> i32 { - - let value = 0; - some_closure(&value) -} -``` - -Normally you can specify the lifetime of the parameter to our closure. We -could annotate it on the function declaration: - -```rust,ignore -fn call_with_ref<'a, F>(some_closure:F) -> i32 - where F: Fn(&'a i32) -> i32 { -``` - -However, this presents a problem in our case. When a function has an explicit -lifetime parameter, that lifetime must be at least as long as the *entire* -call to that function. The borrow checker will complain that `value` doesn't -live long enough, because it is only in scope after its declaration inside the -function body. - -What we need is a closure that can borrow its argument only for its own -invocation scope, not for the outer function's scope. In order to say that, -we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: - -```ignore -fn call_with_ref(some_closure:F) -> i32 - where F: for<'a> Fn(&'a i32) -> i32 { -``` - -This lets the Rust compiler find the minimum lifetime to invoke our closure and -satisfy the borrow checker's rules. Our function then compiles and executes as we -expect. - -```rust -fn call_with_ref(some_closure:F) -> i32 - where F: for<'a> Fn(&'a i32) -> i32 { - - let value = 0; - some_closure(&value) -} -``` - -# Function pointers and closures - -A function pointer is kind of like a closure that has no environment. As such, -you can pass a function pointer to any function expecting a closure argument, -and it will work: - -```rust -fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 { - some_closure(1) -} - -fn add_one(i: i32) -> i32 { - i + 1 -} - -let f = add_one; - -let answer = call_with_one(&f); - -assert_eq!(2, answer); -``` - -In this example, we don’t strictly need the intermediate variable `f`, -the name of the function works just fine too: - -```rust,ignore -let answer = call_with_one(&add_one); -``` - -# 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) -> i32) { - let num = 5; - - |x| x + num -} - -let f = factory(); - -let answer = f(1); -assert_eq!(6, answer); -``` - -This gives us these long, related errors: - -```text -error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277] -fn factory() -> (Fn(i32) -> i32) { - ^~~~~~~~~~~~~~~~ -note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time -fn factory() -> (Fn(i32) -> i32) { - ^~~~~~~~~~~~~~~~ -error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277] -let f = factory(); - ^ -note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time -let f = factory(); - ^ -``` - -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) -> 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: 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](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what -choices do we have? Try `'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 solely for -this closure. So Rust shows them as `closure@`, rather than some -autogenerated name. - -The error also points out that the return type is expected to be a reference, -but what we are trying to return is not. Further, we cannot directly assign a -`'static` lifetime to an object. So we'll take a different approach and return -a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works: - -```rust,ignore -fn factory() -> Box i32> { - let num = 5; - - Box::new(|x| x + num) -} - -let f = factory(); - -let answer = f(1); -assert_eq!(6, answer); -``` - -There’s just one last problem: - -```text -error: closure may outlive the current function, but it borrows `num`, -which is owned by the current function [E0373] -Box::new(|x| x + num) - ^~~~~~~~~~~ -``` - -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! With one last -fix, we can make this work: - -```rust -fn factory() -> Box i32> { - let num = 5; - - Box::new(move |x| x + num) -} - -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, allowing it to -escape our stack frame. diff --git a/src/doc/book/src/comments.md b/src/doc/book/src/comments.md deleted file mode 100644 index 0e68ab218e843..0000000000000 --- a/src/doc/book/src/comments.md +++ /dev/null @@ -1,59 +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 -/// Adds one to the number given. -/// -/// # Examples -/// -/// ``` -/// let five = 5; -/// -/// assert_eq!(6, add_one(5)); -/// # fn add_one(x: i32) -> i32 { -/// # x + 1 -/// # } -/// ``` -fn add_one(x: i32) -> i32 { - x + 1 -} -``` - -There is another style of doc comment, `//!`, to comment containing items (e.g. -crates, modules or functions), instead of the items following it. Commonly used -inside crates root (lib.rs) or modules root (mod.rs): - -``` -//! # The Rust Standard Library -//! -//! The Rust Standard Library provides the essential runtime -//! functionality for building portable Rust software. -``` - -When writing doc comments, providing some examples of usage is very, very -helpful. You’ll notice we’ve used a new macro here: `assert_eq!`. This compares -two values, and `panic!`s if they’re not equal to each other. It’s very helpful -in documentation. There’s another macro, `assert!`, which `panic!`s if the -value passed to it is `false`. - -You can use the [`rustdoc`](documentation.html) tool to generate HTML documentation -from these doc comments, and also to run the code examples as tests! diff --git a/src/doc/book/src/compiler-plugins.md b/src/doc/book/src/compiler-plugins.md deleted file mode 100644 index c05d808a94740..0000000000000 --- a/src/doc/book/src/compiler-plugins.md +++ /dev/null @@ -1,253 +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` 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. - -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 at -compile time. - -Let's write a plugin -[`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs) -that implements Roman numeral integer literals. - -```rust,ignore -#![crate_type="dylib"] -#![feature(plugin_registrar, rustc_private)] - -extern crate syntax; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::parse::token; -use syntax::tokenstream::TokenTree; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; -use syntax::ext::build::AstBuilder; // A trait for expr_usize. -use syntax::ext::quote::rt::Span; -use rustc_plugin::Registry; - -fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) - -> Box { - - static NUMERALS: &'static [(&'static str, usize)] = &[ - ("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)]; - - if args.len() != 1 { - cx.span_err( - sp, - &format!("argument should be a single identifier, but got {} arguments", args.len())); - return DummyResult::any(sp); - } - - let text = match args[0] { - TokenTree::Token(_, token::Ident(s)) => 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_usize(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: - -```rust,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/attributes.html#derive)-like attributes and other kinds of -extensions. See `Registry::register_syntax_extension` and the `SyntaxExtension` -enum. 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` to turn token trees into -higher-level syntax elements like expressions: - -```rust,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 of everything you parse, for better error reporting. You can -wrap `Spanned` around your custom data structures. - -Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to -instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler -can continue and find further errors. - -To print syntax fragments for debugging, you can use `span_note` together with -`syntax::print::pprust::*_to_string`. - -The example above produced an integer literal using `AstBuilder::expr_usize`. -As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of -quasiquote macros. 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/attributes.html#lint-check-attributes) with -additional checks for code style, safety, etc. Now let's write a plugin -[`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs) -that warns about any item named `lintme`. - -```rust,ignore -#![feature(plugin_registrar)] -#![feature(box_syntax, rustc_private)] - -extern crate syntax; - -// Load rustc as a plugin to get macros -#[macro_use] -extern crate rustc; -extern crate rustc_plugin; - -use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, - EarlyLintPassObject, LintArray}; -use rustc_plugin::Registry; -use syntax::ast; - -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) - } -} - -impl EarlyLintPass for Pass { - fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { - cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_early_lint_pass(box Pass as EarlyLintPassObject); -} -``` - -Then code like - -```rust,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` structs; - -* a struct holding any state needed by the lint pass (here, none); - -* a `LintPass` - 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/attributes.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/book/src/concurrency.md b/src/doc/book/src/concurrency.md deleted file mode 100644 index afed379fe471a..0000000000000 --- a/src/doc/book/src/concurrency.md +++ /dev/null @@ -1,465 +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. 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 the vast majority 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 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][ffi] that isn't -thread-safe, we wouldn't want to implement `Send`, and so the compiler will help -us enforce that it can't leave the current thread. - -[ffi]: ffi.html - -### `Sync` - -The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). -When a type `T` implements `Sync`, it indicates that something -of this type has no possibility of introducing memory unsafety when used from -multiple threads concurrently through shared references. This implies that -types which don't have [interior mutability](mutability.html) are inherently -`Sync`, which includes simple primitive types (like `u8`) and aggregate types -containing them. - -For sharing references across threads, Rust provides a wrapper type called -`Arc`. `Arc` implements `Send` and `Sync` if and only if `T` implements -both `Send` and `Sync`. For example, an object of type `Arc>` cannot -be transferred across threads because -[`RefCell`](choosing-your-guarantees.html#refcellt) does not implement -`Sync`, consequently `Arc>` would not implement `Send`. - -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`: - -```rust -use std::thread; - -fn main() { - thread::spawn(|| { - println!("Hello from a thread!"); - }); -} -``` - -The `thread::spawn()` method accepts a [closure](closures.html), which is executed in a -new thread. It returns a handle to the thread, that can be used to -wait for the child thread to finish and extract its result: - -```rust -use std::thread; - -fn main() { - let handle = thread::spawn(|| { - "Hello from a thread!" - }); - - println!("{}", handle.join().unwrap()); -} -``` - -As closures can capture variables from their environment, we can also try to -bring some data into the other thread: - -```rust,ignore -use std::thread; - -fn main() { - let x = 1; - thread::spawn(|| { - println!("x is {}", x); - }); -} -``` - -However, this gives us an error: - -```text -5:19: 7:6 error: closure may outlive the current function, but it - borrows `x`, which is owned by the current function -... -5:19: 7:6 help: to force the closure to take ownership of `x` (and any other referenced variables), - use the `move` keyword, as shown: - thread::spawn(move || { - println!("x is {}", x); - }); -``` - -This is because by default closures capture variables by reference, and thus the -closure only captures a _reference to `x`_. This is a problem, because the -thread may outlive the scope of `x`, leading to a dangling pointer. - -To fix this, we use a `move` closure as mentioned in the error message. `move` -closures are explained in depth [here](closures.html#move-closures); basically -they move variables from their environment into themselves. - -```rust -use std::thread; - -fn main() { - let x = 1; - thread::spawn(move || { - println!("x is {}", x); - }); -} -``` - -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: - -```rust,ignore -use std::thread; -use std::time::Duration; - -fn main() { - let mut data = vec![1, 2, 3]; - - for i in 0..3 { - thread::spawn(move || { - data[0] += i; - }); - } - - thread::sleep(Duration::from_millis(50)); -} -``` - -This gives us an error: - -```text -8:17 error: capture of moved value: `data` - data[0] += i; - ^~~~ -``` - -Rust knows this wouldn't be safe! If we had a reference to `data` in each -thread, and the thread takes ownership of the reference, we'd have three owners! -`data` gets moved out of `main` in the first call to `spawn()`, so subsequent -calls in the loop cannot use this variable. - -So, we need some type that lets us have more than one owning reference to a -value. Usually, we'd use `Rc` for this, which is a reference counted type -that provides shared ownership. It has some runtime bookkeeping that keeps track -of the number of references to it, hence the "reference count" part of its name. - -Calling `clone()` on an `Rc` will return a new owned reference and bump the -internal reference count. We create one of these for each thread: - - -```rust,ignore -use std::thread; -use std::time::Duration; -use std::rc::Rc; - -fn main() { - let mut data = Rc::new(vec![1, 2, 3]); - - for i in 0..3 { - // Create a new owned reference: - let data_ref = data.clone(); - - // Use it in a thread: - thread::spawn(move || { - data_ref[0] += i; - }); - } - - thread::sleep(Duration::from_millis(50)); -} -``` - -This won't work, however, and will give us the error: - -```text -13:9: 13:22 error: the trait bound `alloc::rc::Rc> : core::marker::Send` - is not satisfied -... -13:9: 13:22 note: `alloc::rc::Rc>` - cannot be sent between threads safely -``` - -As the error message mentions, `Rc` cannot be sent between threads safely. This -is because the internal reference count is not maintained in a thread safe -matter and can have a data race. - -To solve this, we'll use `Arc`, Rust's standard atomic reference count type. - -The Atomic part means `Arc` can safely be accessed from multiple threads. -To do this the compiler guarantees that mutations of the internal count use -indivisible operations which can't have data races. - -In essence, `Arc` is a type that lets us share ownership of data _across -threads_. - - -```rust,ignore -use std::thread; -use std::sync::Arc; -use std::time::Duration; - -fn main() { - let mut data = Arc::new(vec![1, 2, 3]); - - for i in 0..3 { - let data = data.clone(); - thread::spawn(move || { - data[0] += i; - }); - } - - thread::sleep(Duration::from_millis(50)); -} -``` - -Similarly to last time, we use `clone()` to create a new owned handle. -This handle is then moved into the new thread. - -And... still gives us an error. - -```text -:11:24 error: cannot borrow immutable borrowed content as mutable -:11 data[0] += i; - ^~~~ -``` - -`Arc` by default has immutable contents. It allows the _sharing_ of data -between threads, but shared mutable data is unsafe—and when threads are -involved—can cause data races! - - -Usually when we wish to make something in an immutable position mutable, we use -`Cell` or `RefCell` which allow safe mutation via runtime checks or -otherwise (see also: [Choosing Your Guarantees](choosing-your-guarantees.html)). -However, similar to `Rc`, these are not thread safe. If we try using these, we -will get an error about these types not being `Sync`, and the code will fail to -compile. - -It looks like we need some type that allows us to safely mutate a shared value -across threads, for example a type that can ensure only one thread at a time is -able to mutate the value inside it at any one time. - -For that, we can use the `Mutex` type! - -Here's the working version: - -```rust -use std::sync::{Arc, Mutex}; -use std::thread; -use std::time::Duration; - -fn main() { - let data = Arc::new(Mutex::new(vec![1, 2, 3])); - - for i in 0..3 { - let data = data.clone(); - thread::spawn(move || { - let mut data = data.lock().unwrap(); - data[0] += i; - }); - } - - thread::sleep(Duration::from_millis(50)); -} -``` - -Note that the value of `i` is bound (copied) to the closure and not shared -among the threads. - -We're "locking" the mutex here. A mutex (short for "mutual exclusion"), as -mentioned, only allows one thread at a time to access a value. When we wish to -access the value, we use `lock()` on it. This will "lock" the mutex, and no -other thread will be able to lock it (and hence, do anything with the value) -until we're done with it. If a thread attempts to lock a mutex which is already -locked, it will wait until the other thread releases the lock. - -The lock "release" here is implicit; when the result of the lock (in this case, -`data`) goes out of scope, the lock is automatically released. - -Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of -[`Mutex`](../std/sync/struct.Mutex.html) has this signature: - -```rust,ignore -fn lock(&self) -> LockResult> -``` - -and because `Send` is not implemented for `MutexGuard`, the guard cannot -cross thread boundaries, ensuring thread-locality of lock acquire and release. - -Let's examine the body of the thread more closely: - -```rust -# use std::sync::{Arc, Mutex}; -# use std::thread; -# use std::time::Duration; -# fn main() { -# let data = Arc::new(Mutex::new(vec![1, 2, 3])); -# for i in 0..3 { -# let data = data.clone(); -thread::spawn(move || { - let mut data = data.lock().unwrap(); - data[0] += i; -}); -# } -# thread::sleep(Duration::from_millis(50)); -# } -``` - -First, we call `lock()`, which acquires the mutex's lock. Because this may fail, -it returns a `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: - -```rust -use std::sync::{Arc, Mutex}; -use std::thread; -use std::sync::mpsc; - -fn main() { - let data = Arc::new(Mutex::new(0)); - - // `tx` is the "transmitter" or "sender". - // `rx` is the "receiver". - 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(()).unwrap(); - }); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } -} -``` - -We use the `mpsc::channel()` method to construct a new channel. We `send` -a simple `()` down the channel, and then wait for ten of them to come back. - -While this channel is sending a generic signal, we can send any data that -is `Send` over the channel! - -```rust -use std::thread; -use std::sync::mpsc; - -fn main() { - let (tx, rx) = mpsc::channel(); - - for i in 0..10 { - let tx = tx.clone(); - - thread::spawn(move || { - let answer = i * i; - - tx.send(answer).unwrap(); - }); - } - - for _ in 0..10 { - println!("{}", rx.recv().unwrap()); - } -} -``` - -Here we create 10 threads, asking each to calculate the square of a number (`i` -at the time of `spawn()`), and then `send()` back 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: - -```rust -use std::thread; - -let handle = thread::spawn(move || { - panic!("oops!"); -}); - -let result = handle.join(); - -assert!(result.is_err()); -``` - -`Thread.join()` gives us a `Result` back, which allows us to check if the thread -has panicked or not. diff --git a/src/doc/book/src/conditional-compilation.md b/src/doc/book/src/conditional-compilation.md deleted file mode 100644 index 0562e9fc430f6..0000000000000 --- a/src/doc/book/src/conditional-compilation.md +++ /dev/null @@ -1,91 +0,0 @@ -# Conditional Compilation - -Rust has a special attribute, `#[cfg]`, which allows you to compile code -based on a flag passed to the compiler. It has two forms: - -```rust -#[cfg(foo)] -# fn foo() {} - -#[cfg(bar = "baz")] -# fn bar() {} -``` - -They also have some helpers: - -```rust -#[cfg(any(unix, windows))] -# fn foo() {} - -#[cfg(all(unix, target_pointer_width = "32"))] -# fn bar() {} - -#[cfg(not(foo))] -# fn not_foo() {} -``` - -These can nest arbitrarily: - -```rust -#[cfg(any(not(unix), all(target_os="macos", target_arch = "powerpc")))] -# fn foo() {} -``` - -As for how to enable or disable these switches, if you’re using Cargo, -they get set in the [`[features]` section][features] of your `Cargo.toml`: - -[features]: http://doc.crates.io/manifest.html#the-features-section - -```toml -[features] -# no features by default -default = [] - -# Add feature "foo" here, then you can use it. -# Our "foo" feature depends on nothing else. -foo = [] -``` - -When you do this, Cargo passes along a flag to `rustc`: - -```text ---cfg feature="${feature_name}" -``` - -The sum of these `cfg` flags will determine which ones get activated, and -therefore, which code gets compiled. Let’s take this code: - -```rust -#[cfg(feature = "foo")] -mod foo { -} -``` - -If we compile it with `cargo build --features "foo"`, it will send the `--cfg -feature="foo"` flag to `rustc`, and the output will have the `mod foo` in it. -If we compile it with a regular `cargo build`, no extra flags get passed on, -and so, no `foo` module will exist. - -# cfg_attr - -You can also set another attribute based on a `cfg` variable with `cfg_attr`: - -```rust -#[cfg_attr(a, b)] -# fn foo() {} -``` - -Will be the same as `#[b]` if `a` is set by `cfg` attribute, and nothing otherwise. - -# cfg! - -The `cfg!` macro lets you use these kinds of flags elsewhere in your code, too: - -```rust -if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - println!("Think Different!"); -} -``` - -These will be replaced by a `true` or `false` at compile-time, depending on the -configuration settings. diff --git a/src/doc/book/src/const-and-static.md b/src/doc/book/src/const-and-static.md deleted file mode 100644 index 66a48566bd7c4..0000000000000 --- a/src/doc/book/src/const-and-static.md +++ /dev/null @@ -1,83 +0,0 @@ -# const and static - -Rust has a way of defining constants with the `const` keyword: - -```rust -const N: i32 = 5; -``` - -Unlike [`let`][let] bindings, you must annotate the type of a `const`. - -[let]: variable-bindings.html - -Constants live for the entire lifetime of a program. More specifically, -constants in Rust have no fixed address in memory. This is because they’re -effectively inlined to each place that they’re used. References to the same -constant are not necessarily guaranteed to refer to the same memory address for -this reason. - -# `static` - -Rust provides a ‘global variable’ sort of facility in static items. They’re -similar to constants, but static items aren’t inlined upon use. This means that -there is only one instance for each value, and it’s at a fixed location in -memory. - -Here’s an example: - -```rust -static N: i32 = 5; -``` - -Unlike [`let`][let] bindings, you must annotate the type of a `static`. - -Statics live for the entire lifetime of a program, and therefore any -reference stored in a static has a [`'static` lifetime][lifetimes]: - -```rust -static NAME: &'static str = "Steve"; -``` - -[lifetimes]: lifetimes.html - -## Mutability - -You can introduce mutability with the `mut` keyword: - -```rust -static mut N: i32 = 5; -``` - -Because this is mutable, one thread could be updating `N` while another is -reading it, causing memory unsafety. As such both accessing and mutating a -`static mut` is [`unsafe`][unsafe], and so must be done in an `unsafe` block: - -```rust -# static mut N: i32 = 5; - -unsafe { - N += 1; - - println!("N: {}", N); -} -``` - -[unsafe]: unsafe.html - -Furthermore, any type stored in a `static` must be `Sync`, and must not have -a [`Drop`][drop] implementation. - -[drop]: drop.html - -# Initializing - -Both `const` and `static` have requirements for giving them a value. They must -be given a value that’s a constant expression. In other words, you cannot use -the result of a function call or anything similarly complex or at runtime. - -# Which construct should I use? - -Almost always, if you can choose between the two, choose `const`. It’s pretty -rare that you actually want a memory location associated with your constant, -and using a `const` allows for optimizations like constant propagation not only -in your crate but downstream crates. diff --git a/src/doc/book/src/crates-and-modules.md b/src/doc/book/src/crates-and-modules.md deleted file mode 100644 index 84f5fac044e0e..0000000000000 --- a/src/doc/book/src/crates-and-modules.md +++ /dev/null @@ -1,593 +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 is 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: - -```rust -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 -``` - -`libphrases-.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`, `src/english/farewells.rs`, -`src/japanese/greetings.rs` and `src/japanese/farewells.rs` or -`src/english/greetings/mod.rs`, `src/english/farewells/mod.rs`, -`src/japanese/greetings/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`, `src/english/farewells.rs`, -`src/japanese/greetings.rs` and `src/japanese/farewells.rs`. Whew! - -The contents of `src/english/greetings.rs`, -`src/english/farewells.rs`, `src/japanese/greetings.rs` and -`src/japanese/farewells.rs` are all 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 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. - -(Note: when importing a crate that has dashes in its name "like-this", which is -not a valid Rust identifier, it will be converted by changing the dashes to -underscores, so you would write `extern crate like_this;`.) - -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 only 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. -``` - -`pub` also applies to `struct`s and their member fields. In keeping with Rust’s -tendency toward safety, simply making a `struct` public won't automatically -make its members public: you must mark the fields individually with `pub`. - -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 only 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. - -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: さようなら -``` - -## Complex imports - -Rust offers several advanced options that can add compactness and -convenience to your `extern crate` and `use` statements. Here is an example: - -```rust,ignore -extern crate phrases as sayings; - -use sayings::japanese::greetings as ja_greetings; -use sayings::japanese::farewells::*; -use sayings::english::{self, greetings as en_greetings, farewells as en_farewells}; - -fn main() { - println!("Hello in English; {}", en_greetings::hello()); - println!("And in Japanese: {}", ja_greetings::hello()); - println!("Goodbye in English: {}", english::farewells::goodbye()); - println!("Again: {}", en_farewells::goodbye()); - println!("And in Japanese: {}", goodbye()); -} -``` - -What's going on here? - -First, both `extern crate` and `use` allow renaming the thing that is being -imported. So the crate is still called "phrases", but here we will refer -to it as "sayings". Similarly, the first `use` statement pulls in the -`japanese::greetings` module from the crate, but makes it available as -`ja_greetings` as opposed to simply `greetings`. This can help to avoid -ambiguity when importing similarly-named items from different places. - -The second `use` statement uses a star glob to bring in all public symbols from -the `sayings::japanese::farewells` module. As you can see we can later refer to -the Japanese `goodbye` function with no module qualifiers. This kind of glob -should be used sparingly. It’s worth noting that it only imports the public -symbols, even if the code doing the globbing is in the same module. - -The third `use` statement bears more explanation. It's using "brace expansion" -globbing to compress three `use` statements into one (this sort of syntax -may be familiar if you've written Linux shell scripts before). The -uncompressed form of this statement would be: - -```rust,ignore -use sayings::english; -use sayings::english::greetings as en_greetings; -use sayings::english::farewells as en_farewells; -``` - -As you can see, the curly brackets compress `use` statements for several items -under the same path, and in this context `self` refers back to that path. -Note: The curly brackets cannot be nested or mixed with star globbing. diff --git a/src/doc/book/src/deref-coercions.md b/src/doc/book/src/deref-coercions.md deleted file mode 100644 index 8552a7c8b3425..0000000000000 --- a/src/doc/book/src/deref-coercions.md +++ /dev/null @@ -1,119 +0,0 @@ -# `Deref` coercions - -The standard library provides a special trait, [`Deref`][deref]. It’s normally -used to overload `*`, the dereference operator: - -```rust -use std::ops::Deref; - -struct DerefExample { - value: T, -} - -impl Deref for DerefExample { - type Target = T; - - fn deref(&self) -> &T { - &self.value - } -} - -fn main() { - let x = DerefExample { value: 'a' }; - assert_eq!('a', *x); -} -``` - -[deref]: ../std/ops/trait.Deref.html - -This is useful for writing custom pointer types. However, there’s a language -feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a -type `U`, and it implements `Deref`, values of `&U` will -automatically coerce to a `&T`. Here’s an example: - -```rust -fn foo(s: &str) { - // Borrow a string for a second. -} - -// String implements Deref. -let owned = "Hello".to_string(); - -// Therefore, this works: -foo(&owned); -``` - -Using an ampersand in front of a value takes a reference to it. So `owned` is a -`String`, `&owned` is an `&String`, and since `impl Deref for -String`, `&String` will deref to `&str`, which `foo()` takes. - -That’s it. This rule is one of the only places in which Rust does an automatic -conversion for you, but it adds a lot of flexibility. For example, the `Rc` -type implements `Deref`, so this works: - -```rust -use std::rc::Rc; - -fn foo(s: &str) { - // Borrow a string for a second. -} - -// String implements Deref. -let owned = "Hello".to_string(); -let counted = Rc::new(owned); - -// Therefore, this works: -foo(&counted); -``` - -All we’ve done is wrap our `String` in an `Rc`. But we can now pass the -`Rc` around anywhere we’d have a `String`. The signature of `foo` -didn’t change, but works just as well with either type. This example has two -conversions: `&Rc` to `&String` and then `&String` to `&str`. Rust will do -this as many times as possible until the types match. - -Another very common implementation provided by the standard library is: - -```rust -fn foo(s: &[i32]) { - // Borrow a slice for a second. -} - -// Vec implements Deref. -let owned = vec![1, 2, 3]; - -foo(&owned); -``` - -Vectors can `Deref` to a slice. - -## Deref and method calls - -`Deref` will also kick in when calling a method. Consider the following -example. - -```rust -struct Foo; - -impl Foo { - fn foo(&self) { println!("Foo"); } -} - -let f = &&Foo; - -f.foo(); -``` - -Even though `f` is a `&&Foo` and `foo` takes `&self`, this works. That’s -because these things are the same: - -```rust,ignore -f.foo(); -(&f).foo(); -(&&f).foo(); -(&&&&&&&&f).foo(); -``` - -A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo` -called, because the compiler will insert as many * operations as necessary to -get it right. And since it’s inserting `*`s, that uses `Deref`. diff --git a/src/doc/book/src/documentation.md b/src/doc/book/src/documentation.md deleted file mode 100644 index 176a7e508c0ac..0000000000000 --- a/src/doc/book/src/documentation.md +++ /dev/null @@ -1,655 +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. - -The first thing to notice about this annotation is that 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: - -```rust -/// The `Option` type. See [the module level documentation](index.html) 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](index.html) 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 -nothing after that last comment. - -[rc-new]: ../std/rc/struct.Rc.html#method.new - -### Writing documentation comments - -Anyway, let's cover each part of this comment in detail: - -```rust -/// 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. - -```rust -/// -/// 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 - -Next, are special sections. These are indicated with a header, `#`. There -are four kinds of headers that are commonly used. They aren't special syntax, -just convention, for now. - -```rust -/// # 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. - -```rust -/// # Errors -# 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. - -```rust -/// # Safety -# fn foo() {} -``` - -If your function is `unsafe`, you should explain which invariants the caller is -responsible for upholding. - -```rust -/// # Examples -/// -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -# fn foo() {} -``` - -Fourth, `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: - -```rust -/// # 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() {} -``` - -#### Code block annotations - -To write some Rust code in a comment, use the triple graves: - -```rust -/// ``` -/// println!("Hello, world"); -/// ``` -# fn foo() {} -``` - -This will add code highlighting. If you are only showing plain text, put `text` -instead of `rust` after the triple graves (see below). - -## Documentation as tests - -Let's discuss our sample example documentation: - -```rust -/// ``` -/// 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, using heuristics to attempt -to put it in the right place. For example: - -```rust -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -# fn foo() {} -``` - -This will end up testing: - -```rust -fn main() { - use std::rc::Rc; - let five = Rc::new(5); -} -``` - -Here's the full algorithm rustdoc uses to preprocess 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 (note the lack of `#[macro_use]`). -4. Finally, if the example does not contain `fn main`, the remainder of the - text is wrapped in `fn main() { your_code }`. - -This generated `fn main` can be a problem! If you have `extern crate` or a `mod` -statements in the example code that are referred to by `use` statements, they will -fail to resolve unless you include at least `fn main() {}` to inhibit step 4. -`#[macro_use] extern crate` also does not work except at the crate root, so when -testing macros an explicit `main` is always required. It doesn't have to clutter -up your docs, though -- keep reading! - -Sometimes this algorithm 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: - -```rust -/// 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 only 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, imagine that we wanted to document this code: - -```rust -let x = 5; -let y = 6; -println!("{}", x + y); -``` - -We might want the documentation to end up looking like this: - -> First, we set `x` to five: -> -> ```rust -> let x = 5; -> # let y = 6; -> # println!("{}", x + y); -> ``` -> -> Next, we set `y` to six: -> -> ```rust -> # let x = 5; -> let y = 6; -> # println!("{}", x + y); -> ``` -> -> Finally, we print the sum of `x` and `y`: -> -> ```rust -> # let x = 5; -> # let y = 6; -> println!("{}", x + y); -> ``` - -To keep each code block testable, we want the whole program in each block, but -we don't want the reader to see every line every time. Here's what we put in -our source code: - -```text - First, we set `x` to five: - - ```rust - let x = 5; - # let y = 6; - # println!("{}", x + y); - ``` - - Next, we set `y` to six: - - ```rust - # let x = 5; - let y = 6; - # println!("{}", x + y); - ``` - - Finally, we print the sum of `x` and `y`: - - ```rust - # 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: - -```rust -/// 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.”); -/// # } -/// ``` -/// -/// ```rust,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 (for reasons discussed above). Finally, a judicious use of -`#` to comment out those two things, so they don’t show up in the output. - -Another case where the use of `#` is handy is when you want to ignore -error handling. Lets say you want the following, - -```rust,ignore -/// use std::io; -/// let mut input = String::new(); -/// try!(io::stdin().read_line(&mut input)); -``` - -The problem is that `try!` returns a `Result` and test functions -don't return anything so this will give a mismatched types error. - -```rust,ignore -/// A doc test using try! -/// -/// ``` -/// use std::io; -/// # fn foo() -> io::Result<()> { -/// let mut input = String::new(); -/// try!(io::stdin().read_line(&mut input)); -/// # Ok(()) -/// # } -/// ``` -# fn foo() {} -``` - -You can get around this by wrapping the code in a function. This catches -and swallows the `Result` when running tests on the docs. This -pattern appears regularly in the standard library. - -### 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. **However, -`cargo test` will not test binary crates, only library ones.** This is -due to the way `rustdoc` works: it links against the library to be tested, -but with a binary, there’s nothing to link to. - -There are a few more annotations that are useful to help `rustdoc` do the right -thing when testing your code: - -```rust -/// ```rust,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. - -```rust -/// ```rust,should_panic -/// assert!(false); -/// ``` -# fn foo() {} -``` - -`should_panic` tells `rustdoc` that the code should compile correctly, but -not actually pass as a test. - -```rust -/// ```rust,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 retrieve a web page," -which you would want to ensure compiles, but might be run in a test -environment that has no network access. - -### Documenting modules - -Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words: - -```rust -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: - -```rust -//! A module for using `foo`s. -//! -//! The `foo` module contains a lot of useful functionality blah blah blah... -``` - -### Crate documentation - -Crates can be documented by placing an inner doc comment (`//!`) at the -beginning of the crate root, aka `lib.rs`: - -```rust -//! This is documentation for the `foo` crate. -//! -//! The foo crate is meant to be used for bar. -``` - -### 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: - -```rust -/// # Examples -/// -/// ``` -/// use std::rc::Rc; -/// -/// let five = Rc::new(5); -/// ``` -# fn foo() {} -``` - -is: - -~~~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 syntactic sugar for documentation -attributes: - -```rust -/// this -# fn foo() {} - -#[doc="this"] -# fn bar() {} -``` - -are the same, as are these: - -```rust -//! 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: - -```rust,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`: - -```rust,ignore -extern crate foo; - -#[doc(no_inline)] -pub use foo::bar; -``` - -## Missing documentation - -Sometimes you want to make sure that every single public thing in your project -is documented, especially when you are working on a library. Rust allows you to -to generate warnings or errors, when an item is missing documentation. -To generate warnings you use `warn`: - -```rust,ignore -#![warn(missing_docs)] -``` - -And to generate errors you use `deny`: - -```rust,ignore -#![deny(missing_docs)] -``` - -There are cases where you want to disable these warnings/errors to explicitly -leave something undocumented. This is done by using `allow`: - -```rust -#[allow(missing_docs)] -struct Undocumented; -``` - -You might even want to hide items from the documentation completely: - -```rust -#[doc(hidden)] -struct Hidden; -``` - -### Controlling HTML - -You can control a few aspects of the HTML that `rustdoc` generates through the -`#![doc]` version of the attribute: - -```rust,ignore -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/")] -``` - -This sets a few different options, with a logo, favicon, and a root URL. - -### Configuring documentation tests - -You can also configure the way that `rustdoc` tests your documentation examples -through the `#![doc(test(..))]` attribute. - -```rust -#![doc(test(attr(allow(unused_variables), deny(warnings))))] -``` - -This allows unused variables within the examples, but will fail the test for any -other lint warning thrown. - -## Generation options - -`rustdoc` also contains a few other options on the command line, for further customization: - -- `--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. - -## Security note - -The Markdown in documentation comments is placed without processing into -the final webpage. Be careful with literal HTML: - -```rust -/// -# fn foo() {} -``` diff --git a/src/doc/book/src/drop.md b/src/doc/book/src/drop.md deleted file mode 100644 index 53c507eba3f78..0000000000000 --- a/src/doc/book/src/drop.md +++ /dev/null @@ -1,67 +0,0 @@ -# Drop - -Now that we’ve discussed traits, let’s talk about a particular trait provided -by the Rust standard library, [`Drop`][drop]. The `Drop` trait provides a way -to run some code when a value goes out of scope. For example: - -[drop]: ../std/ops/trait.Drop.html - -```rust -struct HasDrop; - -impl Drop for HasDrop { - fn drop(&mut self) { - println!("Dropping!"); - } -} - -fn main() { - let x = HasDrop; - - // Do stuff. - -} // `x` goes out of scope here. -``` - -When `x` goes out of scope at the end of `main()`, the code for `Drop` will -run. `Drop` has one method, which is also called `drop()`. It takes a mutable -reference to `self`. - -That’s it! The mechanics of `Drop` are very simple, but there are some -subtleties. For example, values are dropped in the opposite order they are -declared. Here’s another example: - -```rust -struct Firework { - strength: i32, -} - -impl Drop for Firework { - fn drop(&mut self) { - println!("BOOM times {}!!!", self.strength); - } -} - -fn main() { - let firecracker = Firework { strength: 1 }; - let tnt = Firework { strength: 100 }; -} -``` - -This will output: - -```text -BOOM times 100!!! -BOOM times 1!!! -``` - -The `tnt` goes off before the `firecracker` does, because it was declared -afterwards. Last in, first out. - -So what is `Drop` good for? Generally, `Drop` is used to clean up any resources -associated with a `struct`. For example, the [`Arc` type][arc] is a -reference-counted type. When `Drop` is called, it will decrement the reference -count, and if the total number of references is zero, will clean up the -underlying value. - -[arc]: ../std/sync/struct.Arc.html diff --git a/src/doc/book/src/effective-rust.md b/src/doc/book/src/effective-rust.md deleted file mode 100644 index ce2dfe4eae27e..0000000000000 --- a/src/doc/book/src/effective-rust.md +++ /dev/null @@ -1,8 +0,0 @@ -# Effective Rust - -So you’ve learned how to write some Rust code. But there’s a difference between -writing *any* Rust code and writing *good* Rust code. - -This chapter consists of relatively independent tutorials which show you how to -take your Rust to the next level. Common patterns and standard library features -will be introduced. Read these sections in any order of your choosing. diff --git a/src/doc/book/src/enums.md b/src/doc/book/src/enums.md deleted file mode 100644 index 9cf5e6bfa21ac..0000000000000 --- a/src/doc/book/src/enums.md +++ /dev/null @@ -1,107 +0,0 @@ -# Enums - -An `enum` in Rust is a type that represents data that is one of -several possible variants. Each variant in the `enum` can optionally -have data associated with it: - -```rust -enum Message { - Quit, - ChangeColor(i32, i32, i32), - Move { x: i32, y: i32 }, - Write(String), -} -``` - -The syntax for defining variants resembles the syntaxes used to define structs: -you can have variants with no data (like unit-like structs), variants with named -data, and variants with unnamed data (like tuple structs). Unlike -separate struct definitions, however, an `enum` is a single type. A -value of the enum can match any of the variants. For this reason, an -enum is sometimes called a ‘sum type’: the set of possible values of the -enum is the sum of the sets of possible values for each variant. - -We use the `::` syntax to use the name of each variant: they’re scoped by the name -of the `enum` itself. This allows both of these to work: - -```rust -# enum Message { -# Move { x: i32, y: i32 }, -# } -let x: Message = Message::Move { x: 3, y: 4 }; - -enum BoardGameTurn { - Move { squares: i32 }, - Pass, -} - -let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 }; -``` - -Both variants are named `Move`, but since they’re scoped to the name of -the enum, they can both be used without conflict. - -A value of an `enum` type contains information about which variant it is, -in addition to any data associated with that variant. This is sometimes -referred to as a ‘tagged union’, since the data includes a ‘tag’ -indicating what type it is. The compiler uses this information to -enforce that you’re accessing the data in the enum safely. For instance, -you can’t simply try to destructure a value as if it were one of the -possible variants: - -```rust,ignore -fn process_color_change(msg: Message) { - let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error. -} -``` - -Not supporting these operations 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 section. We don’t know enough about Rust to implement -equality yet, but we’ll find out in the [`traits`][traits] section. - -[match]: match.html -[traits]: traits.html - -# Constructors as functions - -An `enum` constructor can also be used like a function. For example: - -```rust -# enum Message { -# Write(String), -# } -let m = Message::Write("Hello, world".to_string()); -``` - -is the same as - -```rust -# enum Message { -# Write(String), -# } -fn foo(x: String) -> Message { - Message::Write(x) -} - -let x = foo("Hello, world".to_string()); -``` - -This is not immediately useful to us, but when we get to -[`closures`][closures], we’ll talk about passing functions as arguments to -other functions. For example, with [`iterators`][iterators], we can do this -to convert a vector of `String`s into a vector of `Message::Write`s: - -```rust -# enum Message { -# Write(String), -# } - -let v = vec!["Hello".to_string(), "World".to_string()]; - -let v1: Vec = v.into_iter().map(Message::Write).collect(); -``` - -[closures]: closures.html -[iterators]: iterators.html diff --git a/src/doc/book/src/error-handling.md b/src/doc/book/src/error-handling.md deleted file mode 100644 index c823c32a135bb..0000000000000 --- a/src/doc/book/src/error-handling.md +++ /dev/null @@ -1,2213 +0,0 @@ -# Error Handling - -Like most programming languages, Rust encourages the programmer to handle -errors in a particular way. Generally speaking, error handling is divided into -two broad categories: exceptions and return values. Rust opts for return -values. - -In this section, we intend to provide a comprehensive treatment of how to deal -with errors in Rust. More than that, we will attempt to introduce error handling -one piece at a time so that you'll come away with a solid working knowledge of -how everything fits together. - -When done naïvely, error handling in Rust can be verbose and annoying. This -section will explore those stumbling blocks and demonstrate how to use the -standard library to make error handling concise and ergonomic. - -# Table of Contents - -This section is very long, mostly because we start at the very beginning with -sum types and combinators, and try to motivate the way Rust does error handling -incrementally. As such, programmers with experience in other expressive type -systems may want to jump around. - -* [The Basics](#the-basics) - * [Unwrapping explained](#unwrapping-explained) - * [The `Option` type](#the-option-type) - * [Composing `Option` values](#composing-optiont-values) - * [The `Result` type](#the-result-type) - * [Parsing integers](#parsing-integers) - * [The `Result` type alias idiom](#the-result-type-alias-idiom) - * [A brief interlude: unwrapping isn't evil](#a-brief-interlude-unwrapping-isnt-evil) -* [Working with multiple error types](#working-with-multiple-error-types) - * [Composing `Option` and `Result`](#composing-option-and-result) - * [The limits of combinators](#the-limits-of-combinators) - * [Early returns](#early-returns) - * [The `try!` macro](#the-try-macro) - * [Defining your own error type](#defining-your-own-error-type) -* [Standard library traits used for error handling](#standard-library-traits-used-for-error-handling) - * [The `Error` trait](#the-error-trait) - * [The `From` trait](#the-from-trait) - * [The real `try!` macro](#the-real-try-macro) - * [Composing custom error types](#composing-custom-error-types) - * [Advice for library writers](#advice-for-library-writers) -* [Case study: A program to read population data](#case-study-a-program-to-read-population-data) - * [Initial setup](#initial-setup) - * [Argument parsing](#argument-parsing) - * [Writing the logic](#writing-the-logic) - * [Error handling with `Box`](#error-handling-with-boxerror) - * [Reading from stdin](#reading-from-stdin) - * [Error handling with a custom type](#error-handling-with-a-custom-type) - * [Adding functionality](#adding-functionality) -* [The short story](#the-short-story) - -# The Basics - -You can think of error handling as using *case analysis* to determine whether -a computation was successful or not. As you will see, the key to ergonomic error -handling is reducing the amount of explicit case analysis the programmer has to -do while keeping code composable. - -Keeping code composable is important, because without that requirement, we -could [`panic`](../std/macro.panic.html) whenever we -come across something unexpected. (`panic` causes the current task to unwind, -and in most cases, the entire program aborts.) Here's an example: - -```rust,should_panic -// Guess a number between 1 and 10. -// If it matches the number we had in mind, return `true`. Else, return `false`. -fn guess(n: i32) -> bool { - if n < 1 || n > 10 { - panic!("Invalid number: {}", n); - } - n == 5 -} - -fn main() { - guess(11); -} -``` - -If you try running this code, the program will crash with a message like this: - -```text -thread 'main' panicked at 'Invalid number: 11', src/bin/panic-simple.rs:5 -``` - -Here's another example that is slightly less contrived. A program that accepts -an integer as an argument, doubles it and prints it. - - - -```rust,should_panic -use std::env; - -fn main() { - let mut argv = env::args(); - let arg: String = argv.nth(1).unwrap(); // error 1 - let n: i32 = arg.parse().unwrap(); // error 2 - println!("{}", 2 * n); -} -``` - -If you give this program zero arguments (error 1) or if the first argument -isn't an integer (error 2), the program will panic just like in the first -example. - -You can think of this style of error handling as similar to a bull running -through a china shop. The bull will get to where it wants to go, but it will -trample everything in the process. - -## Unwrapping explained - -In the previous example, we claimed -that the program would simply panic if it reached one of the two error -conditions, yet, the program does not include an explicit call to `panic` like -the first example. This is because the -panic is embedded in the calls to `unwrap`. - -To “unwrap” something in Rust is to say, “Give me the result of the -computation, and if there was an error, panic and stop the program.” -It would be better if we showed the code for unwrapping because it is so -simple, but to do that, we will first need to explore the `Option` and `Result` -types. Both of these types have a method called `unwrap` defined on them. - -### The `Option` type - -The `Option` type is [defined in the standard library][5]: - -```rust -enum Option { - None, - Some(T), -} -``` - -The `Option` type is a way to use Rust's type system to express the -*possibility of absence*. Encoding the possibility of absence into the type -system is an important concept because it will cause the compiler to force the -programmer to handle that absence. Let's take a look at an example that tries -to find a character in a string: - - - -```rust -// Searches `haystack` for the Unicode character `needle`. If one is found, the -// byte offset of the character is returned. Otherwise, `None` is returned. -fn find(haystack: &str, needle: char) -> Option { - for (offset, c) in haystack.char_indices() { - if c == needle { - return Some(offset); - } - } - None -} -``` - -Notice that when this function finds a matching character, it doesn't only -return the `offset`. Instead, it returns `Some(offset)`. `Some` is a variant or -a *value constructor* for the `Option` type. You can think of it as a function -with the type `fn(value: T) -> Option`. Correspondingly, `None` is also a -value constructor, except it has no arguments. You can think of `None` as a -function with the type `fn() -> Option`. - -This might seem like much ado about nothing, but this is only half of the -story. The other half is *using* the `find` function we've written. Let's try -to use it to find the extension in a file name. - -```rust -# fn find(haystack: &str, needle: char) -> Option { haystack.find(needle) } -fn main() { - let file_name = "foobar.rs"; - match find(file_name, '.') { - None => println!("No file extension found."), - Some(i) => println!("File extension: {}", &file_name[i+1..]), - } -} -``` - -This code uses [pattern matching][1] to do *case -analysis* on the `Option` returned by the `find` function. In fact, case -analysis is the only way to get at the value stored inside an `Option`. This -means that you, as the programmer, must handle the case when an `Option` is -`None` instead of `Some(t)`. - -But wait, what about `unwrap`, which we used [previously](#code-unwrap-double)? -There was no case analysis there! Instead, the case analysis was put inside the -`unwrap` method for you. You could define it yourself if you want: - - - -```rust -enum Option { - None, - Some(T), -} - -impl Option { - fn unwrap(self) -> T { - match self { - Option::Some(val) => val, - Option::None => - panic!("called `Option::unwrap()` on a `None` value"), - } - } -} -``` - -The `unwrap` method *abstracts away the case analysis*. This is precisely the thing -that makes `unwrap` ergonomic to use. Unfortunately, that `panic!` means that -`unwrap` is not composable: it is the bull in the china shop. - -### Composing `Option` values - -In an [example from before](#code-option-ex-string-find), -we saw how to use `find` to discover the extension in a file name. Of course, -not all file names have a `.` in them, so it's possible that the file name has -no extension. This *possibility of absence* is encoded into the types using -`Option`. In other words, the compiler will force us to address the -possibility that an extension does not exist. In our case, we only print out a -message saying as such. - -Getting the extension of a file name is a pretty common operation, so it makes -sense to put it into a function: - -```rust -# fn find(haystack: &str, needle: char) -> Option { haystack.find(needle) } -// Returns the extension of the given file name, where the extension is defined -// as all characters following the first `.`. -// If `file_name` has no `.`, then `None` is returned. -fn extension_explicit(file_name: &str) -> Option<&str> { - match find(file_name, '.') { - None => None, - Some(i) => Some(&file_name[i+1..]), - } -} -``` - -(Pro-tip: don't use this code. Use the -[`extension`](../std/path/struct.Path.html#method.extension) -method in the standard library instead.) - -The code stays simple, but the important thing to notice is that the type of -`find` forces us to consider the possibility of absence. This is a good thing -because it means the compiler won't let us accidentally forget about the case -where a file name doesn't have an extension. On the other hand, doing explicit -case analysis like we've done in `extension_explicit` every time can get a bit -tiresome. - -In fact, the case analysis in `extension_explicit` follows a very common -pattern: *map* a function on to the value inside of an `Option`, unless the -option is `None`, in which case, return `None`. - -Rust has parametric polymorphism, so it is very easy to define a combinator -that abstracts this pattern: - - - -```rust -fn map(option: Option, f: F) -> Option where F: FnOnce(T) -> A { - match option { - None => None, - Some(value) => Some(f(value)), - } -} -``` - -Indeed, `map` is [defined as a method][2] on `Option` in the standard library. -As a method, it has a slightly different signature: methods take `self`, `&self`, -or `&mut self` as their first argument. - -Armed with our new combinator, we can rewrite our `extension_explicit` method -to get rid of the case analysis: - -```rust -# fn find(haystack: &str, needle: char) -> Option { haystack.find(needle) } -// Returns the extension of the given file name, where the extension is defined -// as all characters following the first `.`. -// If `file_name` has no `.`, then `None` is returned. -fn extension(file_name: &str) -> Option<&str> { - find(file_name, '.').map(|i| &file_name[i+1..]) -} -``` - -One other pattern we commonly find is assigning a default value to the case -when an `Option` value is `None`. For example, maybe your program assumes that -the extension of a file is `rs` even if none is present. As you might imagine, -the case analysis for this is not specific to file extensions - it can work -with any `Option`: - -```rust -fn unwrap_or(option: Option, default: T) -> T { - match option { - None => default, - Some(value) => value, - } -} -``` - -Like with `map` above, the standard library implementation is a method instead -of a free function. - -The trick here is that the default value must have the same type as the value -that might be inside the `Option`. Using it is dead simple in our case: - -```rust -# fn find(haystack: &str, needle: char) -> Option { -# for (offset, c) in haystack.char_indices() { -# if c == needle { -# return Some(offset); -# } -# } -# None -# } -# -# fn extension(file_name: &str) -> Option<&str> { -# find(file_name, '.').map(|i| &file_name[i+1..]) -# } -fn main() { - assert_eq!(extension("foobar.csv").unwrap_or("rs"), "csv"); - assert_eq!(extension("foobar").unwrap_or("rs"), "rs"); -} -``` - -(Note that `unwrap_or` is [defined as a method][3] on `Option` in the -standard library, so we use that here instead of the free-standing function we -defined above. Don't forget to check out the more general [`unwrap_or_else`][4] -method.) - -There is one more combinator that we think is worth paying special attention to: -`and_then`. It makes it easy to compose distinct computations that admit the -*possibility of absence*. For example, much of the code in this section is -about finding an extension given a file name. In order to do this, you first -need the file name which is typically extracted from a file *path*. While most -file paths have a file name, not *all* of them do. For example, `.`, `..` or -`/`. - -So, we are tasked with the challenge of finding an extension given a file -*path*. Let's start with explicit case analysis: - -```rust -# fn extension(file_name: &str) -> Option<&str> { None } -fn file_path_ext_explicit(file_path: &str) -> Option<&str> { - match file_name(file_path) { - None => None, - Some(name) => match extension(name) { - None => None, - Some(ext) => Some(ext), - } - } -} - -fn file_name(file_path: &str) -> Option<&str> { - // Implementation elided. - unimplemented!() -} -``` - -You might think that we could use the `map` combinator to reduce the case -analysis, but its type doesn't quite fit... - -```rust,ignore -fn file_path_ext(file_path: &str) -> Option<&str> { - file_name(file_path).map(|x| extension(x)) // This causes a compilation error. -} -``` - -The `map` function here wraps the value returned by the `extension` function -inside an `Option<_>` and since the `extension` function itself returns an -`Option<&str>` the expression `file_name(file_path).map(|x| extension(x))` -actually returns an `Option>`. - -But since `file_path_ext` just returns `Option<&str>` (and not -`Option>`) we get a compilation error. - -The result of the function taken by map as input is *always* [rewrapped with -`Some`](#code-option-map). Instead, we need something like `map`, but which -allows the caller to return a `Option<_>` directly without wrapping it in -another `Option<_>`. - -Its generic implementation is even simpler than `map`: - -```rust -fn and_then(option: Option, f: F) -> Option - where F: FnOnce(T) -> Option { - match option { - None => None, - Some(value) => f(value), - } -} -``` - -Now we can rewrite our `file_path_ext` function without explicit case analysis: - -```rust -# fn extension(file_name: &str) -> Option<&str> { None } -# fn file_name(file_path: &str) -> Option<&str> { None } -fn file_path_ext(file_path: &str) -> Option<&str> { - file_name(file_path).and_then(extension) -} -``` - -Side note: Since `and_then` essentially works like `map` but returns an -`Option<_>` instead of an `Option>` it is known as `flatmap` in some -other languages. - -The `Option` type has many other combinators [defined in the standard -library][5]. It is a good idea to skim this list and familiarize -yourself with what's available—they can often reduce case analysis -for you. Familiarizing yourself with these combinators will pay -dividends because many of them are also defined (with similar -semantics) for `Result`, which we will talk about next. - -Combinators make using types like `Option` ergonomic because they reduce -explicit case analysis. They are also composable because they permit the caller -to handle the possibility of absence in their own way. Methods like `unwrap` -remove choices because they will panic if `Option` is `None`. - -## The `Result` type - -The `Result` type is also -[defined in the standard library][6]: - - - -```rust -enum Result { - Ok(T), - Err(E), -} -``` - -The `Result` type is a richer version of `Option`. Instead of expressing the -possibility of *absence* like `Option` does, `Result` expresses the possibility -of *error*. Usually, the *error* is used to explain why the execution of some -computation failed. This is a strictly more general form of `Option`. Consider -the following type alias, which is semantically equivalent to the real -`Option` in every way: - -```rust -type Option = Result; -``` - -This fixes the second type parameter of `Result` to always be `()` (pronounced -“unit” or “empty tuple”). Exactly one value inhabits the `()` type: `()`. (Yup, -the type and value level terms have the same notation!) - -The `Result` type is a way of representing one of two possible outcomes in a -computation. By convention, one outcome is meant to be expected or “`Ok`” while -the other outcome is meant to be unexpected or “`Err`”. - -Just like `Option`, the `Result` type also has an -[`unwrap` method -defined][7] -in the standard library. Let's define it: - -```rust -# enum Result { Ok(T), Err(E) } -impl Result { - fn unwrap(self) -> T { - match self { - Result::Ok(val) => val, - Result::Err(err) => - panic!("called `Result::unwrap()` on an `Err` value: {:?}", err), - } - } -} -``` - -This is effectively the same as our [definition for -`Option::unwrap`](#code-option-def-unwrap), except it includes the -error value in the `panic!` message. This makes debugging easier, but -it also requires us to add a [`Debug`][8] constraint on the `E` type -parameter (which represents our error type). Since the vast majority -of types should satisfy the `Debug` constraint, this tends to work out -in practice. (`Debug` on a type simply means that there's a reasonable -way to print a human readable description of values with that type.) - -OK, let's move on to an example. - -### Parsing integers - -The Rust standard library makes converting strings to integers dead simple. -It's so easy in fact, that it is very tempting to write something like the -following: - -```rust -fn double_number(number_str: &str) -> i32 { - 2 * number_str.parse::().unwrap() -} - -fn main() { - let n: i32 = double_number("10"); - assert_eq!(n, 20); -} -``` - -At this point, you should be skeptical of calling `unwrap`. For example, if -the string doesn't parse as a number, you'll get a panic: - -```text -thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', /home/rustbuild/src/rust-buildbot/slave/beta-dist-rustc-linux/build/src/libcore/result.rs:729 -``` - -This is rather unsightly, and if this happened inside a library you're -using, you might be understandably annoyed. Instead, we should try to -handle the error in our function and let the caller decide what to -do. This means changing the return type of `double_number`. But to -what? Well, that requires looking at the signature of the [`parse` -method][9] in the standard library: - -```rust,ignore -impl str { - fn parse(&self) -> Result; -} -``` - -Hmm. So we at least know that we need to use a `Result`. Certainly, it's -possible that this could have returned an `Option`. After all, a string either -parses as a number or it doesn't, right? That's certainly a reasonable way to -go, but the implementation internally distinguishes *why* the string didn't -parse as an integer. (Whether it's an empty string, an invalid digit, too big -or too small.) Therefore, using a `Result` makes sense because we want to -provide more information than simply “absence.” We want to say *why* the -parsing failed. You should try to emulate this line of reasoning when faced -with a choice between `Option` and `Result`. If you can provide detailed error -information, then you probably should. (We'll see more on this later.) - -OK, but how do we write our return type? The `parse` method as defined -above is generic over all the different number types defined in the -standard library. We could (and probably should) also make our -function generic, but let's favor explicitness for the moment. We only -care about `i32`, so we need to [find its implementation of -`FromStr`](../std/primitive.i32.html) (do a `CTRL-F` in your browser -for “FromStr”) and look at its [associated type][10] `Err`. We did -this so we can find the concrete error type. In this case, it's -[`std::num::ParseIntError`](../std/num/struct.ParseIntError.html). -Finally, we can rewrite our function: - -```rust -use std::num::ParseIntError; - -fn double_number(number_str: &str) -> Result { - match number_str.parse::() { - Ok(n) => Ok(2 * n), - Err(err) => Err(err), - } -} - -fn main() { - match double_number("10") { - Ok(n) => assert_eq!(n, 20), - Err(err) => println!("Error: {:?}", err), - } -} -``` - -This is a little better, but now we've written a lot more code! The case -analysis has once again bitten us. - -Combinators to the rescue! Just like `Option`, `Result` has lots of combinators -defined as methods. There is a large intersection of common combinators between -`Result` and `Option`. In particular, `map` is part of that intersection: - -```rust -use std::num::ParseIntError; - -fn double_number(number_str: &str) -> Result { - number_str.parse::().map(|n| 2 * n) -} - -fn main() { - match double_number("10") { - Ok(n) => assert_eq!(n, 20), - Err(err) => println!("Error: {:?}", err), - } -} -``` - -The usual suspects are all there for `Result`, including -[`unwrap_or`](../std/result/enum.Result.html#method.unwrap_or) and -[`and_then`](../std/result/enum.Result.html#method.and_then). -Additionally, since `Result` has a second type parameter, there are -combinators that affect only the error type, such as -[`map_err`](../std/result/enum.Result.html#method.map_err) (instead of -`map`) and [`or_else`](../std/result/enum.Result.html#method.or_else) -(instead of `and_then`). - -### The `Result` type alias idiom - -In the standard library, you may frequently see types like -`Result`. But wait, [we defined `Result`](#code-result-def) to -have two type parameters. How can we get away with only specifying -one? The key is to define a `Result` type alias that *fixes* one of -the type parameters to a particular type. Usually the fixed type is -the error type. For example, our previous example parsing integers -could be rewritten like this: - -```rust -use std::num::ParseIntError; -use std::result; - -type Result = result::Result; - -fn double_number(number_str: &str) -> Result { - unimplemented!(); -} -``` - -Why would we do this? Well, if we have a lot of functions that could return -`ParseIntError`, then it's much more convenient to define an alias that always -uses `ParseIntError` so that we don't have to write it out all the time. - -The most prominent place this idiom is used in the standard library is -with [`io::Result`](../std/io/type.Result.html). Typically, one writes -`io::Result`, which makes it clear that you're using the `io` -module's type alias instead of the plain definition from -`std::result`. (This idiom is also used for -[`fmt::Result`](../std/fmt/type.Result.html).) - -## A brief interlude: unwrapping isn't evil - -If you've been following along, you might have noticed that I've taken a pretty -hard line against calling methods like `unwrap` that could `panic` and abort -your program. *Generally speaking*, this is good advice. - -However, `unwrap` can still be used judiciously. What exactly justifies use of -`unwrap` is somewhat of a grey area and reasonable people can disagree. I'll -summarize some of my *opinions* on the matter. - -* **In examples and quick 'n' dirty code.** Sometimes you're writing examples - or a quick program, and error handling simply isn't important. Beating the - convenience of `unwrap` can be hard in such scenarios, so it is very - appealing. -* **When panicking indicates a bug in the program.** When the invariants of - your code should prevent a certain case from happening (like, say, popping - from an empty stack), then panicking can be permissible. This is because it - exposes a bug in your program. This can be explicit, like from an `assert!` - failing, or it could be because your index into an array was out of bounds. - -This is probably not an exhaustive list. Moreover, when using an -`Option`, it is often better to use its -[`expect`](../std/option/enum.Option.html#method.expect) -method. `expect` does exactly the same thing as `unwrap`, except it -prints a message you give to `expect`. This makes the resulting panic -a bit nicer to deal with, since it will show your message instead of -“called unwrap on a `None` value.” - -My advice boils down to this: use good judgment. There's a reason why the words -“never do X” or “Y is considered harmful” don't appear in my writing. There are -trade offs to all things, and it is up to you as the programmer to determine -what is acceptable for your use cases. My goal is only to help you evaluate -trade offs as accurately as possible. - -Now that we've covered the basics of error handling in Rust, and -explained unwrapping, let's start exploring more of the standard -library. - -# Working with multiple error types - -Thus far, we've looked at error handling where everything was either an -`Option` or a `Result`. But what happens when you have both an -`Option` and a `Result`? Or what if you have a `Result` and a -`Result`? Handling *composition of distinct error types* is the next -challenge in front of us, and it will be the major theme throughout the rest of -this section. - -## Composing `Option` and `Result` - -So far, I've talked about combinators defined for `Option` and combinators -defined for `Result`. We can use these combinators to compose results of -different computations without doing explicit case analysis. - -Of course, in real code, things aren't always as clean. Sometimes you have a -mix of `Option` and `Result` types. Must we resort to explicit case analysis, -or can we continue using combinators? - -For now, let's revisit one of the first examples in this section: - -```rust,should_panic -use std::env; - -fn main() { - let mut argv = env::args(); - let arg: String = argv.nth(1).unwrap(); // error 1 - let n: i32 = arg.parse().unwrap(); // error 2 - println!("{}", 2 * n); -} -``` - -Given our new found knowledge of `Option`, `Result` and their various -combinators, we should try to rewrite this so that errors are handled properly -and the program doesn't panic if there's an error. - -The tricky aspect here is that `argv.nth(1)` produces an `Option` while -`arg.parse()` produces a `Result`. These aren't directly composable. When faced -with both an `Option` and a `Result`, the solution is *usually* to convert the -`Option` to a `Result`. In our case, the absence of a command line parameter -(from `env::args()`) means the user didn't invoke the program correctly. We -could use a `String` to describe the error. Let's try: - - - -```rust -use std::env; - -fn double_arg(mut argv: env::Args) -> Result { - argv.nth(1) - .ok_or("Please give at least one argument".to_owned()) - .and_then(|arg| arg.parse::().map_err(|err| err.to_string())) - .map(|n| 2 * n) -} - -fn main() { - match double_arg(env::args()) { - Ok(n) => println!("{}", n), - Err(err) => println!("Error: {}", err), - } -} -``` - -There are a couple new things in this example. The first is the use of the -[`Option::ok_or`](../std/option/enum.Option.html#method.ok_or) -combinator. This is one way to convert an `Option` into a `Result`. The -conversion requires you to specify what error to use if `Option` is `None`. -Like the other combinators we've seen, its definition is very simple: - -```rust -fn ok_or(option: Option, err: E) -> Result { - match option { - Some(val) => Ok(val), - None => Err(err), - } -} -``` - -The other new combinator used here is -[`Result::map_err`](../std/result/enum.Result.html#method.map_err). -This is like `Result::map`, except it maps a function on to the *error* -portion of a `Result` value. If the `Result` is an `Ok(...)` value, then it is -returned unmodified. - -We use `map_err` here because it is necessary for the error types to remain -the same (because of our use of `and_then`). Since we chose to convert the -`Option` (from `argv.nth(1)`) to a `Result`, we must -also convert the `ParseIntError` from `arg.parse()` to a `String`. - -## The limits of combinators - -Doing IO and parsing input is a very common task, and it's one that I -personally have done a lot of in Rust. Therefore, we will use (and continue to -use) IO and various parsing routines to exemplify error handling. - -Let's start simple. We are tasked with opening a file, reading all of its -contents and converting its contents to a number. Then we multiply it by `2` -and print the output. - -Although I've tried to convince you not to use `unwrap`, it can be useful -to first write your code using `unwrap`. It allows you to focus on your problem -instead of the error handling, and it exposes the points where proper error -handling need to occur. Let's start there so we can get a handle on the code, -and then refactor it to use better error handling. - -```rust,should_panic -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> i32 { - let mut file = File::open(file_path).unwrap(); // error 1 - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); // error 2 - let n: i32 = contents.trim().parse().unwrap(); // error 3 - 2 * n -} - -fn main() { - let doubled = file_double("foobar"); - println!("{}", doubled); -} -``` - -(N.B. The `AsRef` is used because those are the -[same bounds used on -`std::fs::File::open`](../std/fs/struct.File.html#method.open). -This makes it ergonomic to use any kind of string as a file path.) - -There are three different errors that can occur here: - -1. A problem opening the file. -2. A problem reading data from the file. -3. A problem parsing the data as a number. - -The first two problems are described via the -[`std::io::Error`](../std/io/struct.Error.html) type. We know this -because of the return types of -[`std::fs::File::open`](../std/fs/struct.File.html#method.open) and -[`std::io::Read::read_to_string`](../std/io/trait.Read.html#method.read_to_string). -(Note that they both use the [`Result` type alias -idiom](#the-result-type-alias-idiom) described previously. If you -click on the `Result` type, you'll [see the type -alias](../std/io/type.Result.html), and consequently, the underlying -`io::Error` type.) The third problem is described by the -[`std::num::ParseIntError`](../std/num/struct.ParseIntError.html) -type. The `io::Error` type in particular is *pervasive* throughout the -standard library. You will see it again and again. - -Let's start the process of refactoring the `file_double` function. To make this -function composable with other components of the program, it should *not* panic -if any of the above error conditions are met. Effectively, this means that the -function should *return an error* if any of its operations fail. Our problem is -that the return type of `file_double` is `i32`, which does not give us any -useful way of reporting an error. Thus, we must start by changing the return -type from `i32` to something else. - -The first thing we need to decide: should we use `Option` or `Result`? We -certainly could use `Option` very easily. If any of the three errors occur, we -could simply return `None`. This will work *and it is better than panicking*, -but we can do a lot better. Instead, we should pass some detail about the error -that occurred. Since we want to express the *possibility of error*, we should -use `Result`. But what should `E` be? Since two *different* types of -errors can occur, we need to convert them to a common type. One such type is -`String`. Let's see how that impacts our code: - -```rust -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result { - File::open(file_path) - .map_err(|err| err.to_string()) - .and_then(|mut file| { - let mut contents = String::new(); - file.read_to_string(&mut contents) - .map_err(|err| err.to_string()) - .map(|_| contents) - }) - .and_then(|contents| { - contents.trim().parse::() - .map_err(|err| err.to_string()) - }) - .map(|n| 2 * n) -} - -fn main() { - match file_double("foobar") { - Ok(n) => println!("{}", n), - Err(err) => println!("Error: {}", err), - } -} -``` - -This code looks a bit hairy. It can take quite a bit of practice before code -like this becomes easy to write. The way we write it is by *following the -types*. As soon as we changed the return type of `file_double` to -`Result`, we had to start looking for the right combinators. In -this case, we only used three different combinators: `and_then`, `map` and -`map_err`. - -`and_then` is used to chain multiple computations where each computation could -return an error. After opening the file, there are two more computations that -could fail: reading from the file and parsing the contents as a number. -Correspondingly, there are two calls to `and_then`. - -`map` is used to apply a function to the `Ok(...)` value of a `Result`. For -example, the very last call to `map` multiplies the `Ok(...)` value (which is -an `i32`) by `2`. If an error had occurred before that point, this operation -would have been skipped because of how `map` is defined. - -`map_err` is the trick that makes all of this work. `map_err` is like -`map`, except it applies a function to the `Err(...)` value of a `Result`. In -this case, we want to convert all of our errors to one type: `String`. Since -both `io::Error` and `num::ParseIntError` implement `ToString`, we can call the -`to_string()` method to convert them. - -With all of that said, the code is still hairy. Mastering use of combinators is -important, but they have their limits. Let's try a different approach: early -returns. - -## Early returns - -I'd like to take the code from the previous section and rewrite it using *early -returns*. Early returns let you exit the function early. We can't return early -in `file_double` from inside another closure, so we'll need to revert back to -explicit case analysis. - -```rust -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result { - let mut file = match File::open(file_path) { - Ok(file) => file, - Err(err) => return Err(err.to_string()), - }; - let mut contents = String::new(); - if let Err(err) = file.read_to_string(&mut contents) { - return Err(err.to_string()); - } - let n: i32 = match contents.trim().parse() { - Ok(n) => n, - Err(err) => return Err(err.to_string()), - }; - Ok(2 * n) -} - -fn main() { - match file_double("foobar") { - Ok(n) => println!("{}", n), - Err(err) => println!("Error: {}", err), - } -} -``` - -Reasonable people can disagree over whether this code is better than the code -that uses combinators, but if you aren't familiar with the combinator approach, -this code looks simpler to read to me. It uses explicit case analysis with -`match` and `if let`. If an error occurs, it simply stops executing the -function and returns the error (by converting it to a string). - -Isn't this a step backwards though? Previously, we said that the key to -ergonomic error handling is reducing explicit case analysis, yet we've reverted -back to explicit case analysis here. It turns out, there are *multiple* ways to -reduce explicit case analysis. Combinators aren't the only way. - -## The `try!` macro - -A cornerstone of error handling in Rust is the `try!` macro. The `try!` macro -abstracts case analysis like combinators, but unlike combinators, it also -abstracts *control flow*. Namely, it can abstract the *early return* pattern -seen above. - -Here is a simplified definition of a `try!` macro: - - - -```rust -macro_rules! try { - ($e:expr) => (match $e { - Ok(val) => val, - Err(err) => return Err(err), - }); -} -``` - -(The [real definition](../std/macro.try.html) is a bit more -sophisticated. We will address that later.) - -Using the `try!` macro makes it very easy to simplify our last example. Since -it does the case analysis and the early return for us, we get tighter code that -is easier to read: - -```rust -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result { - let mut file = try!(File::open(file_path).map_err(|e| e.to_string())); - let mut contents = String::new(); - try!(file.read_to_string(&mut contents).map_err(|e| e.to_string())); - let n = try!(contents.trim().parse::().map_err(|e| e.to_string())); - Ok(2 * n) -} - -fn main() { - match file_double("foobar") { - Ok(n) => println!("{}", n), - Err(err) => println!("Error: {}", err), - } -} -``` - -The `map_err` calls are still necessary given -[our definition of `try!`](#code-try-def-simple). -This is because the error types still need to be converted to `String`. -The good news is that we will soon learn how to remove those `map_err` calls! -The bad news is that we will need to learn a bit more about a couple important -traits in the standard library before we can remove the `map_err` calls. - -## Defining your own error type - -Before we dive into some of the standard library error traits, I'd like to wrap -up this section by removing the use of `String` as our error type in the -previous examples. - -Using `String` as we did in our previous examples is convenient because it's -easy to convert errors to strings, or even make up your own errors as strings -on the spot. However, using `String` for your errors has some downsides. - -The first downside is that the error messages tend to clutter your -code. It's possible to define the error messages elsewhere, but unless -you're unusually disciplined, it is very tempting to embed the error -message into your code. Indeed, we did exactly this in a [previous -example](#code-error-double-string). - -The second and more important downside is that `String`s are *lossy*. That is, -if all errors are converted to strings, then the errors we pass to the caller -become completely opaque. The only reasonable thing the caller can do with a -`String` error is show it to the user. Certainly, inspecting the string to -determine the type of error is not robust. (Admittedly, this downside is far -more important inside of a library as opposed to, say, an application.) - -For example, the `io::Error` type embeds an -[`io::ErrorKind`](../std/io/enum.ErrorKind.html), -which is *structured data* that represents what went wrong during an IO -operation. This is important because you might want to react differently -depending on the error. (e.g., A `BrokenPipe` error might mean quitting your -program gracefully while a `NotFound` error might mean exiting with an error -code and showing an error to the user.) With `io::ErrorKind`, the caller can -examine the type of an error with case analysis, which is strictly superior -to trying to tease out the details of an error inside of a `String`. - -Instead of using a `String` as an error type in our previous example of reading -an integer from a file, we can define our own error type that represents errors -with *structured data*. We endeavor to not drop information from underlying -errors in case the caller wants to inspect the details. - -The ideal way to represent *one of many possibilities* is to define our own -sum type using `enum`. In our case, an error is either an `io::Error` or a -`num::ParseIntError`, so a natural definition arises: - -```rust -use std::io; -use std::num; - -// We derive `Debug` because all types should probably derive `Debug`. -// This gives us a reasonable human readable description of `CliError` values. -#[derive(Debug)] -enum CliError { - Io(io::Error), - Parse(num::ParseIntError), -} -``` - -Tweaking our code is very easy. Instead of converting errors to strings, we -simply convert them to our `CliError` type using the corresponding value -constructor: - -```rust -# #[derive(Debug)] -# enum CliError { Io(::std::io::Error), Parse(::std::num::ParseIntError) } -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result { - let mut file = try!(File::open(file_path).map_err(CliError::Io)); - let mut contents = String::new(); - try!(file.read_to_string(&mut contents).map_err(CliError::Io)); - let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse)); - Ok(2 * n) -} - -fn main() { - match file_double("foobar") { - Ok(n) => println!("{}", n), - Err(err) => println!("Error: {:?}", err), - } -} -``` - -The only change here is switching `map_err(|e| e.to_string())` (which converts -errors to strings) to `map_err(CliError::Io)` or `map_err(CliError::Parse)`. -The *caller* gets to decide the level of detail to report to the user. In -effect, using a `String` as an error type removes choices from the caller while -using a custom `enum` error type like `CliError` gives the caller all of the -conveniences as before in addition to *structured data* describing the error. - -A rule of thumb is to define your own error type, but a `String` error type -will do in a pinch, particularly if you're writing an application. If you're -writing a library, defining your own error type should be strongly preferred so -that you don't remove choices from the caller unnecessarily. - -# Standard library traits used for error handling - -The standard library defines two integral traits for error handling: -[`std::error::Error`](../std/error/trait.Error.html) and -[`std::convert::From`](../std/convert/trait.From.html). While `Error` -is designed specifically for generically describing errors, the `From` -trait serves a more general role for converting values between two -distinct types. - -## The `Error` trait - -The `Error` trait is [defined in the standard -library](../std/error/trait.Error.html): - -```rust -use std::fmt::{Debug, Display}; - -trait Error: Debug + Display { - /// A short description of the error. - fn description(&self) -> &str; - - /// The lower level cause of this error, if any. - fn cause(&self) -> Option<&Error> { None } -} -``` - -This trait is super generic because it is meant to be implemented for *all* -types that represent errors. This will prove useful for writing composable code -as we'll see later. Otherwise, the trait allows you to do at least the -following things: - -* Obtain a `Debug` representation of the error. -* Obtain a user-facing `Display` representation of the error. -* Obtain a short description of the error (via the `description` method). -* Inspect the causal chain of an error, if one exists (via the `cause` method). - -The first two are a result of `Error` requiring impls for both `Debug` and -`Display`. The latter two are from the two methods defined on `Error`. The -power of `Error` comes from the fact that all error types impl `Error`, which -means errors can be existentially quantified as a -[trait object](../book/trait-objects.html). -This manifests as either `Box` or `&Error`. Indeed, the `cause` method -returns an `&Error`, which is itself a trait object. We'll revisit the -`Error` trait's utility as a trait object later. - -For now, it suffices to show an example implementing the `Error` trait. Let's -use the error type we defined in the -[previous section](#defining-your-own-error-type): - -```rust -use std::io; -use std::num; - -// We derive `Debug` because all types should probably derive `Debug`. -// This gives us a reasonable human readable description of `CliError` values. -#[derive(Debug)] -enum CliError { - Io(io::Error), - Parse(num::ParseIntError), -} -``` - -This particular error type represents the possibility of two types of errors -occurring: an error dealing with I/O or an error converting a string to a -number. The error could represent as many error types as you want by adding new -variants to the `enum` definition. - -Implementing `Error` is pretty straight-forward. It's mostly going to be a lot -explicit case analysis. - -```rust,ignore -use std::error; -use std::fmt; - -impl fmt::Display for CliError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - // Both underlying errors already impl `Display`, so we defer to - // their implementations. - CliError::Io(ref err) => write!(f, "IO error: {}", err), - CliError::Parse(ref err) => write!(f, "Parse error: {}", err), - } - } -} - -impl error::Error for CliError { - fn description(&self) -> &str { - // Both underlying errors already impl `Error`, so we defer to their - // implementations. - match *self { - CliError::Io(ref err) => err.description(), - CliError::Parse(ref err) => err.description(), - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - // N.B. Both of these implicitly cast `err` from their concrete - // types (either `&io::Error` or `&num::ParseIntError`) - // to a trait object `&Error`. This works because both error types - // implement `Error`. - CliError::Io(ref err) => Some(err), - CliError::Parse(ref err) => Some(err), - } - } -} -``` - -We note that this is a very typical implementation of `Error`: match on your -different error types and satisfy the contracts defined for `description` and -`cause`. - -## The `From` trait - -The `std::convert::From` trait is -[defined in the standard -library](../std/convert/trait.From.html): - - - -```rust -trait From { - fn from(T) -> Self; -} -``` - -Deliciously simple, yes? `From` is very useful because it gives us a generic -way to talk about conversion *from* a particular type `T` to some other type -(in this case, “some other type” is the subject of the impl, or `Self`). -The crux of `From` is the -[set of implementations provided by the standard -library](../std/convert/trait.From.html). - -Here are a few simple examples demonstrating how `From` works: - -```rust -let string: String = From::from("foo"); -let bytes: Vec = From::from("foo"); -let cow: ::std::borrow::Cow = From::from("foo"); -``` - -OK, so `From` is useful for converting between strings. But what about errors? -It turns out, there is one critical impl: - -```rust,ignore -impl<'a, E: Error + 'a> From for Box -``` - -This impl says that for *any* type that impls `Error`, we can convert it to a -trait object `Box`. This may not seem terribly surprising, but it is -useful in a generic context. - -Remember the two errors we were dealing with previously? Specifically, -`io::Error` and `num::ParseIntError`. Since both impl `Error`, they work with -`From`: - -```rust -use std::error::Error; -use std::fs; -use std::io; -use std::num; - -// We have to jump through some hoops to actually get error values: -let io_err: io::Error = io::Error::last_os_error(); -let parse_err: num::ParseIntError = "not a number".parse::().unwrap_err(); - -// OK, here are the conversions: -let err1: Box = From::from(io_err); -let err2: Box = From::from(parse_err); -``` - -There is a really important pattern to recognize here. Both `err1` and `err2` -have the *same type*. This is because they are existentially quantified types, -or trait objects. In particular, their underlying type is *erased* from the -compiler's knowledge, so it truly sees `err1` and `err2` as exactly the same. -Additionally, we constructed `err1` and `err2` using precisely the same -function call: `From::from`. This is because `From::from` is overloaded on both -its argument and its return type. - -This pattern is important because it solves a problem we had earlier: it gives -us a way to reliably convert errors to the same type using the same function. - -Time to revisit an old friend; the `try!` macro. - -## The real `try!` macro - -Previously, we presented this definition of `try!`: - -```rust -macro_rules! try { - ($e:expr) => (match $e { - Ok(val) => val, - Err(err) => return Err(err), - }); -} -``` - -This is not its real definition. Its real definition is -[in the standard library](../std/macro.try.html): - - - -```rust -macro_rules! try { - ($e:expr) => (match $e { - Ok(val) => val, - Err(err) => return Err(::std::convert::From::from(err)), - }); -} -``` - -There's one tiny but powerful change: the error value is passed through -`From::from`. This makes the `try!` macro a lot more powerful because it gives -you automatic type conversion for free. - -Armed with our more powerful `try!` macro, let's take a look at code we wrote -previously to read a file and convert its contents to an integer: - -```rust -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result { - let mut file = try!(File::open(file_path).map_err(|e| e.to_string())); - let mut contents = String::new(); - try!(file.read_to_string(&mut contents).map_err(|e| e.to_string())); - let n = try!(contents.trim().parse::().map_err(|e| e.to_string())); - Ok(2 * n) -} -``` - -Earlier, we promised that we could get rid of the `map_err` calls. Indeed, all -we have to do is pick a type that `From` works with. As we saw in the previous -section, `From` has an impl that lets it convert any error type into a -`Box`: - -```rust -use std::error::Error; -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result> { - let mut file = try!(File::open(file_path)); - let mut contents = String::new(); - try!(file.read_to_string(&mut contents)); - let n = try!(contents.trim().parse::()); - Ok(2 * n) -} -``` - -We are getting very close to ideal error handling. Our code has very little -overhead as a result from error handling because the `try!` macro encapsulates -three things simultaneously: - -1. Case analysis. -2. Control flow. -3. Error type conversion. - -When all three things are combined, we get code that is unencumbered by -combinators, calls to `unwrap` or case analysis. - -There's one little nit left: the `Box` type is *opaque*. If we -return a `Box` to the caller, the caller can't (easily) inspect -underlying error type. The situation is certainly better than `String` -because the caller can call methods like -[`description`](../std/error/trait.Error.html#tymethod.description) -and [`cause`](../std/error/trait.Error.html#method.cause), but the -limitation remains: `Box` is opaque. (N.B. This isn't entirely -true because Rust does have runtime reflection, which is useful in -some scenarios that are [beyond the scope of this -section](https://crates.io/crates/error).) - -It's time to revisit our custom `CliError` type and tie everything together. - -## Composing custom error types - -In the last section, we looked at the real `try!` macro and how it does -automatic type conversion for us by calling `From::from` on the error value. -In particular, we converted errors to `Box`, which works, but the type -is opaque to callers. - -To fix this, we use the same remedy that we're already familiar with: a custom -error type. Once again, here is the code that reads the contents of a file and -converts it to an integer: - -```rust -use std::fs::File; -use std::io::{self, Read}; -use std::num; -use std::path::Path; - -// We derive `Debug` because all types should probably derive `Debug`. -// This gives us a reasonable human readable description of `CliError` values. -#[derive(Debug)] -enum CliError { - Io(io::Error), - Parse(num::ParseIntError), -} - -fn file_double_verbose>(file_path: P) -> Result { - let mut file = try!(File::open(file_path).map_err(CliError::Io)); - let mut contents = String::new(); - try!(file.read_to_string(&mut contents).map_err(CliError::Io)); - let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse)); - Ok(2 * n) -} -``` - -Notice that we still have the calls to `map_err`. Why? Well, recall the -definitions of [`try!`](#code-try-def) and [`From`](#code-from-def). The -problem is that there is no `From` impl that allows us to convert from error -types like `io::Error` and `num::ParseIntError` to our own custom `CliError`. -Of course, it is easy to fix this! Since we defined `CliError`, we can impl -`From` with it: - -```rust -# #[derive(Debug)] -# enum CliError { Io(io::Error), Parse(num::ParseIntError) } -use std::io; -use std::num; - -impl From for CliError { - fn from(err: io::Error) -> CliError { - CliError::Io(err) - } -} - -impl From for CliError { - fn from(err: num::ParseIntError) -> CliError { - CliError::Parse(err) - } -} -``` - -All these impls are doing is teaching `From` how to create a `CliError` from -other error types. In our case, construction is as simple as invoking the -corresponding value constructor. Indeed, it is *typically* this easy. - -We can finally rewrite `file_double`: - -```rust -# use std::io; -# use std::num; -# enum CliError { Io(::std::io::Error), Parse(::std::num::ParseIntError) } -# impl From for CliError { -# fn from(err: io::Error) -> CliError { CliError::Io(err) } -# } -# impl From for CliError { -# fn from(err: num::ParseIntError) -> CliError { CliError::Parse(err) } -# } - -use std::fs::File; -use std::io::Read; -use std::path::Path; - -fn file_double>(file_path: P) -> Result { - let mut file = try!(File::open(file_path)); - let mut contents = String::new(); - try!(file.read_to_string(&mut contents)); - let n: i32 = try!(contents.trim().parse()); - Ok(2 * n) -} -``` - -The only thing we did here was remove the calls to `map_err`. They are no -longer needed because the `try!` macro invokes `From::from` on the error value. -This works because we've provided `From` impls for all the error types that -could appear. - -If we modified our `file_double` function to perform some other operation, say, -convert a string to a float, then we'd need to add a new variant to our error -type: - -```rust -use std::io; -use std::num; - -enum CliError { - Io(io::Error), - ParseInt(num::ParseIntError), - ParseFloat(num::ParseFloatError), -} -``` - -And add a new `From` impl: - -```rust -# enum CliError { -# Io(::std::io::Error), -# ParseInt(num::ParseIntError), -# ParseFloat(num::ParseFloatError), -# } - -use std::num; - -impl From for CliError { - fn from(err: num::ParseFloatError) -> CliError { - CliError::ParseFloat(err) - } -} -``` - -And that's it! - -## Advice for library writers - -If your library needs to report custom errors, then you should -probably define your own error type. It's up to you whether or not to -expose its representation (like -[`ErrorKind`](../std/io/enum.ErrorKind.html)) or keep it hidden (like -[`ParseIntError`](../std/num/struct.ParseIntError.html)). Regardless -of how you do it, it's usually good practice to at least provide some -information about the error beyond its `String` -representation. But certainly, this will vary depending on use cases. - -At a minimum, you should probably implement the -[`Error`](../std/error/trait.Error.html) -trait. This will give users of your library some minimum flexibility for -[composing errors](#the-real-try-macro). Implementing the `Error` trait also -means that users are guaranteed the ability to obtain a string representation -of an error (because it requires impls for both `fmt::Debug` and -`fmt::Display`). - -Beyond that, it can also be useful to provide implementations of `From` on your -error types. This allows you (the library author) and your users to -[compose more detailed errors](#composing-custom-error-types). For example, -[`csv::Error`](http://burntsushi.net/rustdoc/csv/enum.Error.html) -provides `From` impls for both `io::Error` and `byteorder::Error`. - -Finally, depending on your tastes, you may also want to define a -[`Result` type alias](#the-result-type-alias-idiom), particularly if your -library defines a single error type. This is used in the standard library -for [`io::Result`](../std/io/type.Result.html) -and [`fmt::Result`](../std/fmt/type.Result.html). - -# Case study: A program to read population data - -This section was long, and depending on your background, it might be -rather dense. While there is plenty of example code to go along with -the prose, most of it was specifically designed to be pedagogical. So, -we're going to do something new: a case study. - -For this, we're going to build up a command line program that lets you -query world population data. The objective is simple: you give it a location -and it will tell you the population. Despite the simplicity, there is a lot -that can go wrong! - -The data we'll be using comes from the [Data Science -Toolkit][11]. I've prepared some data from it for this exercise. You -can either grab the [world population data][12] (41MB gzip compressed, -145MB uncompressed) or only the [US population data][13] (2.2MB gzip -compressed, 7.2MB uncompressed). - -Up until now, we've kept the code limited to Rust's standard library. For a real -task like this though, we'll want to at least use something to parse CSV data, -parse the program arguments and decode that stuff into Rust types automatically. For that, we'll use the -[`csv`](https://crates.io/crates/csv), -and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates. - -## Initial setup - -We're not going to spend a lot of time on setting up a project with -Cargo because it is already covered well in [the Cargo -section](getting-started.html#hello-cargo) and [Cargo's documentation][14]. - -To get started from scratch, run `cargo new --bin city-pop` and make sure your -`Cargo.toml` looks something like this: - -```text -[package] -name = "city-pop" -version = "0.1.0" -authors = ["Andrew Gallant "] - -[[bin]] -name = "city-pop" - -[dependencies] -csv = "0.*" -rustc-serialize = "0.*" -getopts = "0.*" -``` - -You should already be able to run: - -```text -cargo build --release -./target/release/city-pop -# Outputs: Hello, world! -``` - -## Argument parsing - -Let's get argument parsing out of the way. We won't go into too much -detail on Getopts, but there is [some good documentation][15] -describing it. The short story is that Getopts generates an argument -parser and a help message from a vector of options (The fact that it -is a vector is hidden behind a struct and a set of methods). Once the -parsing is done, the parser returns a struct that records matches -for defined options, and remaining "free" arguments. -From there, we can get information about the flags, for -instance, whether they were passed in, and what arguments they -had. Here's our program with the appropriate `extern crate` -statements, and the basic argument setup for Getopts: - -```rust,ignore -extern crate getopts; -extern crate rustc_serialize; - -use getopts::Options; -use std::env; - -fn print_usage(program: &str, opts: Options) { - println!("{}", opts.usage(&format!("Usage: {} [options] ", program))); -} - -fn main() { - let args: Vec = env::args().collect(); - let program = &args[0]; - - let mut opts = Options::new(); - opts.optflag("h", "help", "Show this usage message."); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => { m } - Err(e) => { panic!(e.to_string()) } - }; - if matches.opt_present("h") { - print_usage(&program, opts); - return; - } - let data_path = &matches.free[0]; - let city: &str = &matches.free[1]; - - // Do stuff with information. -} -``` - -First, we get a vector of the arguments passed into our program. We -then store the first one, knowing that it is our program's name. Once -that's done, we set up our argument flags, in this case a simplistic -help message flag. Once we have the argument flags set up, we use -`Options.parse` to parse the argument vector (starting from index one, -because index 0 is the program name). If this was successful, we -assign matches to the parsed object, if not, we panic. Once past that, -we test if the user passed in the help flag, and if so print the usage -message. The option help messages are constructed by Getopts, so all -we have to do to print the usage message is tell it what we want it to -print for the program name and template. If the user has not passed in -the help flag, we assign the proper variables to their corresponding -arguments. - -## Writing the logic - -We all write code differently, but error handling is usually the last thing we -want to think about. This isn't great for the overall design of a program, but -it can be useful for rapid prototyping. Because Rust forces us to be explicit -about error handling (by making us call `unwrap`), it is easy to see which -parts of our program can cause errors. - -In this case study, the logic is really simple. All we need to do is parse the -CSV data given to us and print out a field in matching rows. Let's do it. (Make -sure to add `extern crate csv;` to the top of your file.) - -```rust,ignore -use std::fs::File; - -// This struct represents the data in each row of the CSV file. -// Type based decoding absolves us of a lot of the nitty gritty error -// handling, like parsing strings as integers or floats. -#[derive(Debug, RustcDecodable)] -struct Row { - country: String, - city: String, - accent_city: String, - region: String, - - // Not every row has data for the population, latitude or longitude! - // So we express them as `Option` types, which admits the possibility of - // absence. The CSV parser will fill in the correct value for us. - population: Option, - latitude: Option, - longitude: Option, -} - -fn print_usage(program: &str, opts: Options) { - println!("{}", opts.usage(&format!("Usage: {} [options] ", program))); -} - -fn main() { - let args: Vec = env::args().collect(); - let program = &args[0]; - - let mut opts = Options::new(); - opts.optflag("h", "help", "Show this usage message."); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => { m } - Err(e) => { panic!(e.to_string()) } - }; - - if matches.opt_present("h") { - print_usage(&program, opts); - return; - } - - let data_path = &matches.free[0]; - let city: &str = &matches.free[1]; - - let file = File::open(data_path).unwrap(); - let mut rdr = csv::Reader::from_reader(file); - - for row in rdr.decode::() { - let row = row.unwrap(); - - if row.city == city { - println!("{}, {}: {:?}", - row.city, row.country, - row.population.expect("population count")); - } - } -} -``` - -Let's outline the errors. We can start with the obvious: the three places that -`unwrap` is called: - -1. [`File::open`](../std/fs/struct.File.html#method.open) - can return an - [`io::Error`](../std/io/struct.Error.html). -2. [`csv::Reader::decode`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.decode) - decodes one record at a time, and - [decoding a - record](http://burntsushi.net/rustdoc/csv/struct.DecodedRecords.html) - (look at the `Item` associated type on the `Iterator` impl) - can produce a - [`csv::Error`](http://burntsushi.net/rustdoc/csv/enum.Error.html). -3. If `row.population` is `None`, then calling `expect` will panic. - -Are there any others? What if we can't find a matching city? Tools like `grep` -will return an error code, so we probably should too. So we have logic errors -specific to our problem, IO errors and CSV parsing errors. We're going to -explore two different ways to approach handling these errors. - -I'd like to start with `Box`. Later, we'll see how defining our own -error type can be useful. - -## Error handling with `Box` - -`Box` is nice because it *just works*. You don't need to define your own -error types and you don't need any `From` implementations. The downside is that -since `Box` is a trait object, it *erases the type*, which means the -compiler can no longer reason about its underlying type. - -[Previously](#the-limits-of-combinators) we started refactoring our code by -changing the type of our function from `T` to `Result`. In -this case, `OurErrorType` is only `Box`. But what's `T`? And can we add -a return type to `main`? - -The answer to the second question is no, we can't. That means we'll need to -write a new function. But what is `T`? The simplest thing we can do is to -return a list of matching `Row` values as a `Vec`. (Better code would -return an iterator, but that is left as an exercise to the reader.) - -Let's refactor our code into its own function, but keep the calls to `unwrap`. -Note that we opt to handle the possibility of a missing population count by -simply ignoring that row. - -```rust,ignore -use std::path::Path; - -struct Row { - // This struct remains unchanged. -} - -struct PopulationCount { - city: String, - country: String, - // This is no longer an `Option` because values of this type are only - // constructed if they have a population count. - count: u64, -} - -fn print_usage(program: &str, opts: Options) { - println!("{}", opts.usage(&format!("Usage: {} [options] ", program))); -} - -fn search>(file_path: P, city: &str) -> Vec { - let mut found = vec![]; - let file = File::open(file_path).unwrap(); - let mut rdr = csv::Reader::from_reader(file); - for row in rdr.decode::() { - let row = row.unwrap(); - match row.population { - None => { } // Skip it. - Some(count) => if row.city == city { - found.push(PopulationCount { - city: row.city, - country: row.country, - count: count, - }); - }, - } - } - found -} - -fn main() { - let args: Vec = env::args().collect(); - let program = &args[0]; - - let mut opts = Options::new(); - opts.optflag("h", "help", "Show this usage message."); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => { m } - Err(e) => { panic!(e.to_string()) } - }; - - if matches.opt_present("h") { - print_usage(&program, opts); - return; - } - - let data_path = &matches.free[0]; - let city: &str = &matches.free[1]; - - for pop in search(data_path, city) { - println!("{}, {}: {:?}", pop.city, pop.country, pop.count); - } -} - -``` - -While we got rid of one use of `expect` (which is a nicer variant of `unwrap`), -we still should handle the absence of any search results. - -To convert this to proper error handling, we need to do the following: - -1. Change the return type of `search` to be `Result, - Box>`. -2. Use the [`try!` macro](#code-try-def) so that errors are returned to the - caller instead of panicking the program. -3. Handle the error in `main`. - -Let's try it: - -```rust,ignore -use std::error::Error; - -// The rest of the code before this is unchanged. - -fn search> - (file_path: P, city: &str) - -> Result, Box> { - let mut found = vec![]; - let file = try!(File::open(file_path)); - let mut rdr = csv::Reader::from_reader(file); - for row in rdr.decode::() { - let row = try!(row); - match row.population { - None => { } // Skip it. - Some(count) => if row.city == city { - found.push(PopulationCount { - city: row.city, - country: row.country, - count: count, - }); - }, - } - } - if found.is_empty() { - Err(From::from("No matching cities with a population were found.")) - } else { - Ok(found) - } -} -``` - -Instead of `x.unwrap()`, we now have `try!(x)`. Since our function returns a -`Result`, the `try!` macro will return early from the function if an -error occurs. - -At the end of `search` we also convert a plain string to an error type -by using the [corresponding `From` impls](../std/convert/trait.From.html): - -```rust,ignore -// We are making use of this impl in the code above, since we call `From::from` -// on a `&'static str`. -impl<'a> From<&'a str> for Box - -// But this is also useful when you need to allocate a new string for an -// error message, usually with `format!`. -impl From for Box -``` - -Since `search` now returns a `Result`, `main` should use case analysis -when calling `search`: - -```rust,ignore -... - match search(data_path, city) { - Ok(pops) => { - for pop in pops { - println!("{}, {}: {:?}", pop.city, pop.country, pop.count); - } - } - Err(err) => println!("{}", err) - } -... -``` - -Now that we've seen how to do proper error handling with `Box`, let's -try a different approach with our own custom error type. But first, let's take -a quick break from error handling and add support for reading from `stdin`. - -## Reading from stdin - -In our program, we accept a single file for input and do one pass over the -data. This means we probably should be able to accept input on stdin. But maybe -we like the current format too—so let's have both! - -Adding support for stdin is actually quite easy. There are only three things we -have to do: - -1. Tweak the program arguments so that a single parameter—the - city—can be accepted while the population data is read from stdin. -2. Modify the program so that an option `-f` can take the file, if it - is not passed into stdin. -3. Modify the `search` function to take an *optional* file path. When `None`, - it should know to read from stdin. - -First, here's the new usage: - -```rust,ignore -fn print_usage(program: &str, opts: Options) { - println!("{}", opts.usage(&format!("Usage: {} [options] ", program))); -} -``` -Of course we need to adapt the argument handling code: - -```rust,ignore -... - let mut opts = Options::new(); - opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME"); - opts.optflag("h", "help", "Show this usage message."); - ... - let data_path = matches.opt_str("f"); - - let city = if !matches.free.is_empty() { - &matches.free[0] - } else { - print_usage(&program, opts); - return; - }; - - match search(&data_path, city) { - Ok(pops) => { - for pop in pops { - println!("{}, {}: {:?}", pop.city, pop.country, pop.count); - } - } - Err(err) => println!("{}", err) - } -... -``` - -We've made the user experience a bit nicer by showing the usage message, -instead of a panic from an out-of-bounds index, when `city`, the -remaining free argument, is not present. - -Modifying `search` is slightly trickier. The `csv` crate can build a -parser out of -[any type that implements `io::Read`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.from_reader). -But how can we use the same code over both types? There's actually a -couple ways we could go about this. One way is to write `search` such -that it is generic on some type parameter `R` that satisfies -`io::Read`. Another way is to use trait objects: - -```rust,ignore -use std::io; - -// The rest of the code before this is unchanged. - -fn search> - (file_path: &Option

, city: &str) - -> Result, Box> { - let mut found = vec![]; - let input: Box = match *file_path { - None => Box::new(io::stdin()), - Some(ref file_path) => Box::new(try!(File::open(file_path))), - }; - let mut rdr = csv::Reader::from_reader(input); - // The rest remains unchanged! -} -``` - -## Error handling with a custom type - -Previously, we learned how to -[compose errors using a custom error type](#composing-custom-error-types). -We did this by defining our error type as an `enum` and implementing `Error` -and `From`. - -Since we have three distinct errors (IO, CSV parsing and not found), let's -define an `enum` with three variants: - -```rust,ignore -#[derive(Debug)] -enum CliError { - Io(io::Error), - Csv(csv::Error), - NotFound, -} -``` - -And now for impls on `Display` and `Error`: - -```rust,ignore -use std::fmt; - -impl fmt::Display for CliError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CliError::Io(ref err) => err.fmt(f), - CliError::Csv(ref err) => err.fmt(f), - CliError::NotFound => write!(f, "No matching cities with a \ - population were found."), - } - } -} - -impl Error for CliError { - fn description(&self) -> &str { - match *self { - CliError::Io(ref err) => err.description(), - CliError::Csv(ref err) => err.description(), - CliError::NotFound => "not found", - } - } - - fn cause(&self) -> Option<&Error> { - match *self { - CliError::Io(ref err) => Some(err), - CliError::Csv(ref err) => Some(err), - // Our custom error doesn't have an underlying cause, - // but we could modify it so that it does. - CliError::NotFound => None, - } - } -} -``` - -Before we can use our `CliError` type in our `search` function, we need to -provide a couple `From` impls. How do we know which impls to provide? Well, -we'll need to convert from both `io::Error` and `csv::Error` to `CliError`. -Those are the only external errors, so we'll only need two `From` impls for -now: - -```rust,ignore -impl From for CliError { - fn from(err: io::Error) -> CliError { - CliError::Io(err) - } -} - -impl From for CliError { - fn from(err: csv::Error) -> CliError { - CliError::Csv(err) - } -} -``` - -The `From` impls are important because of how -[`try!` is defined](#code-try-def). In particular, if an error occurs, -`From::from` is called on the error, which in this case, will convert it to our -own error type `CliError`. - -With the `From` impls done, we only need to make two small tweaks to our -`search` function: the return type and the “not found” error. Here it is in -full: - -```rust,ignore -fn search> - (file_path: &Option

, city: &str) - -> Result, CliError> { - let mut found = vec![]; - let input: Box = match *file_path { - None => Box::new(io::stdin()), - Some(ref file_path) => Box::new(try!(File::open(file_path))), - }; - let mut rdr = csv::Reader::from_reader(input); - for row in rdr.decode::() { - let row = try!(row); - match row.population { - None => { } // Skip it. - Some(count) => if row.city == city { - found.push(PopulationCount { - city: row.city, - country: row.country, - count: count, - }); - }, - } - } - if found.is_empty() { - Err(CliError::NotFound) - } else { - Ok(found) - } -} -``` - -No other changes are necessary. - -## Adding functionality - -Writing generic code is great, because generalizing stuff is cool, and -it can then be useful later. But sometimes, the juice isn't worth the -squeeze. Look at what we just did in the previous step: - -1. Defined a new error type. -2. Added impls for `Error`, `Display` and two for `From`. - -The big downside here is that our program didn't improve a whole lot. -There is quite a bit of overhead to representing errors with `enum`s, -especially in short programs like this. - -*One* useful aspect of using a custom error type like we've done here is that -the `main` function can now choose to handle errors differently. Previously, -with `Box`, it didn't have much of a choice: just print the message. -We're still doing that here, but what if we wanted to, say, add a `--quiet` -flag? The `--quiet` flag should silence any verbose output. - -Right now, if the program doesn't find a match, it will output a message saying -so. This can be a little clumsy, especially if you intend for the program to -be used in shell scripts. - -So let's start by adding the flags. Like before, we need to tweak the usage -string and add a flag to the Option variable. Once we've done that, Getopts does the rest: - -```rust,ignore -... - let mut opts = Options::new(); - opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME"); - opts.optflag("h", "help", "Show this usage message."); - opts.optflag("q", "quiet", "Silences errors and warnings."); -... -``` - -Now we only need to implement our “quiet” functionality. This requires us to -tweak the case analysis in `main`: - -```rust,ignore -use std::process; -... - match search(&data_path, city) { - Err(CliError::NotFound) if matches.opt_present("q") => process::exit(1), - Err(err) => panic!("{}", err), - Ok(pops) => for pop in pops { - println!("{}, {}: {:?}", pop.city, pop.country, pop.count); - } - } -... -``` - -Certainly, we don't want to be quiet if there was an IO error or if the data -failed to parse. Therefore, we use case analysis to check if the error type is -`NotFound` *and* if `--quiet` has been enabled. If the search failed, we still -quit with an exit code (following `grep`'s convention). - -If we had stuck with `Box`, then it would be pretty tricky to implement -the `--quiet` functionality. - -This pretty much sums up our case study. From here, you should be ready to go -out into the world and write your own programs and libraries with proper error -handling. - -# The Short Story - -Since this section is long, it is useful to have a quick summary for error -handling in Rust. These are some good “rules of thumb." They are emphatically -*not* commandments. There are probably good reasons to break every one of these -heuristics! - -* If you're writing short example code that would be overburdened by error - handling, it's probably fine to use `unwrap` (whether that's - [`Result::unwrap`](../std/result/enum.Result.html#method.unwrap), - [`Option::unwrap`](../std/option/enum.Option.html#method.unwrap) - or preferably - [`Option::expect`](../std/option/enum.Option.html#method.expect)). - Consumers of your code should know to use proper error handling. (If they - don't, send them here!) -* If you're writing a quick 'n' dirty program, don't feel ashamed if you use - `unwrap`. Be warned: if it winds up in someone else's hands, don't be - surprised if they are agitated by poor error messages! -* If you're writing a quick 'n' dirty program and feel ashamed about panicking - anyway, then use either a `String` or a `Box` for your - error type. -* Otherwise, in a program, define your own error types with appropriate - [`From`](../std/convert/trait.From.html) - and - [`Error`](../std/error/trait.Error.html) - impls to make the [`try!`](../std/macro.try.html) - macro more ergonomic. -* If you're writing a library and your code can produce errors, define your own - error type and implement the - [`std::error::Error`](../std/error/trait.Error.html) - trait. Where appropriate, implement - [`From`](../std/convert/trait.From.html) to make both - your library code and the caller's code easier to write. (Because of Rust's - coherence rules, callers will not be able to impl `From` on your error type, - so your library should do it.) -* Learn the combinators defined on - [`Option`](../std/option/enum.Option.html) - and - [`Result`](../std/result/enum.Result.html). - Using them exclusively can be a bit tiring at times, but I've personally - found a healthy mix of `try!` and combinators to be quite appealing. - `and_then`, `map` and `unwrap_or` are my favorites. - -[1]: ../book/patterns.html -[2]: ../std/option/enum.Option.html#method.map -[3]: ../std/option/enum.Option.html#method.unwrap_or -[4]: ../std/option/enum.Option.html#method.unwrap_or_else -[5]: ../std/option/enum.Option.html -[6]: ../std/result/index.html -[7]: ../std/result/enum.Result.html#method.unwrap -[8]: ../std/fmt/trait.Debug.html -[9]: ../std/primitive.str.html#method.parse -[10]: ../book/associated-types.html -[11]: https://github.com/petewarden/dstkdata -[12]: http://burntsushi.net/stuff/worldcitiespop.csv.gz -[13]: http://burntsushi.net/stuff/uscitiespop.csv.gz -[14]: http://doc.crates.io/guide.html -[15]: http://doc.rust-lang.org/getopts/getopts/index.html diff --git a/src/doc/book/src/ffi.md b/src/doc/book/src/ffi.md deleted file mode 100644 index 3dd9aa3885bc0..0000000000000 --- a/src/doc/book/src/ffi.md +++ /dev/null @@ -1,767 +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)). - -## A note about libc - -Many of these examples use [the `libc` crate][libc], which provides various -type definitions for C types, among other things. If you’re trying these -examples yourself, you’ll need to add `libc` to your `Cargo.toml`: - -```toml -[dependencies] -libc = "0.2.0" -``` - -[libc]: https://crates.io/crates/libc - -and add `extern crate libc;` to your crate root. - -## Calling foreign functions - -The following is a minimal example of calling a foreign function which will -compile if snappy is installed: - -```rust,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 -cannot 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: - -```rust,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 the 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. - -```rust -# #![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. - -```rust -# #![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. - -```rust -# #![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 - } - } -} -``` - -Then, we can add some tests to show how to use them. - -```rust -# #![feature(libc)] -# extern crate libc; -# use libc::{c_int, size_t}; -# unsafe fn snappy_compress(input: *const u8, -# input_length: size_t, -# compressed: *mut u8, -# compressed_length: *mut size_t) -# -> c_int { 0 } -# 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_max_compressed_length(source_length: size_t) -> size_t { 0 } -# unsafe fn snappy_uncompressed_length(compressed: *const u8, -# compressed_length: size_t, -# result: *mut size_t) -# -> c_int { 0 } -# unsafe fn snappy_validate_compressed_buffer(compressed: *const u8, -# compressed_length: size_t) -# -> c_int { 0 } -# fn main() { } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn valid() { - let d = vec![0xde, 0xad, 0xd0, 0x0d]; - let c: &[u8] = &compress(&d); - assert!(validate_compressed_buffer(c)); - assert!(uncompress(c) == Some(d)); - } - - #[test] - fn invalid() { - let d = vec![0, 0, 0, 0]; - assert!(!validate_compressed_buffer(&d)); - assert!(uncompress(&d).is_none()); - } - - #[test] - fn empty() { - let d = vec![]; - assert!(!validate_compressed_buffer(&d)); - assert!(uncompress(&d).is_none()); - let c = compress(&d); - assert!(validate_compressed_buffer(&c)); - assert!(uncompress(&c) == Some(d)); - } -} -``` - -# 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: - -```rust,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 a raw 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: - -```rust,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::sync::mpsc`) 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 macOS 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 library and framework dependencies are propagated to the final -artifact boundary, while static library dependencies are not propagated at -all, because the static libraries are integrated directly into the subsequent -artifact. - -A few examples of how this model can be used are: - -* A native build dependency. Sometimes some C/C++ glue is needed when writing - some Rust code, but distribution of the C/C++ code in a library format is - 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 macOS, frameworks behave with the same semantics as a dynamic library. - -# Unsafe blocks - -Some operations, like dereferencing raw 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: - -```rust -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: - -```rust,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.", - unsafe { 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. - -```rust,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: - -```rust -# #![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` -* `vectorcall` -This is currently hidden behind the `abi_vectorcall` gate and is subject to change. -* `Rust` -* `rust-intrinsic` -* `system` -* `C` -* `win64` -* `sysv64` - -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 only 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 [`libc` crate on crates.io][libc] includes type aliases and function -definitions for the C standard library in the `libc` module, and Rust links -against `libc` and `libm` by default. - -# Variadic functions - -In C, functions can be 'variadic', meaning they accept a variable number of arguments. This can -be achieved in Rust by specifying `...` within the argument list of a foreign function declaration: - -```no_run -extern { - fn foo(x: i32, ...); -} - -fn main() { - unsafe { - foo(10, 20, 30, 40, 50); - } -} -``` - -Normal Rust functions can *not* be variadic: - -```ignore -// This will not compile - -fn foo(x: i32, ...) { } -``` - -# The "nullable pointer optimization" - -Certain Rust types are defined to never 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, which would seem to -require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types. -However, the language provides a workaround. - -As a special case, an `enum` is eligible for the "nullable pointer optimization" if it contains -exactly two variants, one of which contains no data and the other contains a field of one of the -non-nullable types listed above. This means no extra space is required for a discriminant; rather, -the empty variant is represented by putting a `null` value into the non-nullable field. This is -called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible -types. - -The most common type that takes advantage of the nullable pointer optimization is `Option`, -where `None` corresponds to `null`. So `Option c_int>` is a correct way -to represent a nullable function pointer using the C ABI (corresponding to the C type -`int (*)(int)`). - -Here is a contrived example. Let's say some C library has a facility for registering a -callback, which gets called in certain situations. The callback is passed a function pointer -and an integer and it is supposed to run the function with the integer as a parameter. So -we have function pointers flying across the FFI boundary in both directions. - -```rust -# #![feature(libc)] -extern crate libc; -use libc::c_int; - -# #[cfg(hidden)] -extern "C" { - /// Registers the callback. - fn register(cb: Option c_int>, c_int) -> c_int>); -} -# unsafe fn register(_: Option c_int>, -# c_int) -> c_int>) -# {} - -/// This fairly useless function receives a function pointer and an integer -/// from C, and returns the result of calling the function with the integer. -/// In case no function is provided, it squares the integer by default. -extern "C" fn apply(process: Option c_int>, int: c_int) -> c_int { - match process { - Some(f) => f(int), - None => int * int - } -} - -fn main() { - unsafe { - register(Some(apply)); - } -} -``` - -And the code on the C side looks like this: - -```c -void register(void (*f)(void (*)(int), int)) { - ... -} -``` - -No `transmute` required! - -# 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: - -```rust -#[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. - -# FFI and panics - -It’s important to be mindful of `panic!`s when working with FFI. A `panic!` -across an FFI boundary is undefined behavior. If you’re writing code that may -panic, you should run it in a closure with [`catch_unwind`]: - -```rust -use std::panic::catch_unwind; - -#[no_mangle] -pub extern fn oh_no() -> i32 { - let result = catch_unwind(|| { - panic!("Oops!"); - }); - match result { - Ok(_) => 0, - Err(_) => 1, - } -} - -fn main() {} -``` - -Please note that [`catch_unwind`] will only catch unwinding panics, not -those who abort the process. See the documentation of [`catch_unwind`] -for more information. - -[`catch_unwind`]: ../std/panic/fn.catch_unwind.html - -# Representing opaque structs - -Sometimes, a C library wants to provide a pointer to something, but not let you -know the internal details of the thing it wants. The simplest way is to use a -`void *` argument: - -```c -void foo(void *arg); -void bar(void *arg); -``` - -We can represent this in Rust with the `c_void` type: - -```rust -# #![feature(libc)] -extern crate libc; - -extern "C" { - pub fn foo(arg: *mut libc::c_void); - pub fn bar(arg: *mut libc::c_void); -} -# fn main() {} -``` - -This is a perfectly valid way of handling the situation. However, we can do a bit -better. To solve this, some C libraries will instead create a `struct`, where -the details and memory layout of the struct are private. This gives some amount -of type safety. These structures are called ‘opaque’. Here’s an example, in C: - -```c -struct Foo; /* Foo is a structure, but its contents are not part of the public interface */ -struct Bar; -void foo(struct Foo *arg); -void bar(struct Bar *arg); -``` - -To do this in Rust, let’s create our own opaque types with `enum`: - -```rust -pub enum Foo {} -pub enum Bar {} - -extern "C" { - pub fn foo(arg: *mut Foo); - pub fn bar(arg: *mut Bar); -} -# fn main() {} -``` - -By using an `enum` with no variants, we create an opaque type that we can’t -instantiate, as it has no variants. But because our `Foo` and `Bar` types are -different, we’ll get type safety between the two of them, so we cannot -accidentally pass a pointer to `Foo` to `bar()`. diff --git a/src/doc/book/src/functions.md b/src/doc/book/src/functions.md deleted file mode 100644 index 96c8e9f5d6834..0000000000000 --- a/src/doc/book/src/functions.md +++ /dev/null @@ -1,336 +0,0 @@ -# Functions - -Every Rust program has at least one function, 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 -expected one of `!`, `:`, or `@`, found `)` -fn print_sum(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 (`>`). The last -line of a function determines what it returns. 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; - ^ -``` - -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. -That’s why we end up with ‘not all control paths return a value’ here: the -statement `x + 1;` doesn’t return a value. There are two kinds of statements in -Rust: ‘declaration statements’ and ‘expression statements’. Everything else is -an expression. Let’s talk about declaration statements first. - -In some languages, variable bindings can be written as expressions, not -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: - -```rust,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 other -languages where an assignment evaluates to the assigned value (e.g. `5` in the -previous example), in Rust the value of an assignment is an empty tuple `()` -because the assigned value can have [only one owner](ownership.html), and any -other returned value would be too surprising: - -```rust -let mut y = 5; - -let x = (y = 6); // `x` has the value `()`, not `6`. -``` - -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 -fn add_one(x: i32) -> i32 { - x + 1 -} -``` - -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 in the error we saw before. - -## Early returns - -But what about early returns? Rust does have a keyword for that, `return`: - -```rust -fn foo(x: i32) -> i32 { - return x; - - // We never run this code! - x + 1 -} -``` - -Using a `return` as the last line of a function works, but is considered poor -style: - -```rust -fn foo(x: i32) -> i32 { - 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. - -## Diverging functions - -Rust has some special syntax for ‘diverging functions’, which are functions that -do not return: - -```rust -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’. - -If you add a main function that calls `diverges()` and run it, you’ll get -some output that looks like this: - -```text -thread ‘main’ panicked at ‘This function never returns!’, hello.rs:2 -``` - -If you want more information, you can get a backtrace by setting the -`RUST_BACKTRACE` environment variable: - -```text -$ RUST_BACKTRACE=1 ./diverges -thread 'main' panicked at 'This function never returns!', hello.rs:2 -Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. -stack backtrace: - hello::diverges - at ./hello.rs:2 - hello::main - at ./hello.rs:6 -``` - -If you want the complete backtrace and filenames: - -```text -$ RUST_BACKTRACE=full ./diverges -thread 'main' panicked at 'This function never returns!', hello.rs:2 -stack backtrace: - 1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r - 2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w - 3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw - 4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650 - 5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa - 6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa - 7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231 - 8: 0x7f402773d1d8 - __rust_try - 9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w - 10: 0x7f4027738a19 - main - 11: 0x7f402694ab44 - __libc_start_main - 12: 0x7f40277386c8 - - 13: 0x0 - -``` - -If you need to override an already set `RUST_BACKTRACE`, -in cases when you cannot just unset the variable, -then set it to `0` to avoid getting a backtrace. -Any other value (even no value at all) turns on backtrace. - -```text -$ export RUST_BACKTRACE=1 -... -$ RUST_BACKTRACE=0 ./diverges -thread 'main' panicked at 'This function never returns!', hello.rs:2 -note: Run with `RUST_BACKTRACE=1` for a backtrace. -``` - -`RUST_BACKTRACE` also works with Cargo’s `run` command: - -```text -$ RUST_BACKTRACE=full cargo run - Running `target/debug/diverges` -thread 'main' panicked at 'This function never returns!', hello.rs:2 -stack backtrace: - 1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r - 2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w - 3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw - 4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650 - 5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa - 6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa - 7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231 - 8: 0x7f402773d1d8 - __rust_try - 9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w - 10: 0x7f4027738a19 - main - 11: 0x7f402694ab44 - __libc_start_main - 12: 0x7f40277386c8 - - 13: 0x0 - -``` - -A diverging function can be used as any type: - -```rust,should_panic -# fn diverges() -> ! { -# panic!("This function never returns!"); -# } -let x: i32 = diverges(); -let x: String = diverges(); -``` - -## Function pointers - -We can also create variable bindings which point to functions: - -```rust -let f: fn(i32) -> i32; -``` - -`f` is a variable binding which points to a function that takes an `i32` as -an argument and returns an `i32`. For example: - -```rust -fn plus_one(i: i32) -> i32 { - i + 1 -} - -// Without type inference: -let f: fn(i32) -> i32 = plus_one; - -// With type inference: -let f = plus_one; -``` - -We can then use `f` to call the function: - -```rust -# fn plus_one(i: i32) -> i32 { i + 1 } -# let f = plus_one; -let six = f(5); -``` diff --git a/src/doc/book/src/generics.md b/src/doc/book/src/generics.md deleted file mode 100644 index d02cd776d00e3..0000000000000 --- a/src/doc/book/src/generics.md +++ /dev/null @@ -1,190 +0,0 @@ -# Generics - -Sometimes, when writing a function or data type, we may want it to work for -multiple types of arguments. In Rust, we can do this with 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 type theory, let’s check out some generic code. Rust’s -standard library provides a type, `Option`, that’s generic: - -```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 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 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 another type from Rust’s standard library that’s similar, `Result`: - -```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. - -## Generic functions - -We can write functions that take generic types with a similar syntax: - -```rust -fn takes_anything(x: T) { - // Do something with `x`. -} -``` - -The syntax has two parts: the `` says “this function is generic over one -type, `T`”, and the `x: T` says “x has the type `T`.” - -Multiple arguments can have the same generic type: - -```rust -fn takes_two_of_the_same_things(x: T, y: T) { - // ... -} -``` - -We could write a version that takes multiple types: - -```rust -fn takes_two_things(x: T, y: U) { - // ... -} -``` - -## Generic structs - -You can store a generic type in a `struct` as well: - -```rust -struct Point { - x: T, - y: T, -} - -let int_origin = Point { x: 0, y: 0 }; -let float_origin = Point { x: 0.0, y: 0.0 }; -``` - -Similar to functions, the `` is where we declare the generic parameters, -and we then use `x: T` in the type declaration, too. - -When you want to add an implementation for the generic `struct`, you -declare the type parameter after the `impl`: - -```rust -# struct Point { -# x: T, -# y: T, -# } -# -impl Point { - fn swap(&mut self) { - std::mem::swap(&mut self.x, &mut self.y); - } -} -``` - -So far you’ve seen generics that take absolutely any type. These are useful in -many cases: you’ve already seen `Option`, and later you’ll meet universal -container types like [`Vec`][Vec]. On the other hand, often you want to -trade that flexibility for increased expressive power. Read about [trait -bounds][traits] to see why and how. - -## Resolving ambiguities - -Most of the time when generics are involved, the compiler can infer the -generic parameters automatically: - -```rust -// v must be a Vec but we don't know what T is yet -let mut v = Vec::new(); -// v just got a bool value, so T must be bool! -v.push(true); -// Debug-print v -println!("{:?}", v); -``` - -Sometimes though, the compiler needs a little help. For example, had we -omitted the last line, we would get a compile error: - -```rust,ignore -let v = Vec::new(); -// ^^^^^^^^ cannot infer type for `T` -// -// note: type annotations or generic parameter binding required -println!("{:?}", v); -``` - -We can solve this using either a type annotation: - -```rust -let v: Vec = Vec::new(); -println!("{:?}", v); -``` - -or by binding the generic parameter `T` via the so-called -[‘turbofish’][turbofish] `::<>` syntax: - -```rust -let v = Vec::::new(); -println!("{:?}", v); -``` - -The second approach is useful in situations where we don’t want to bind the -result to a variable. It can also be used to bind generic parameters in -functions or methods. See [Iterators § Consumers](iterators.html#consumers) -for an example. - -[traits]: traits.html -[Vec]: ../std/vec/struct.Vec.html -[turbofish]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect diff --git a/src/doc/book/src/getting-started.md b/src/doc/book/src/getting-started.md deleted file mode 100644 index 06ea24fef3c1d..0000000000000 --- a/src/doc/book/src/getting-started.md +++ /dev/null @@ -1,550 +0,0 @@ -# Getting Started - -This first chapter of the book will get us going with Rust and its tooling. -First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally, -we’ll talk about Cargo, Rust’s build system and package manager. - -We’ll be showing off a number of commands using a terminal, and those lines all -start with `$`. You don't need to type in the `$`s, they are there to indicate -the start of each command. We’ll see many tutorials and examples around the web -that follow this convention: `$` for commands run as our regular user, and `#` -for commands we should be running as an administrator. - -# Installing Rust - -The first step to using Rust is to install it. Generally speaking, you’ll need -an Internet connection to run the commands in this section, as we’ll be -downloading Rust from the Internet. - -The Rust compiler runs on, and compiles to, a great number of platforms, but is -best supported on Linux, Mac, and Windows, on the x86 and x86-64 CPU -architecture. There are official builds of the Rust compiler and standard -library for these platforms and more. [For full details on Rust platform support -see the website][platform-support]. - -[platform-support]: https://forge.rust-lang.org/platform-support.html - -## Installing Rust - -All you need to do on Unix systems like Linux and macOS is open a -terminal and type this: - -```bash -$ curl https://sh.rustup.rs -sSf | sh -``` - -It will download a script, and start the installation. If everything -goes well, you’ll see this appear: - -```text -Rust is installed now. Great! -``` - -Installing on Windows is nearly as easy: download and run -[rustup-init.exe]. It will start the installation in a console and -present the above message on success. - -For other installation options and information, visit the [install] -page of the Rust website. - -[rustup-init.exe]: https://win.rustup.rs -[install]: https://www.rust-lang.org/install.html - -## Uninstalling - -Uninstalling Rust is as easy as installing it: - -```bash -$ rustup self uninstall -``` - -## Troubleshooting - -If we've got Rust installed, we can open up a shell, and type this: - -```bash -$ rustc --version -``` - -You should see the version number, commit hash, and commit date. - -If you do, Rust has been installed successfully! Congrats! - -If you don't, that probably means that the `PATH` environment variable -doesn't include Cargo's binary directory, `~/.cargo/bin` on Unix, or -`%USERPROFILE%\.cargo\bin` on Windows. This is the directory where -Rust development tools live, and most Rust developers keep it in their -`PATH` environment variable, which makes it possible to run `rustc` on -the command line. Due to differences in operating systems, command -shells, and bugs in installation, you may need to restart your shell, -log out of the system, or configure `PATH` manually as appropriate for -your operating environment. - -Rust does not do its own linking, and so you’ll need to have a linker -installed. Doing so will depend on your specific system. For -Linux-based systems, Rust will attempt to call `cc` for linking. On -`windows-msvc` (Rust built on Windows with Microsoft Visual Studio), -this depends on having [Microsoft Visual C++ Build Tools][msvbt] -installed. These do not need to be in `%PATH%` as `rustc` will find -them automatically. In general, if you have your linker in a -non-traditional location you can call `rustc -linker=/path/to/cc`, where `/path/to/cc` should point to your linker path. - -[msvbt]: http://landinghub.visualstudio.com/visual-cpp-build-tools - -If you are still stuck, there are a number of places where we can get -help. The easiest is -[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] -and for general discussion -[the #rust IRC channel on irc.mozilla.org][irc], which we -can access through [Mibbit][mibbit]. Then we'll be chatting with other -Rustaceans (a silly nickname we call ourselves) who can help us out. Other great -resources include [the user’s forum][users] and [Stack Overflow][stackoverflow]. - -[irc-beginners]: irc://irc.mozilla.org/#rust-beginners -[irc]: irc://irc.mozilla.org/#rust -[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-beginners,%23rust -[users]: https://users.rust-lang.org/ -[stackoverflow]: http://stackoverflow.com/questions/tagged/rust - -This installer also installs a copy of the documentation locally, so we can -read it offline. It's only a `rustup doc` away! - -# Hello, world! - -Now that you have Rust installed, we'll help you write your first Rust program. -It's traditional when learning a new language to write a little program to -print the text “Hello, world!” to the screen, and in this section, we'll follow -that tradition. - -The nice thing about starting with such a simple program is that you can -quickly verify that your compiler is installed, and that it's working properly. -Printing information to the screen is also a pretty common thing to do, so -practicing it early on is good. - -> Note: This book assumes basic familiarity with the command line. Rust itself -> makes no specific demands about your editing, tooling, or where your code -> lives, so if you prefer an IDE to the command line, that's an option. You may -> want to check out [SolidOak], which was built specifically with Rust in mind. -> There are a number of extensions in development by the community, and the -> Rust team ships plugins for [various editors]. Configuring your editor or -> IDE is out of the scope of this tutorial, so check the documentation for your -> specific setup. - -[SolidOak]: https://github.com/oakes/SolidOak -[various editors]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md - -## Creating a Project File - -First, make a file to put your Rust code in. Rust doesn't care where your code -lives, but for this book, I suggest making a *projects* directory in your home -directory, and keeping all your projects there. Open a terminal and enter the -following commands to make a directory for this particular project: - -```bash -$ mkdir ~/projects -$ cd ~/projects -$ mkdir hello_world -$ cd hello_world -``` - -> Note: If you’re on Windows and not using PowerShell, the `~` may not work. -> Consult the documentation for your shell for more details. - -## Writing and Running a Rust Program - -We need to create a source file for our Rust program. Rust files always end -in a *.rs* extension. If you are using more than one word in your filename, -use an underscore to separate them; for example, you would use -*my_program.rs* rather than *myprogram.rs*. - -Now, make a new file and call it *main.rs*. Open the file and type -the following code: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Save the file, and go back to your terminal window. On Linux or macOS, enter the -following commands: - -```bash -$ rustc main.rs -$ ./main -Hello, world! -``` - -In Windows, replace `main` with `main.exe`. Regardless of your operating -system, you should see the string `Hello, world!` print to the terminal. If you -did, then congratulations! You've officially written a Rust program. That makes -you a Rust programmer! Welcome. - -## Anatomy of a Rust Program - -Now, let’s go over what just happened in your "Hello, world!" program in -detail. Here's the first piece of the puzzle: - -```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` that 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. - -Also note that the function body is wrapped in curly braces (`{` and `}`). Rust -requires these around all function bodies. It's considered good style to put -the opening curly brace on the same line as the function declaration, with one -space in between. - -Inside the `main()` function: - -```rust - println!("Hello, world!"); -``` - -This line does all of the work in this little program: it prints text to the -screen. There are a number of details that are important here. The first is -that it’s indented with four spaces, not tabs. - -The second important part is the `println!()` line. This is calling a Rust -*[macro]*, which is how metaprogramming is done in Rust. If it were calling a -function instead, it would look like this: `println()` (without the !). We'll -discuss Rust macros in more detail later, but for now you only need to -know that when you see a `!` that means that you’re calling a macro instead of -a normal function. - - -[macro]: macros.html - -Next is `"Hello, world!"` which is a *string*. Strings are a surprisingly -complicated topic in a systems programming language, and this is a *[statically -allocated]* string. We pass this string as an argument to `println!`, which -prints the string to the screen. Easy enough! - -[statically allocated]: the-stack-and-the-heap.html - -The line ends with a semicolon (`;`). Rust is an *[expression-oriented -language]*, which means that most things are expressions, rather than -statements. The `;` indicates that this expression is over, and the next one is -ready to begin. Most lines of Rust code end with a `;`. - -[expression-oriented language]: glossary.html#expression-oriented-language - -## Compiling and Running Are Separate Steps - -In "Writing and Running a Rust Program", we showed you how to run a newly -created program. We'll break that process down and examine each step now. - -Before running a Rust program, you have to compile it. You can use the Rust -compiler by entering the `rustc` command and passing it the name of your source -file, like this: - -```bash -$ rustc main.rs -``` - -If you come from a C or C++ background, you'll notice that this is similar to -`gcc` or `clang`. After compiling successfully, Rust should output a binary -executable, which you can see on Linux or macOS by entering the `ls` command in -your shell as follows: - -```bash -$ ls -main main.rs -``` - -On Windows, you'd enter: - -```bash -$ dir -main.exe -main.rs -``` - -This shows we have two files: the source code, with an `.rs` extension, and the -executable (`main.exe` on Windows, `main` everywhere else). All that's left to -do from here is run the `main` or `main.exe` file, like this: - -```bash -$ ./main # or .\main.exe on Windows -``` - -If *main.rs* were your "Hello, world!" program, this would print `Hello, -world!` to your terminal. - -If you come from a dynamic language like Ruby, Python, or JavaScript, you may -not be used to compiling and running a program being separate steps. Rust is an -*ahead-of-time compiled* language, which means that you can compile a program, -give it to someone else, and they can run it even without Rust installed. If -you give someone a `.rb` or `.py` or `.js` file, on the other hand, they need -to have a Ruby, Python, or JavaScript implementation installed (respectively), -but you only need one command to both compile and run your program. Everything -is a tradeoff in language design. - -Just compiling with `rustc` is fine for simple programs, but as your project -grows, you'll want to be able to manage all of the options your project has, -and make it easy to share your code with other people and projects. Next, I'll -introduce you to a tool called Cargo, which will help you write real-world Rust -programs. - -# Hello, Cargo! - -Cargo is Rust’s build system and package manager, and Rustaceans use Cargo to -manage their Rust projects. Cargo manages three things: building your code, -downloading the libraries your code depends on, and building those libraries. -We call libraries your code needs ‘dependencies’ since your code depends on -them. - -The simplest Rust programs don’t have any dependencies, so right now, you'd -only use the first part of its functionality. As you write more complex Rust -programs, you’ll want to add dependencies, and if you start off using Cargo, -that will be a lot easier to do. - -As the vast, vast majority of Rust projects use Cargo, we will assume that -you’re using it for the rest of the book. Cargo comes installed with Rust -itself, if you used the official installers. If you installed Rust through some -other means, you can check if you have Cargo installed by typing: - -```bash -$ cargo --version -``` - -Into a terminal. If you see a version number, great! If you see an error like -‘`command not found`’, then you should look at the documentation for the system -in which you installed Rust, to determine if Cargo is separate. - -## Converting to Cargo - -Let’s convert the Hello World program to Cargo. To Cargo-fy a project, you need -to do three things: - -1. Put your source file in the right directory. -2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere - else). -3. Make a Cargo configuration file. - -Let's get started! - -### Creating a Source Directory and Removing the Old Executable - -First, go back to your terminal, move to your *hello_world* directory, and -enter the following commands: - -```bash -$ mkdir src -$ mv main.rs src/main.rs # or 'move main.rs src/main.rs' on Windows -$ rm main # or 'del main.exe' on Windows -``` - -Cargo expects your source files to live inside a *src* directory, so do that -first. This leaves the top-level project directory (in this case, -*hello_world*) for READMEs, license information, and anything else not related -to your code. In this way, using Cargo helps you keep your projects nice and -tidy. There's a place for everything, and everything is in its place. - -Now, move *main.rs* into the *src* directory, and delete the compiled file you -created with `rustc`. As usual, replace `main` with `main.exe` if you're on -Windows. - -This example retains `main.rs` as the source filename because it's creating an -executable. If you wanted to make a library instead, you'd name the file -`lib.rs`. This convention is used by Cargo to successfully compile your -projects, but it can be overridden if you wish. - -### Creating a Configuration File - -Next, create a new file inside your *hello_world* directory, and call it -`Cargo.toml`. - -Make sure to capitalize the `C` in `Cargo.toml`, or Cargo won't know what to do -with the configuration file. - -This file is in the *[TOML]* (Tom's Obvious, Minimal Language) format. TOML is -similar to INI, but has some extra goodies, and is used as Cargo’s -configuration format. - -[TOML]: https://github.com/toml-lang/toml - -Inside this file, type the following information: - -```toml -[package] - -name = "hello_world" -version = "0.0.1" -authors = [ "Your name " ] -``` - -The first line, `[package]`, indicates that the following statements are -configuring a package. As we add more information to this file, we’ll add other -sections, but for now, we only have the package configuration. - -The other three lines set the three bits of configuration that Cargo needs to -know to compile your program: its name, what version it is, and who wrote it. - -Once you've added this information to the *Cargo.toml* file, save it to finish -creating the configuration file. - -## Building and Running a Cargo Project - -With your *Cargo.toml* file in place in your project's root directory, you -should be ready to build and run your Hello World program! To do so, enter the -following commands: - -```bash -$ cargo build - Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) -$ ./target/debug/hello_world -Hello, world! -``` - -Bam! If all goes well, `Hello, world!` should print to the terminal once more. - -You just built a project with `cargo build` and ran it with -`./target/debug/hello_world`, but you can actually do both in one step with -`cargo run` as follows: - -```bash -$ cargo run - Running `target/debug/hello_world` -Hello, world! -``` - -The `run` command comes in handy when you need to rapidly iterate on a -project. - -Notice that this example didn’t re-build the project. Cargo figured out that -the file hasn’t changed, and so it just ran the binary. If you'd modified your -source code, Cargo would have rebuilt the project before running it, and you -would have seen something like this: - -```bash -$ cargo run - Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) - Running `target/debug/hello_world` -Hello, world! -``` - -Cargo checks to see if any of your project’s files have been modified, and only -rebuilds your project if they’ve changed since the last time you built it. - -With simple projects, Cargo doesn't bring a whole lot over just using `rustc`, -but it will become useful in the future. This is especially true when you start -using crates; these are synonymous with a ‘library’ or ‘package’ in other -programming languages. For complex projects composed of multiple crates, it’s -much easier to let Cargo coordinate the build. Using Cargo, you can run `cargo -build`, and it should work the right way. - -### Building for Release - -When your project is ready for release, you can use `cargo build ---release` to compile your project with optimizations. These optimizations make -your Rust code run faster, but turning them on makes your program take longer -to compile. This is why there are two different profiles, one for development, -and one for building the final program you’ll give to a user. - -### What Is That `Cargo.lock`? - -Running `cargo build` also causes Cargo to create a new file called -*Cargo.lock*, which looks like this: - -```toml -[root] -name = "hello_world" -version = "0.0.1" -``` - -Cargo uses the *Cargo.lock* file to keep track of dependencies in your -application. This is the Hello World project's *Cargo.lock* file. This project -doesn't have dependencies, so the file is a bit sparse. Realistically, you -won't ever need to touch this file yourself; just let Cargo handle it. - -That’s it! If you've been following along, you should have successfully built -`hello_world` with Cargo. - -Even though the project is simple, it now uses much of the real tooling you’ll -use for the rest of your Rust career. In fact, you can expect to start -virtually all Rust projects with some variation on the following commands: - -```bash -$ git clone someurl.com/foo -$ cd foo -$ cargo build -``` - -## Making A New Cargo Project the Easy Way - -You don’t have to go through that previous process every time you want to start -a new project! Cargo can quickly make a bare-bones project directory that you -can start developing in right away. - -To start a new project with Cargo, enter `cargo new` at the command line: - -```bash -$ cargo new hello_world --bin -``` - -This command passes `--bin` because the goal is to get straight to making an -executable application, as opposed to a library. Executables are often called -*binaries* (as in `/usr/bin`, if you’re on a Unix system). - -Cargo has generated two files and one directory for us: a `Cargo.toml` and a -*src* directory with a *main.rs* file inside. These should look familiar, -they’re exactly what we created by hand, above. - -This output is all you need to get started. First, open `Cargo.toml`. It should -look something like this: - -```toml -[package] - -name = "hello_world" -version = "0.1.0" -authors = ["Your Name "] - -[dependencies] -``` - -Do not worry about the `[dependencies]` line, we will come back to it later. - -Cargo has populated *Cargo.toml* with reasonable defaults based on 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 should be in `src/main.rs`: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Cargo has generated a "Hello World!" for you, and you’re ready to start coding! - -> Note: If you want to look at Cargo in more detail, check out the official [Cargo -guide], which covers all of its features. - -[Cargo guide]: http://doc.crates.io/guide.html - -# Closing Thoughts - -This chapter covered the basics that will serve you well through the rest of -this book, and the rest of your time with Rust. Now that you’ve got the tools -down, we'll cover more about the Rust language itself. - -You have two options: Dive into a project with ‘[Tutorial: Guessing Game][guessinggame]’, or -start from the bottom and work your way up with ‘[Syntax and -Semantics][syntax]’. More experienced systems programmers will probably prefer -‘Tutorial: Guessing Game’, while those from dynamic backgrounds may enjoy either. Different -people learn differently! Choose whatever’s right for you. - -[guessinggame]: guessing-game.html -[syntax]: syntax-and-semantics.html diff --git a/src/doc/book/src/glossary.md b/src/doc/book/src/glossary.md deleted file mode 100644 index b17b89633f356..0000000000000 --- a/src/doc/book/src/glossary.md +++ /dev/null @@ -1,85 +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. - -### 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 -``` - -### 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. - -### Bounds - -Bounds are constraints on a type or [trait][traits]. For example, if a bound -is placed on the argument a function takes, types passed to that function -must abide by that constraint. - -[traits]: traits.html - -### Combinators - -Combinators are higher-order functions that apply only functions and -earlier defined combinators to provide a result from its arguments. -They can be used to manage control flow in a modular fashion. - -### DST (Dynamically Sized Type) - -A type without a statically known size or alignment. ([more info][link]) - -[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-dsts - -### Expression - -In computer programming, an expression is a combination of values, constants, -variables, operators and functions that evaluate to a single value. For example, -`2 + (3 * 4)` is an expression that returns the value 14. It is worth noting -that expressions can have side-effects. For example, a function included in an -expression might perform actions other than simply returning a value. - -### Expression-Oriented Language - -In early programming languages, [expressions][expression] and -[statements][statement] were two separate syntactic categories: expressions had -a value and statements did things. However, later languages blurred this -distinction, allowing expressions to do things and statements to have a value. -In an expression-oriented language, (nearly) every statement is an expression -and therefore returns a value. Consequently, these expression statements can -themselves form part of larger expressions. - -[expression]: glossary.html#expression -[statement]: glossary.html#statement - -### Statement - -In computer programming, a statement is the smallest standalone element of a -programming language that commands a computer to perform an action. diff --git a/src/doc/book/src/guessing-game.md b/src/doc/book/src/guessing-game.md deleted file mode 100644 index bbb43b4a9ef4b..0000000000000 --- a/src/doc/book/src/guessing-game.md +++ /dev/null @@ -1,1010 +0,0 @@ -# Guessing Game - -Let’s learn some Rust! For our first project, we’ll implement a classic -beginner programming problem: the guessing game. Here’s how it works: Our -program will generate a random integer between one and a hundred. It will then -prompt us to enter a guess. Upon entering our guess, it will tell us if we’re -too low or too high. Once we guess correctly, it will congratulate us. Sounds -good? - -Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax -and Semantics’, will dive deeper into each part. - -# Set up - -Let’s set up a new project. Go to your projects directory. Remember how we had -to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo -has a command that does that for us. Let’s give it a shot: - -```bash -$ cd ~/projects -$ cargo new guessing_game --bin - Created binary (application) `guessing_game` project -$ cd guessing_game -``` - -We pass the name of our project to `cargo new`, and then the `--bin` flag, -since we’re making a binary, rather than a library. - -Check out the generated `Cargo.toml`: - -```toml -[package] - -name = "guessing_game" -version = "0.1.0" -authors = ["Your Name "] -``` - -Cargo gets this information from your environment. If it’s not correct, go ahead -and fix that. - -Finally, Cargo generated a ‘Hello, world!’ for us. Check out `src/main.rs`: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Let’s try compiling what Cargo gave us: - -```{bash} -$ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.53 secs -``` - -Excellent! Open up your `src/main.rs` again. We’ll be writing all of -our code in this file. - -Remember the `run` command from last chapter? Try it out again here: - -```bash -$ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs - Running `target/debug/guessing_game` -Hello, world! -``` - -Great! Our game is just the kind of project `run` is good for: we need -to quickly test each iteration before moving on to the next one. - -# Processing a Guess - -Let’s get to it! The first thing we need to do for our guessing game is -allow our player to input a guess. Put this in your `src/main.rs`: - -```rust,no_run -use std::io; - -fn main() { - println!("Guess the number!"); - - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - println!("You guessed: {}", guess); -} -``` - -There’s a lot here! Let’s go over it, bit by bit. - -```rust,ignore -use std::io; -``` - -We’ll need to take user input, and then print the result as output. As such, we -need the `io` library from the standard library. Rust only imports a few things -by default into every program, [the ‘prelude’][prelude]. If it’s not in the -prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the -[`io` prelude][ioprelude], which serves a similar function: you import it, and it -imports a number of useful, `io`-related things. - -[prelude]: ../std/prelude/index.html -[ioprelude]: ../std/io/prelude/index.html - -```rust,ignore -fn main() { -``` - -As you’ve seen before, the `main()` function is the entry point into your -program. The `fn` syntax declares a new function, the `()`s indicate that -there are no arguments, and `{` starts the body of the function. Because -we didn’t include a return type, it’s assumed to be `()`, an empty -[tuple][tuples]. - -[tuples]: primitive-types.html#tuples - -```rust,ignore - println!("Guess the number!"); - - println!("Please input your guess."); -``` - -We previously learned that `println!()` is a [macro][macros] that -prints a [string][strings] to the screen. - -[macros]: macros.html -[strings]: strings.html - -```rust,ignore - let mut guess = String::new(); -``` - -Now we’re getting interesting! There’s a lot going on in this little line. -The first thing to notice is that this is a [let statement][let], which is -used to create ‘variable bindings’. They take this form: - -```rust,ignore -let foo = bar; -``` - -[let]: variable-bindings.html - -This will create a new binding named `foo`, and bind it to the value `bar`. In -many languages, this is called a ‘variable’, but Rust’s variable bindings have -a few tricks up their sleeves. - -For example, they’re [immutable][immutable] by default. That’s why our example -uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t -take a name on the left hand side of the assignment, it actually accepts a -‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough -to use for now: - -```rust -let foo = 5; // `foo` is immutable. -let mut bar = 5; // `bar` is mutable. -``` - -[immutable]: mutability.html -[patterns]: patterns.html - -Oh, and `//` will start a comment, until the end of the line. Rust ignores -everything in [comments][comments]. - -[comments]: comments.html - -So now we know that `let mut guess` will introduce a mutable binding named -`guess`, but we have to look at the other side of the `=` for what it’s -bound to: `String::new()`. - -`String` is a string type, provided by the standard library. A -[`String`][string] is a growable, UTF-8 encoded bit of text. - -[string]: ../std/string/struct.String.html - -The `::new()` syntax uses `::` because this is an ‘associated function’ of -a particular type. That is to say, it’s associated with `String` itself, -rather than a particular instance of a `String`. Some languages call this a -‘static method’. - -This function is named `new()`, because it creates a new, empty `String`. -You’ll find a `new()` function on many types, as it’s a common name for making -a new value of some kind. - -Let’s move forward: - -```rust,ignore - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); -``` - -That’s a lot more! Let’s go bit-by-bit. The first line has two parts. Here’s -the first: - -```rust,ignore -io::stdin() -``` - -Remember how we `use`d `std::io` on the first line of the program? We’re now -calling an associated function on it. If we didn’t `use std::io`, we could -have written this line as `std::io::stdin()`. - -This particular function returns a handle to the standard input for your -terminal. More specifically, a [std::io::Stdin][iostdin]. - -[iostdin]: ../std/io/struct.Stdin.html - -The next part will use this handle to get input from the user: - -```rust,ignore -.read_line(&mut guess) -``` - -Here, we call the [`read_line`][read_line] method on our handle. -[Methods][method] are like associated functions, but are only available on a -particular instance of a type, rather than the type itself. We’re also passing -one argument to `read_line()`: `&mut guess`. - -[read_line]: ../std/io/struct.Stdin.html#method.read_line -[method]: method-syntax.html - -Remember how we bound `guess` above? We said it was mutable. However, -`read_line` doesn’t take a `String` as an argument: it takes a `&mut String`. -Rust has a feature called ‘[references][references]’, which allows you to have -multiple references to one piece of data, which can reduce copying. References -are a complex feature, as one of Rust’s major selling points is how safe and -easy it is to use references. We don’t need to know a lot of those details to -finish our program right now, though. For now, all we need to know is that -like `let` bindings, references are immutable by default. Hence, we need to -write `&mut guess`, rather than `&guess`. - -Why does `read_line()` take a mutable reference to a string? Its job is -to take what the user types into standard input, and place that into a -string. So it takes that string as an argument, and in order to add -the input, it needs to be mutable. - -[references]: references-and-borrowing.html - -But we’re not quite done with this line of code, though. While it’s -a single line of text, it’s only the first part of the single logical line of -code: - -```rust,ignore - .expect("Failed to read line"); -``` - -When you call a method with the `.foo()` syntax, you may introduce a newline -and other whitespace. This helps you split up long lines. We _could_ have -done: - -```rust,ignore - io::stdin().read_line(&mut guess).expect("Failed to read line"); -``` - -But that gets hard to read. So we’ve split it up, two lines for two method -calls. We already talked about `read_line()`, but what about `expect()`? Well, -we already mentioned that `read_line()` puts what the user types into the `&mut -String` we pass it. But it also returns a value: in this case, an -[`io::Result`][ioresult]. Rust has a number of types named `Result` in its -standard library: a generic [`Result`][result], and then specific versions for -sub-libraries, like `io::Result`. - -[ioresult]: ../std/io/type.Result.html -[result]: ../std/result/enum.Result.html - -The purpose of these `Result` types is to encode error handling information. -Values of the `Result` type, like any type, have methods defined on them. In -this case, `io::Result` has an [`expect()` method][expect] that takes a value -it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a -message you passed it. A `panic!` like this will cause our program to crash, -displaying the message. - -[expect]: ../std/result/enum.Result.html#method.expect -[panic]: error-handling.html - -If we do not call `expect()`, our program will compile, but -we’ll get a warning: - -```bash -$ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -warning: unused result which must be used, #[warn(unused_must_use)] on by default - --> src/main.rs:10:5 - | -10 | io::stdin().read_line(&mut guess); - | ^ - - Finished debug [unoptimized + debuginfo] target(s) in 0.42 secs -``` - -Rust warns us that we haven’t used the `Result` value. This warning comes from -a special annotation that `io::Result` has. Rust is trying to tell you that -you haven’t handled a possible error. The right way to suppress the error is -to actually write error handling. Luckily, if we want to crash if there’s -a problem, we can use `expect()`. If we can recover from the -error somehow, we’d do something else, but we’ll save that for a future -project. - -There’s only one line of this first example left: - -```rust,ignore - println!("You guessed: {}", guess); -} -``` - -This prints out the string we saved our input in. The `{}`s are a placeholder, -and so we pass it `guess` as an argument. If we had multiple `{}`s, we would -pass multiple arguments: - -```rust -let x = 5; -let y = 10; - -println!("x and y: {} and {}", x, y); -``` - -Easy. - -Anyway, that’s the tour. We can run what we have with `cargo run`: - -```bash -$ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.44 secs - Running `target/debug/guessing_game` -Guess the number! -Please input your guess. -6 -You guessed: 6 -``` - -All right! Our first part is done: we can get input from the keyboard, -and then print it back out. - -# Generating a secret number - -Next, we need to generate a secret number. Rust does not yet include random -number functionality in its standard library. The Rust team does, however, -provide a [`rand` crate][randcrate]. A ‘crate’ is a package of Rust code. -We’ve been building a ‘binary crate’, which is an executable. `rand` is a -‘library crate’, which contains code that’s intended to be used with other -programs. - -[randcrate]: https://crates.io/crates/rand - -Using external crates is where Cargo really shines. Before we can write -the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and -add these few lines at the bottom: - -```toml -[dependencies] - -rand="0.3.0" -``` - -The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: -everything that follows it is part of it, until the next section starts. -Cargo uses the dependencies section to know what dependencies on external -crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`, -which Cargo understands to be any release that’s compatible with this specific version. -Cargo understands [Semantic Versioning][semver], which is a standard for writing version -numbers. A bare number like above is actually shorthand for `^0.3.0`, -meaning "anything compatible with 0.3.0". -If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` -(note the two equal signs). -We could also use a range of versions. -[Cargo’s documentation][cargodoc] contains more details. - -[semver]: http://semver.org -[cargodoc]: http://doc.crates.io/specifying-dependencies.html - -Now, without changing any of our code, let’s build our project: - -```bash -$ cargo build - Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading rand v0.3.14 - Downloading libc v0.2.17 - Compiling libc v0.2.17 - Compiling rand v0.3.14 - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 5.88 secs -``` - -(You may see different versions, of course.) - -Lots of new output! Now that we have an external dependency, Cargo fetches the -latest versions of everything from the registry, which is a copy of data from -[Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem -post their open source Rust projects for others to use. - -[cratesio]: https://crates.io - -After updating the registry, Cargo checks our `[dependencies]` and downloads -any we don’t have yet. In this case, while we only said we wanted to depend on -`rand`, we’ve also grabbed a copy of `libc`. This is because `rand` depends on -`libc` to work. After downloading them, it compiles them, and then compiles -our project. - -If we run `cargo build` again, we’ll get different output: - -```bash -$ cargo build - Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs -``` - -That’s right, nothing was done! Cargo knows that our project has been built, and that -all of its dependencies are built, and so there’s no reason to do all that -stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again, -make a trivial change, and then save it again, we’ll only see two lines: - -```bash -$ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.45 secs -``` - -So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest -version at the time this was written, `v0.3.14`. But what happens when next -week, version `v0.3.15` comes out, with an important bugfix? While getting -bugfixes is important, what if `0.3.15` contains a regression that breaks our -code? - -The answer to this problem is the `Cargo.lock` file you’ll now find in your -project directory. When you build your project for the first time, Cargo -figures out all of the versions that fit your criteria, and then writes them -to the `Cargo.lock` file. When you build your project in the future, Cargo -will see that the `Cargo.lock` file exists, and then use that specific version -rather than do all the work of figuring out versions again. This lets you -have a repeatable build automatically. In other words, we’ll stay at `0.3.14` -until we explicitly upgrade, and so will anyone who we share our code with, -thanks to the lock file. - -What about when we _do_ want to use `v0.3.15`? Cargo has another command, -`update`, which says ‘ignore the lock, figure out all the latest versions that -fit what we’ve specified. If that works, write those versions out to the lock -file’. But, by default, Cargo will only look for versions larger than `0.3.0` -and smaller than `0.4.0`. If we want to move to `0.4.x`, we’d have to update -the `Cargo.toml` directly. When we do, the next time we `cargo build`, Cargo -will update the index and re-evaluate our `rand` requirements. - -There’s a lot more to say about [Cargo][doccargo] and [its -ecosystem][doccratesio], but for now, that’s all we need to know. Cargo makes -it really easy to re-use libraries, and so Rustaceans tend to write smaller -projects which are assembled out of a number of sub-packages. - -[doccargo]: http://doc.crates.io -[doccratesio]: http://doc.crates.io/crates-io.html - -Let’s get on to actually _using_ `rand`. Here’s our next step: - -```rust,ignore -extern crate rand; - -use std::io; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - println!("You guessed: {}", guess); -} -``` - -The first thing we’ve done is change the first line. It now says -`extern crate rand`. Because we declared `rand` in our `[dependencies]`, we -can use `extern crate` to let Rust know we’ll be making use of it. This also -does the equivalent of a `use rand;` as well, so we can make use of anything -in the `rand` crate by prefixing it with `rand::`. - -Next, we added another `use` line: `use rand::Rng`. We’re going to use a -method in a moment, and it requires that `Rng` be in scope to work. The basic -idea is this: methods are defined on something called ‘traits’, and for the -method to work, it needs the trait to be in scope. For more about the -details, read the [traits][traits] section. - -[traits]: traits.html - -There are two other lines we added, in the middle: - -```rust,ignore - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); -``` - -We use the `rand::thread_rng()` function to get a copy of the random number -generator, which is local to the particular [thread][concurrency] of execution -we’re in. Because we `use rand::Rng`’d above, it has a `gen_range()` method -available. This method takes two arguments, and generates a number between -them. It’s inclusive on the lower bound, but exclusive on the upper bound, -so we need `1` and `101` to get a number ranging from one to a hundred. - -[concurrency]: concurrency.html - -The second line prints out the secret number. This is useful while -we’re developing our program, so we can easily test it out. But we’ll be -deleting it for the final version. It’s not much of a game if it prints out -the answer when you start it up! - -Try running our new program a few times: - -```bash -$ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.55 secs - Running `target/debug/guessing_game` -Guess the number! -The secret number is: 7 -Please input your guess. -4 -You guessed: 4 -$ cargo run - Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs - Running `target/debug/guessing_game` -Guess the number! -The secret number is: 83 -Please input your guess. -5 -You guessed: 5 -``` - -Great! Next up: comparing our guess to the secret number. - -# Comparing guesses - -Now that we’ve got user input, let’s compare our guess to the secret number. -Here’s our next step, though it doesn’t quite compile yet: - -```rust,ignore -extern crate rand; - -use std::io; -use std::cmp::Ordering; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - println!("You guessed: {}", guess); - - match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} -``` - -A few new bits here. The first is another `use`. We bring a type called -`std::cmp::Ordering` into scope. Then, five new lines at the bottom that use -it: - -```rust,ignore -match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), -} -``` - -The `cmp()` method can be called on anything that can be compared, and it -takes a reference to the thing you want to compare it to. It returns the -`Ordering` type we `use`d earlier. We use a [`match`][match] statement to -determine exactly what kind of `Ordering` it is. `Ordering` is an -[`enum`][enum], short for ‘enumeration’, which looks like this: - -```rust -enum Foo { - Bar, - Baz, -} -``` - -[match]: match.html -[enum]: enums.html - -With this definition, anything of type `Foo` can be either a -`Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the -namespace for a particular `enum` variant. - -The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`, -and `Greater`. The `match` statement takes a value of a type, and lets you -create an ‘arm’ for each possible value. Since we have three types of -`Ordering`, we have three arms: - -```rust,ignore -match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), -} -``` - -[ordering]: ../std/cmp/enum.Ordering.html - -If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if -`Equal`, `You win!`. `match` is really useful, and is used often in Rust. - -I did mention that this won’t quite compile yet, though. Let’s try it: - -```bash -$ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -error[E0308]: mismatched types - --> src/main.rs:23:21 - | -23 | match guess.cmp(&secret_number) { - | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable - | - = note: expected type `&std::string::String` - = note: found type `&{integer}` - -error: aborting due to previous error - -error: Could not compile `guessing_game`. - -To learn more, run the command again with --verbose. -``` - -Whew! This is a big error. The core of it is that we have ‘mismatched types’. -Rust has a strong, static type system. However, it also has type inference. -When we wrote `let guess = String::new()`, Rust was able to infer that `guess` -should be a `String`, and so it doesn’t make us write out the type. And with -our `secret_number`, there are a number of types which can have a value -between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an -unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number or others. -So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here, -Rust doesn’t know how to compare the `guess` and the `secret_number`. They -need to be the same type. Ultimately, we want to convert the `String` we -read as input into a real number type, for comparison. We can do that -with two more lines. Here’s our new program: - -```rust,ignore -extern crate rand; - -use std::io; -use std::cmp::Ordering; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); - - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); - - println!("You guessed: {}", guess); - - match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } -} -``` - -The new two lines: - -```rust,ignore - let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); -``` - -Wait a minute, I thought we already had a `guess`? We do, but Rust allows us -to ‘shadow’ the previous `guess` with a new one. This is often used in this -exact situation, where `guess` starts as a `String`, but we want to convert it -to an `u32`. Shadowing lets us re-use the `guess` name, rather than forcing us -to come up with two unique names like `guess_str` and `guess`, or something -else. - -We bind `guess` to an expression that looks like something we wrote earlier: - -```rust,ignore -guess.trim().parse() -``` - -Here, `guess` refers to the old `guess`, the one that was a `String` with our -input in it. The `trim()` method on `String`s will eliminate any white space at -the beginning and end of our string. This is important, as we had to press the -‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit -return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the -enter key. `trim()` gets rid of this, leaving our string with only the `5`. The -[`parse()` method on strings][parse] parses a string into some kind of number. -Since it can parse a variety of numbers, we need to give Rust a hint as to the -exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after -`guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, -thirty-two bit integer. Rust has [a number of built-in number types][number], -but we’ve chosen `u32`. It’s a good default choice for a small positive number. - -[parse]: ../std/primitive.str.html#method.parse -[number]: primitive-types.html#numeric-types - -Just like `read_line()`, our call to `parse()` could cause an error. What if -our string contained `A👍%`? There’d be no way to convert that to a number. As -such, we’ll do the same thing we did with `read_line()`: use the `expect()` -method to crash if there’s an error. - -Let’s try our program out! - -```bash -$ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs - Running `target/guessing_game` -Guess the number! -The secret number is: 58 -Please input your guess. - 76 -You guessed: 76 -Too big! -``` - -Nice! You can see I even added spaces before my guess, and it still figured -out that I guessed 76. Run the program a few times, and verify that guessing -the number works, as well as guessing a number too small. - -Now we’ve got most of the game working, but we can only make one guess. Let’s -change that by adding loops! - -# Looping - -The `loop` keyword gives us an infinite loop. Let’s add that in: - -```rust,ignore -extern crate rand; - -use std::io; -use std::cmp::Ordering; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); - - loop { - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); - - println!("You guessed: {}", guess); - - match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => println!("You win!"), - } - } -} -``` - -And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember -our discussion about `parse()`? If we give a non-number answer, we’ll `panic!` -and quit. Observe: - -```bash -$ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.58 secs - Running `target/guessing_game` -Guess the number! -The secret number is: 59 -Please input your guess. -45 -You guessed: 45 -Too small! -Please input your guess. -60 -You guessed: 60 -Too big! -Please input your guess. -59 -You guessed: 59 -You win! -Please input your guess. -quit -thread 'main' panicked at 'Please type a number!' -``` - -Ha! `quit` actually quits. As does any other non-number input. Well, this is -suboptimal to say the least. First, let’s actually quit when you win the game: - -```rust,ignore -extern crate rand; - -use std::io; -use std::cmp::Ordering; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); - - loop { - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); - - println!("You guessed: {}", guess); - - match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - break; - } - } - } -} -``` - -By adding the `break` line after the `You win!`, we’ll exit the loop when we -win. Exiting the loop also means exiting the program, since it’s the last -thing in `main()`. We have only one more tweak to make: when someone inputs a -non-number, we don’t want to quit, we want to ignore it. We can do that -like this: - -```rust,ignore -extern crate rand; - -use std::io; -use std::cmp::Ordering; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - println!("The secret number is: {}", secret_number); - - loop { - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - let guess: u32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => continue, - }; - - println!("You guessed: {}", guess); - - match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - break; - } - } - } -} -``` - -These are the lines that changed: - -```rust,ignore -let guess: u32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => continue, -}; -``` -This is how you generally move from ‘crash on error’ to ‘actually handle the -error’, by switching from `expect()` to a `match` statement. A `Result` is -returned by `parse()`, this is an `enum` like `Ordering`, but in this case, -each variant has some data associated with it: `Ok` is a success, and `Err` is a -failure. Each contains more information: the successfully parsed integer, or an -error type. In this case, we `match` on `Ok(num)`, which sets the name `num` to -the unwrapped `Ok` value (the integer), and then we return it on the -right-hand side. In the `Err` case, we don’t care what kind of error it is, so -we just use the catch all `_` instead of a name. This catches everything that -isn't `Ok`, and `continue` lets us move to the next iteration of the loop; in -effect, this enables us to ignore all errors and continue with our program. - -Now we should be good! Let’s try: - -```bash -$ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) - Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs - Running `target/guessing_game` -Guess the number! -The secret number is: 61 -Please input your guess. -10 -You guessed: 10 -Too small! -Please input your guess. -99 -You guessed: 99 -Too big! -Please input your guess. -foo -Please input your guess. -61 -You guessed: 61 -You win! -``` - -Awesome! With one tiny last tweak, we have finished the guessing game. Can you -think of what it is? That’s right, we don’t want to print out the secret -number. It was good for testing, but it kind of ruins the game. Here’s our -final source: - -```rust,ignore -extern crate rand; - -use std::io; -use std::cmp::Ordering; -use rand::Rng; - -fn main() { - println!("Guess the number!"); - - let secret_number = rand::thread_rng().gen_range(1, 101); - - loop { - println!("Please input your guess."); - - let mut guess = String::new(); - - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); - - let guess: u32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => continue, - }; - - println!("You guessed: {}", guess); - - match guess.cmp(&secret_number) { - Ordering::Less => println!("Too small!"), - Ordering::Greater => println!("Too big!"), - Ordering::Equal => { - println!("You win!"); - break; - } - } - } -} -``` - -# Complete! - -This project showed you a lot: `let`, `match`, methods, associated -functions, using external crates, and more. - -At this point, you have successfully built the Guessing Game! Congratulations! diff --git a/src/doc/book/src/if-let.md b/src/doc/book/src/if-let.md deleted file mode 100644 index 9eeac3d687ebf..0000000000000 --- a/src/doc/book/src/if-let.md +++ /dev/null @@ -1,84 +0,0 @@ -# if let - -`if let` permits [patterns][patterns] matching within the condition of an [if][if] statement. -This allows us to reduce the overhead of certain kinds of [pattern][patterns] matches -and express them in a more convenient way. - -For example, let’s say we have some sort of `Option`. We want to call a function -on it if it’s `Some`, but do nothing if it’s `None`. That looks like this: - -```rust -# let option = Some(5); -# fn foo(x: i32) { } -match option { - Some(x) => { foo(x) }, - None => {}, -} -``` - -We don’t have to use `match` here, for example, we could use `if`: - -```rust -# let option = Some(5); -# fn foo(x: i32) { } -if option.is_some() { - let x = option.unwrap(); - foo(x); -} -``` - -Neither of these options is particularly appealing. We can use `if let` to -do the same thing in a nicer way: - -```rust -# let option = Some(5); -# fn foo(x: i32) { } -if let Some(x) = option { - foo(x); -} -``` - -If a [pattern][patterns] matches successfully, it binds any appropriate parts of -the value to the identifiers in the pattern, then evaluates the expression. If -the pattern doesn’t match, nothing happens. - -If you want to do something else when the pattern does not match, you can -use `else`: - -```rust -# let option = Some(5); -# fn foo(x: i32) { } -# fn bar() { } -if let Some(x) = option { - foo(x); -} else { - bar(); -} -``` - -## `while let` - -In a similar fashion, `while let` can be used when you want to conditionally -loop as long as a value matches a certain pattern. It turns code like this: - -```rust -let mut v = vec![1, 3, 5, 7, 11]; -loop { - match v.pop() { - Some(x) => println!("{}", x), - None => break, - } -} -``` - -Into code like this: - -```rust -let mut v = vec![1, 3, 5, 7, 11]; -while let Some(x) = v.pop() { - println!("{}", x); -} -``` - -[patterns]: patterns.html -[if]: if.html diff --git a/src/doc/book/src/if.md b/src/doc/book/src/if.md deleted file mode 100644 index d74503757bc48..0000000000000 --- a/src/doc/book/src/if.md +++ /dev/null @@ -1,73 +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’, whose 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 works because `if` is an expression. The value of the expression is the -value of the last expression in whichever branch was chosen. An `if` without an -`else` always results in `()` as the value. diff --git a/src/doc/book/src/iterators.md b/src/doc/book/src/iterators.md deleted file mode 100644 index 8ee6c0828ad6b..0000000000000 --- a/src/doc/book/src/iterators.md +++ /dev/null @@ -1,344 +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. - -(By the way, a range with two dots like `0..10` is inclusive on the left (so it -starts at 0) and exclusive on the right (so it ends at 9). A mathematician -would write "[0, 10)". To get a range that goes all the way up to 10 you can -write `0...10`.) - -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 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. But first, a few notes about limitations of ranges. - -Ranges are very primitive, and we often can use better alternatives. Consider the -following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Let’s -suppose 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 only borrowing a reference to the data, -and so it's only 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 adaptors*, and *consumers*. Here's some definitions: - -* *iterators* give you a sequence of values. -* *iterator adaptors* 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](generics.html#resolving-ambiguities) -allows us to give a type hint that tells the compiler 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!("Found a match!"), - None => println!("No match 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. `find` returns the first element satisfying -the specified predicate. 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 -can be *lazy* and not generate all of the values upfront. This code, -for example, does not actually generate the numbers `1-99`, instead -creating a value that merely 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 = vec![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. - -That's enough about iterators. Iterator adaptors are the last concept -we need to talk about with regards to iterators. Let's get to it! - -## Iterator adaptors - -*Iterator adaptors* 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, -use `for` instead. - -There are tons of interesting iterator adaptors. `take(n)` will return an -iterator over the next `n` elements of the original iterator. Let's try it out -with an infinite iterator: - -```rust -for i in (1..).take(5) { - println!("{}", i); -} -``` - -This will print - -```text -1 -2 -3 -4 -5 -``` - -`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 the 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, unlike `map`, the closure passed to `filter` is passed a reference -to the element instead of the element itself. The filter predicate here uses -the `&x` pattern to extract the integer. The filter closure is passed a -reference because it returns `true` or `false` instead of the element, -so the `filter` implementation must retain ownership to put the elements -into the newly constructed iterator.) - -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..) - .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 adaptors, 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/book/src/lifetimes.md b/src/doc/book/src/lifetimes.md deleted file mode 100644 index 042d9af9717d0..0000000000000 --- a/src/doc/book/src/lifetimes.md +++ /dev/null @@ -1,428 +0,0 @@ -# Lifetimes - -This is the last of three sections presenting Rust’s ownership system. This is one of -Rust’s most distinct and compelling features, with which Rust developers should -become quite acquainted. Ownership is how Rust achieves its largest goal, -memory safety. There are a few distinct concepts, each with its own chapter: - -* [ownership][ownership], the key concept -* [borrowing][borrowing], and their associated feature ‘references’ -* lifetimes, which you’re reading now - -These three chapters are related, and in order. You’ll need all three to fully -understand the ownership system. - -[ownership]: ownership.html -[borrowing]: references-and-borrowing.html - -# 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 lifetimes. - -# Lifetimes - -Lending out a reference to a resource that someone else owns can be -complicated. 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. A small -example of such a situation would be: - -```rust,compile_fail -let r; // Introduce reference: `r`. -{ - let i = 1; // Introduce scoped value: `i`. - r = &i; // Store reference of `i` in `r`. -} // `i` goes out of scope and is dropped. - -println!("{}", r); // `r` still refers to `i`. -``` - -To fix this, we have to make sure that step four never happens after step -three. In the small example above the Rust compiler is able to report the issue -as it can see the lifetimes of the various values in the function. - -When we have a function that takes arguments by reference the situation becomes -more complex. Consider the following example: - -```rust,compile_fail,E0106 -fn skip_prefix(line: &str, prefix: &str) -> &str { - // ... -# line -} - -let line = "lang:en=Hello World!"; -let lang = "en"; - -let v; -{ - let p = format!("lang:{}=", lang); // -+ `p` comes into scope. - v = skip_prefix(line, p.as_str()); // | -} // -+ `p` goes out of scope. -println!("{}", v); -``` - -Here we have a function `skip_prefix` which takes two `&str` references -as parameters and returns a single `&str` reference. We call it -by passing in references to `line` and `p`: Two variables with different -lifetimes. Now the safety of the `println!`-line depends on whether the -reference returned by `skip_prefix` function references the still living -`line` or the already dropped `p` string. - -Because of the above ambiguity, Rust will refuse to compile the example -code. To get it to compile we need to tell the compiler more about the -lifetimes of the references. This can be done by making the lifetimes -explicit in the function declaration: - -```rust -fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str { - // ... -# line -} -``` - -Let's examine the changes without going too deep into the syntax for now - -we'll get to that later. The first change was adding the `<'a, 'b>` after the -method name. This introduces two lifetime parameters: `'a` and `'b`. Next, each -reference in the function signature was associated with one of the lifetime -parameters by adding the lifetime name after the `&`. This tells the compiler -how the lifetimes between different references are related. - -As a result the compiler is now able to deduce that the return value of -`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v` -reference safe to use even after the `p` goes out of scope in the original -example. - -In addition to the compiler being able to validate the usage of `skip_prefix` -return value, it can also ensure that the implementation follows the contract -established by the function declaration. This is useful especially when you are -implementing traits that are introduced [later in the book][traits]. - -**Note** It's important to understand that lifetime annotations are -_descriptive_, not _prescriptive_. This means that how long a reference is valid -is determined by the code, not by the annotations. The annotations, however, -give information about lifetimes to the compiler that uses them to check the -validity of references. The compiler can do so without annotations in simple -cases, but needs the programmer's support in complex scenarios. - -[traits]: traits.html - -# Syntax - -The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime -associated with it, but the compiler lets you elide (i.e. omit, see -["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we -get to that, though, let’s look at a short example with explicit lifetimes: - -[lifetime-elision]: #lifetime-elision - -```rust,ignore -fn bar<'a>(...) -``` - -We previously talked a little about [function syntax][functions], but we didn’t -discuss the `<>`s after a function’s name. A function can have ‘generic -parameters’ between the `<>`s, of which lifetimes are one kind. We’ll discuss -other kinds of generics [later in the book][generics], but for now, let’s -focus on the lifetimes aspect. - -[functions]: functions.html -[generics]: generics.html - -We use `<>` to declare our lifetimes. This says that `bar` has one lifetime, -`'a`. If we had two reference parameters with different lifetimes, it would -look like this: - - -```rust,ignore -fn bar<'a, 'b>(...) -``` - -Then in our parameter list, we use the lifetimes we’ve named: - -```rust,ignore -...(x: &'a i32) -``` - -If we wanted a `&mut` reference, we’d do this: - -```rust,ignore -...(x: &'a mut i32) -``` - -If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s 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`’. - -# In `struct`s - -You’ll also need explicit lifetimes when working with [`struct`][structs]s that -contain references: - -```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); -} -``` - -[structs]: structs.html - -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. - -## `impl` blocks - -Let’s implement a method on `Foo`: - -```rust -struct Foo<'a> { - x: &'a i32, -} - -impl<'a> Foo<'a> { - fn x(&self) -> &'a i32 { self.x } -} - -fn main() { - let y = &5; // This is the same as `let _y = 5; let y = &_y;`. - let f = Foo { x: y }; - - println!("x is: {}", f.x()); -} -``` - -As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat -`'a` twice, like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>` -uses it. - -## Multiple lifetimes - -If you have multiple references, you can use the same lifetime multiple times: - -```rust -fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str { -# x -# } -``` - -This says that `x` and `y` both are alive for the same scope, and that the -return value is also alive for that scope. If you wanted `x` and `y` to have -different lifetimes, you can use multiple lifetime parameters: - -```rust -fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { -# x -# } -``` - -In this example, `x` and `y` have different valid scopes, but the return value -has the same lifetime as `x`. - -## 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` comes 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` comes into scope. - let f = Foo { x: y }; // -+ `f` comes 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` comes into scope. - // | - { // | - let y = &5; // ---+ `y` comes into scope. - let f = Foo { x: y }; // ---+ `f` comes into scope. - x = &f.x; // | | This causes an error. - } // ---+ `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. - -## Lifetime Elision - -Rust supports powerful local type inference in the bodies of functions, but it -deliberately does not perform any reasoning about types for item signatures. -However, for ergonomic reasons, a very restricted secondary inference algorithm called -“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring -lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision -acts as 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 terms *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. - -```rust,ignore -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 ambiguous - -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 -``` diff --git a/src/doc/book/src/loops.md b/src/doc/book/src/loops.md deleted file mode 100644 index b7658d57a9e16..0000000000000 --- a/src/doc/book/src/loops.md +++ /dev/null @@ -1,211 +0,0 @@ -# Loops - -Rust currently provides three approaches to performing some kind of iterative activity. They are: `loop`, `while` and `for`. Each approach has its own set of uses. - -## loop - -The infinite `loop` is the simplest form of loop available in Rust. Using the keyword `loop`, Rust provides a way to loop indefinitely until some terminating statement is reached. Rust's infinite `loop`s look like this: - -```rust,ignore -loop { - println!("Loop forever!"); -} -``` - -## while - -Rust also has a `while` loop. It looks like this: - -```rust -let mut x = 5; // mut x: i32 -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, `loop` is far better suited 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. 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. - -## 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, - -```rust,ignore -for var in expression { - code -} -``` - -The expression is an item that can be converted into an [iterator] using -[`IntoIterator`]. 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. - -[iterator]: iterators.html -[`IntoIterator`]: ../std/iter/trait.IntoIterator.html - -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. - -### Enumerate - -When you need to keep track of how many times you have already looped, you can -use the `.enumerate()` function. - -#### On ranges: - -```rust -for (index, value) in (5..10).enumerate() { - println!("index = {} and value = {}", index, value); -} -``` - -Outputs: - -```text -index = 0 and value = 5 -index = 1 and value = 6 -index = 2 and value = 7 -index = 3 and value = 8 -index = 4 and value = 9 -``` - -Don't forget to add the parentheses around the range. - -#### On iterators: - -```rust -let lines = "hello\nworld".lines(); - -for (linenumber, line) in lines.enumerate() { - println!("{}: {}", linenumber, line); -} -``` - -Outputs: - -```text -0: hello -1: world -``` - -## 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. Issuing an explicit `return` statement will also serve to terminate the loop early. - -`continue` is similar, but instead of ending the loop, it 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); -} -``` - -## Loop labels - -You may also encounter situations where you have nested loops and need to -specify which one your `break` or `continue` statement is for. Like most -other languages, by default a `break` or `continue` will apply to innermost -loop. In a situation where you would like to `break` or `continue` for one -of the outer loops, you can use labels to specify which loop the `break` or - `continue` statement applies to. This will only print when both `x` and `y` are - odd: - -```rust -'outer: for x in 0..10 { - 'inner: for y in 0..10 { - if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`. - if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`. - println!("x: {}, y: {}", x, y); - } -} -``` diff --git a/src/doc/book/src/macros.md b/src/doc/book/src/macros.md deleted file mode 100644 index fa8e8975a5b01..0000000000000 --- a/src/doc/book/src/macros.md +++ /dev/null @@ -1,763 +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][vector] with -any number of elements. - -[vector]: vectors.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. - -```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. - -```rust,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 - -```rust,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/macros.html - -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 later in this 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,ignore -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: - -```rust,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: - -```rust,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](https://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 block with multiple statements. - -```text -#define LOG(msg) do { \ - int state = get_log_state(); \ - if (state > 0) { \ - printf("log(%d): %s\n", state, msg); \ - } \ -} while (0) -``` - -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"; -do { - int state = get_log_state(); - if (state > 0) { - printf("log(%d): %s\n", state, state); - } -} while (0); -``` - -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]: https://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 that 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][items]. -So the following code does compile: - -```rust -macro_rules! foo { - () => (fn x() { }); -} - -fn main() { - foo!(); - x(); -} -``` - -[items]: ../reference/items.html - -# 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 { 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 and optionally an expression. Example: - `{ log(error, "hi"); return 12; }`. -* `item`: an [item][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` and `stmt` variables may only be followed by one of: `=> , ;` -* `ty` and `path` variables may only be followed by one of: `=> , = | ; : > [ { as where` -* `pat` variables may only be followed by one of: `=> , = | if in` -* 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 `$($i:ident)* $e:expr` will always fail to parse, because the parser would -be forced to choose between parsing `$i` and parsing `$e`. Changing the -invocation syntax to put a distinctive token in front can solve the problem. In -this case, you can write `$(I $i:ident)* E $e:expr`. - -[item]: ../reference/items.html - -# 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/attributes.html#macro-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`. - -# 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](https://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. - -# Common macros - -Here are some common macros you’ll see in Rust code. - -## panic! - -This macro causes the current thread to panic. You can give it a message -to panic with: - -```rust,should_panic -panic!("oh no!"); -``` - -## vec! - -The `vec!` macro is used throughout the book, so you’ve probably seen it -already. It creates `Vec`s with ease: - -```rust -let v = vec![1, 2, 3, 4, 5]; -``` - -It also lets you make vectors with repeating values. For example, a hundred -zeroes: - -```rust -let v = vec![0; 100]; -``` - -## assert! and assert_eq! - -These two macros are used in tests. `assert!` takes a boolean. `assert_eq!` -takes two values and checks them for equality. `true` passes, `false` `panic!`s. -Like this: - -```rust,should_panic -// A-ok! - -assert!(true); -assert_eq!(5, 3 + 2); - -// Nope :( - -assert!(5 < 3); -assert_eq!(5, 3); -``` - -## try! - -`try!` is used for error handling. It takes something that can return a -`Result`, and gives `T` if it’s a `Ok`, and `return`s with the -`Err(E)` if it’s that. Like this: - -```rust,no_run -use std::fs::File; - -fn foo() -> std::io::Result<()> { - let f = try!(File::create("foo.txt")); - - Ok(()) -} -``` - -This is cleaner than doing this: - -```rust,no_run -use std::fs::File; - -fn foo() -> std::io::Result<()> { - let f = File::create("foo.txt"); - - let f = match f { - Ok(t) => t, - Err(e) => return Err(e), - }; - - Ok(()) -} -``` - -## unreachable! - -This macro is used when you think some code should never execute: - -```rust -if false { - unreachable!(); -} -``` - -Sometimes, the compiler may make you have a different branch that you know -will never, ever run. In these cases, use this macro, so that if you end -up wrong, you’ll get a `panic!` about it. - -```rust -let x: Option = None; - -match x { - Some(_) => unreachable!(), - None => println!("I know x is None!"), -} -``` - -## unimplemented! - -The `unimplemented!` macro can be used when you’re trying to get your functions -to typecheck, and don’t want to worry about writing out the body of the -function. One example of this situation is implementing a trait with multiple -required methods, where you want to tackle one at a time. Define the others -as `unimplemented!` until you’re ready to write them. diff --git a/src/doc/book/src/match.md b/src/doc/book/src/match.md deleted file mode 100644 index b1e26a9c9d3cd..0000000000000 --- a/src/doc/book/src/match.md +++ /dev/null @@ -1,100 +0,0 @@ -# Match - -Often, a simple [`if`][if]/`else` isn’t enough, because you have more than two -possible options. Also, conditions can get quite complex. 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"), -} -``` - -[if]: if.html - -`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. There’s a [separate section on -patterns][patterns] that covers all the patterns that are possible here. - -[patterns]: patterns.html - -One of the many advantages of `match` is it enforces ‘exhaustiveness checking’. -For example if we remove the last arm with the underscore `_`, the compiler will -give us an error: - -```text -error: non-exhaustive patterns: `_` not covered -``` - -Rust is telling us that we forgot some value. The compiler infers from `x` that it -can have any 32bit integer value; for example -2,147,483,648 to 2,147,483,647. The `_` acts -as a 'catch-all', and will catch all possible values that *aren't* specified in -an arm of `match`. As you can see in the previous example, we provide `match` -arms for integers 1-5, if `x` is 6 or any other value, then it is caught by `_`. - -`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: - -```rust -let x = 5; - -let number = match x { - 1 => "one", - 2 => "two", - 3 => "three", - 4 => "four", - 5 => "five", - _ => "something else", -}; -``` - -Sometimes it’s a nice way of converting something from one type to another; in -this example the integers are converted to `String`. - -# Matching on enums - -Another important use of the `match` keyword is to process the possible -variants of an enum: - -```rust -enum Message { - Quit, - ChangeColor(i32, i32, i32), - Move { x: i32, y: i32 }, - Write(String), -} - -fn quit() { /* ... */ } -fn change_color(r: i32, g: i32, b: i32) { /* ... */ } -fn move_cursor(x: i32, y: i32) { /* ... */ } - -fn process_message(msg: Message) { - match msg { - Message::Quit => quit(), - Message::ChangeColor(r, g, b) => change_color(r, g, b), - Message::Move { x, y: new_name_for_y } => move_cursor(x, new_name_for_y), - Message::Write(s) => println!("{}", s), - }; -} -``` - -Again, the Rust compiler checks exhaustiveness, so it demands that you -have a match arm for every variant of the enum. If you leave one off, it -will give you a compile-time error unless you use `_` or provide all possible -arms. - -Unlike the previous uses of `match`, you can’t use the normal `if` -statement to do this. You can use the [`if let`][if-let] statement, -which can be seen as an abbreviated form of `match`. - -[if-let]: if-let.html diff --git a/src/doc/book/src/method-syntax.md b/src/doc/book/src/method-syntax.md deleted file mode 100644 index 0404a5c992ba3..0000000000000 --- a/src/doc/book/src/method-syntax.md +++ /dev/null @@ -1,259 +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)); -``` - -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 -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 -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 `foo` in `foo.bar()`. The three variants correspond to the three -kinds of things `foo` could be: `self` if it’s a value on the stack, -`&self` if it’s a reference, and `&mut self` if it’s a mutable reference. -Because we took the `&self` parameter to `area`, we can use it like any -other parameter. Because we know it’s a `Circle`, we can access the `radius` -like we would with any other `struct`. - -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!"); - } -} -``` - -You can use as many `impl` blocks as you’d like. The previous example could -have also been written like this: - -```rust -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn reference(&self) { - println!("taking self by reference!"); - } -} - -impl Circle { - fn mutable_reference(&mut self) { - println!("taking self by mutable reference!"); - } -} - -impl Circle { - fn takes_ownership(self) { - println!("taking ownership of self!"); - } -} -``` - -# 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’. Let’s -look at an example: - -```rust -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: - -```rust -# struct Circle; -# impl Circle { -fn grow(&self, increment: f64) -> Circle { -# Circle } } -``` - -We say we’re returning a `Circle`. With this method, we can grow a new -`Circle` to any arbitrary size. - -# Associated functions - -You can also define associated functions that do not take a `self` parameter. -Here’s a pattern that’s very common in Rust code: - -```rust -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 ‘associated function’ builds a new `Circle` for us. Note that associated -functions are called with the `Struct::function()` syntax, rather than the -`ref.method()` syntax. Some other languages call associated functions ‘static -methods’. - -# Builder Pattern - -Let’s say that we want our users to be able to create `Circle`s, 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: - -```rust -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: 1.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/book/src/mutability.md b/src/doc/book/src/mutability.md deleted file mode 100644 index fa7a259392a7e..0000000000000 --- a/src/doc/book/src/mutability.md +++ /dev/null @@ -1,181 +0,0 @@ -# Mutability - -Mutability, the ability to change something, works a bit differently in Rust -than in other languages. The first aspect of mutability is its non-default -status: - -```rust,ignore -let x = 5; -x = 6; // Error! -``` - -We can introduce mutability with the `mut` keyword: - -```rust -let mut x = 5; - -x = 6; // No problem! -``` - -This is a mutable [variable binding][vb]. When a binding is mutable, it means -you’re allowed to change what the binding points to. So in the above example, -it’s not so much that the value at `x` is changing, but that the binding -changed from one `i32` to another. - -[vb]: variable-bindings.html - -You can also create a [reference][ref] to it, using `&x`, but if you want to use the reference to change it, you will need a mutable reference: - -```rust -let mut x = 5; -let y = &mut x; -``` - -[ref]: references-and-borrowing.html - -`y` is an immutable binding to a mutable reference, which means that you can’t bind 'y' to something else (`y = &mut z`), but `y` can be used to bind `x` to something else (`*y = 5`). A subtle distinction. - -Of course, if you need both: - -```rust -let mut x = 5; -let mut y = &mut x; -``` - -Now `y` can be bound to another value, and the value it’s referencing can be -changed. - -It’s important to note that `mut` is part of a [pattern][pattern], so you -can do things like this: - -```rust -let (mut x, y) = (5, 6); - -fn foo(mut x: i32) { -# } -``` - -Note that here, the `x` is mutable, but not the `y`. - -[pattern]: patterns.html - -# Interior vs. Exterior Mutability - -However, when we say something is ‘immutable’ in Rust, that doesn’t mean that -it’s not able to be changed: we are referring to its ‘exterior mutability’ that -in this case is immutable. Consider, for example, [`Arc`][arc]: - -```rust -use std::sync::Arc; - -let x = Arc::new(5); -let y = x.clone(); -``` - -[arc]: ../std/sync/struct.Arc.html - -When we call `clone()`, the `Arc` needs to update the reference count. Yet -we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take -`&mut 5` or anything. So what gives? - -To understand this, we have to go back to the core of Rust’s guiding -philosophy, memory safety, and the mechanism by which Rust guarantees it, the -[ownership][ownership] system, and more specifically, [borrowing][borrowing]: - -> You may have one or the other of these two kinds of borrows, but not both at -> the same time: -> -> * one or more references (`&T`) to a resource, -> * exactly one mutable reference (`&mut T`). - -[ownership]: ownership.html -[borrowing]: references-and-borrowing.html#borrowing - -So, that’s the real definition of ‘immutability’: is this safe to have two -pointers to? In `Arc`’s case, yes: the mutation is entirely contained inside -the structure itself. It’s not user facing. For this reason, it hands out `&T` -with `clone()`. If it handed out `&mut T`s, though, that would be a problem. - -Other types, like the ones in the [`std::cell`][stdcell] module, have the -opposite: interior mutability. For example: - -```rust -use std::cell::RefCell; - -let x = RefCell::new(42); - -let y = x.borrow_mut(); -``` - -[stdcell]: ../std/cell/index.html - -RefCell hands out `&mut` references to what’s inside of it with the -`borrow_mut()` method. Isn’t that dangerous? What if we do: - -```rust,ignore -use std::cell::RefCell; - -let x = RefCell::new(42); - -let y = x.borrow_mut(); -let z = x.borrow_mut(); -# (y, z); -``` - -This will in fact panic, at runtime. This is what `RefCell` does: it enforces -Rust’s borrowing rules at runtime, and `panic!`s if they’re violated. This -allows us to get around another aspect of Rust’s mutability rules. Let’s talk -about it first. - -## Field-level mutability - -Mutability is a property of either a borrow (`&mut`) or a binding (`let mut`). -This means that, for example, you cannot have a [`struct`][struct] with -some fields mutable and some immutable: - -```rust,ignore -struct Point { - x: i32, - mut y: i32, // Nope. -} -``` - -The mutability of a struct is in its binding: - -```rust,ignore -struct Point { - x: i32, - y: i32, -} - -let mut a = Point { x: 5, y: 6 }; - -a.x = 10; - -let b = Point { x: 5, y: 6}; - -b.x = 10; // Error: cannot assign to immutable field `b.x`. -``` - -[struct]: structs.html - -However, by using [`Cell`][cell], you can emulate field-level mutability: - -```rust -use std::cell::Cell; - -struct Point { - x: i32, - y: Cell, -} - -let point = Point { x: 5, y: Cell::new(6) }; - -point.y.set(7); - -println!("y: {:?}", point.y); -``` - -[cell]: ../std/cell/struct.Cell.html - -This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`. diff --git a/src/doc/book/src/operators-and-overloading.md b/src/doc/book/src/operators-and-overloading.md deleted file mode 100644 index a69cd6adb3b1f..0000000000000 --- a/src/doc/book/src/operators-and-overloading.md +++ /dev/null @@ -1,135 +0,0 @@ -# Operators and Overloading - -Rust allows for a limited form of operator overloading. There are certain -operators that are able to be overloaded. To support a particular operator -between types, there’s a specific trait that you can implement, which then -overloads the operator. - -For example, the `+` operator can be overloaded with the `Add` trait: - -```rust -use std::ops::Add; - -#[derive(Debug)] -struct Point { - x: i32, - y: i32, -} - -impl Add for Point { - type Output = Point; - - fn add(self, other: Point) -> Point { - Point { x: self.x + other.x, y: self.y + other.y } - } -} - -fn main() { - let p1 = Point { x: 1, y: 0 }; - let p2 = Point { x: 2, y: 3 }; - - let p3 = p1 + p2; - - println!("{:?}", p3); -} -``` - -In `main`, we can use `+` on our two `Point`s, since we’ve implemented -`Add` for `Point`. - -There are a number of operators that can be overloaded this way, and all of -their associated traits live in the [`std::ops`][stdops] module. Check out its -documentation for the full list. - -[stdops]: ../std/ops/index.html - -Implementing these traits follows a pattern. Let’s look at [`Add`][add] in more -detail: - -```rust -# mod foo { -pub trait Add { - type Output; - - fn add(self, rhs: RHS) -> Self::Output; -} -# } -``` - -[add]: ../std/ops/trait.Add.html - -There’s three types in total involved here: the type you `impl Add` for, `RHS`, -which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x` -is the `Self` type, `y` is the RHS, and `z` is the `Self::Output` type. - -```rust -# struct Point; -# use std::ops::Add; -impl Add for Point { - type Output = f64; - - fn add(self, rhs: i32) -> f64 { - // Add an i32 to a Point and get an f64. -# 1.0 - } -} -``` - -will let you do this: - -```rust,ignore -let p: Point = // ... -let x: f64 = p + 2i32; -``` - -# Using operator traits in generic structs - -Now that we know how operator traits are defined, we can define our `HasArea` -trait and `Square` struct from the [traits chapter][traits] more generically: - -[traits]: traits.html - -```rust -use std::ops::Mul; - -trait HasArea { - fn area(&self) -> T; -} - -struct Square { - x: T, - y: T, - side: T, -} - -impl HasArea for Square - where T: Mul + Copy { - fn area(&self) -> T { - self.side * self.side - } -} - -fn main() { - let s = Square { - x: 0.0f64, - y: 0.0f64, - side: 12.0f64, - }; - - println!("Area of s: {}", s.area()); -} -``` - -For `HasArea` and `Square`, we declare a type parameter `T` and replace -`f64` with it. The `impl` needs more involved modifications: - -```rust,ignore -impl HasArea for Square - where T: Mul + Copy { ... } -``` - -The `area` method requires that we can multiply the sides, so we declare that -type `T` must implement `std::ops::Mul`. Like `Add`, mentioned above, `Mul` -itself takes an `Output` parameter: since we know that numbers don't change -type when multiplied, we also set it to `T`. `T` must also support copying, so -Rust doesn't try to move `self.side` into the return value. diff --git a/src/doc/book/src/ownership.md b/src/doc/book/src/ownership.md deleted file mode 100644 index 21ebd6333f710..0000000000000 --- a/src/doc/book/src/ownership.md +++ /dev/null @@ -1,295 +0,0 @@ -# Ownership - -This is the first of three sections presenting Rust’s ownership system. This is one of -Rust’s most distinct and compelling features, with which Rust developers should -become quite acquainted. Ownership is how Rust achieves its largest goal, -memory safety. There are a few distinct concepts, each with its own -chapter: - -* ownership, which you’re reading now -* [borrowing][borrowing], and their associated feature ‘references’ -* [lifetimes][lifetimes], an advanced concept of borrowing - -These three chapters are related, and in order. You’ll need all three to fully -understand the ownership system. - -[borrowing]: references-and-borrowing.html -[lifetimes]: lifetimes.html - -# 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 - -[Variable bindings][bindings] have a property in Rust: they ‘have ownership’ -of what they’re bound to. This means that when a binding goes out of scope, -Rust will free the bound resources. For example: - -```rust -fn foo() { - let v = vec![1, 2, 3]; -} -``` - -When `v` comes into scope, a new [vector][vectors] is created on [the stack][stack], -and it allocates space on [the heap][heap] for its elements. When `v` goes out -of scope at the end of `foo()`, Rust will clean up everything related to the -vector, even the heap-allocated memory. This happens deterministically, at the -end of the scope. - -We covered [vectors] in the previous chapter; we use them -here as an example of a type that allocates space on the heap at runtime. They -behave like [arrays], except their size may change by `push()`ing more -elements onto them. - -Vectors have a [generic type][generics] `Vec`, so in this example `v` will have type -`Vec`. We'll cover [generics] in detail in a later chapter. - -[arrays]: primitive-types.html#arrays -[vectors]: vectors.html -[heap]: the-stack-and-the-heap.html#the-heap -[stack]: the-stack-and-the-heap.html#the-stack -[bindings]: variable-bindings.html -[generics]: generics.html - -# Move semantics - -There’s some more subtlety here, though: Rust ensures that there is _exactly -one_ binding to any given resource. For example, if we have a vector, we can -assign it to another binding: - -```rust -let v = vec![1, 2, 3]; - -let v2 = v; -``` - -But, if we try to use `v` afterwards, we get an error: - -```rust,ignore -let v = vec![1, 2, 3]; - -let v2 = v; - -println!("v[0] is: {}", v[0]); -``` - -It looks like this: - -```text -error: use of moved value: `v` -println!("v[0] is: {}", v[0]); - ^ -``` - -A similar thing happens if we define a function which takes ownership, and -try to use something after we’ve passed it as an argument: - -```rust,ignore -fn take(v: Vec) { - // What happens here isn’t important. -} - -let v = vec![1, 2, 3]; - -take(v); - -println!("v[0] is: {}", v[0]); -``` - -Same error: ‘use of moved value’. When we transfer ownership to something else, -we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of -special annotation here, it’s the default thing that Rust does. - -## The details - -The reason that we cannot use a binding after we’ve moved it is subtle, but -important. - -When we write code like this: - -```rust -let x = 10; -``` - -Rust allocates memory for an integer [i32] on the [stack][sh], copies the bit -pattern representing the value of 10 to the allocated memory and binds the -variable name x to this memory region for future reference. - -[i32]: primitive-types.html#numeric-types - -Now consider the following code fragment: - -```rust -let v = vec![1, 2, 3]; - -let mut v2 = v; -``` - -The first line allocates memory for the vector object `v` on the stack like -it does for `x` above. But in addition to that it also allocates some memory -on the [heap][sh] for the actual data (`[1, 2, 3]`). Rust copies the address -of this heap allocation to an internal pointer, which is part of the vector -object placed on the stack (let's call it the data pointer). - -It is worth pointing out (even at the risk of stating the obvious) that the -vector object and its data live in separate memory regions instead of being a -single contiguous memory allocation (due to reasons we will not go into at -this point of time). These two parts of the vector (the one on the stack and -one on the heap) must agree with each other at all times with regards to -things like the length, capacity, etc. - -When we move `v` to `v2`, Rust actually does a bitwise copy of the vector -object `v` into the stack allocation represented by `v2`. This shallow copy -does not create a copy of the heap allocation containing the actual data. -Which means that there would be two pointers to the contents of the vector -both pointing to the same memory allocation on the heap. It would violate -Rust’s safety guarantees by introducing a data race if one could access both -`v` and `v2` at the same time. - -For example if we truncated the vector to just two elements through `v2`: - -```rust -# let v = vec![1, 2, 3]; -# let mut v2 = v; -v2.truncate(2); -``` - -and `v` were still accessible we'd end up with an invalid vector since `v` -would not know that the heap data has been truncated. Now, the part of the -vector `v` on the stack does not agree with the corresponding part on the -heap. `v` still thinks there are three elements in the vector and will -happily let us access the non existent element `v[2]` but as you might -already know this is a recipe for disaster. Especially because it might lead -to a segmentation fault or worse allow an unauthorized user to read from -memory to which they don't have access. - -This is why Rust forbids using `v` after we’ve done the move. - -[sh]: the-stack-and-the-heap.html - -It’s also important to note that optimizations may remove the actual copy of -the bytes on the stack, depending on circumstances. So it may not be as -inefficient as it initially seems. - -## `Copy` types - -We’ve established that when ownership is transferred to another binding, you -cannot use the original binding. However, there’s a [trait][traits] that changes this -behavior, and it’s called `Copy`. We haven’t discussed traits yet, but for now, -you can think of them as an annotation to a particular type that adds extra -behavior. For example: - -```rust -let v = 1; - -let v2 = v; - -println!("v is: {}", v); -``` - -In this case, `v` is an `i32`, which implements the `Copy` trait. This means -that, just like a move, when we assign `v` to `v2`, a copy of the data is made. -But, unlike a move, we can still use `v` afterward. This is because an `i32` -has no pointers to data somewhere else, copying it is a full copy. - -All primitive types implement the `Copy` trait and their ownership is -therefore not moved like one would assume, following the ‘ownership rules’. -To give an example, the two following snippets of code only compile because the -`i32` and `bool` types implement the `Copy` trait. - -```rust -fn main() { - let a = 5; - - let _y = double(a); - println!("{}", a); -} - -fn double(x: i32) -> i32 { - x * 2 -} -``` - -```rust -fn main() { - let a = true; - - let _y = change_truth(a); - println!("{}", a); -} - -fn change_truth(x: bool) -> bool { - !x -} -``` - -If we had used types that do not implement the `Copy` trait, -we would have gotten a compile error because we tried to use a moved value. - -```text -error: use of moved value: `a` -println!("{}", a); - ^ -``` - -We will discuss how to make your own types `Copy` in the [traits][traits] -section. - -[traits]: traits.html - -# More than ownership - -Of course, if we had to hand ownership back with every function we wrote: - -```rust -fn foo(v: Vec) -> Vec { - // Do stuff with `v`. - - // Hand back ownership. - v -} -``` - -This would get very tedious. It gets worse the more things we want to take ownership of: - -```rust -fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // Do stuff with `v1` and `v2`. - - // Hand back ownership, and the result of our function. - (v1, v2, 42) -} - -let v1 = vec![1, 2, 3]; -let v2 = vec![1, 2, 3]; - -let (v1, v2, answer) = foo(v1, v2); -``` - -Ugh! The return type, return line, and calling the function gets way more -complicated. - -Luckily, Rust offers a feature which helps us solve this problem. -It’s called borrowing and is the topic of the next section! - diff --git a/src/doc/book/src/patterns.md b/src/doc/book/src/patterns.md deleted file mode 100644 index 1983927085c14..0000000000000 --- a/src/doc/book/src/patterns.md +++ /dev/null @@ -1,411 +0,0 @@ -# Patterns - -Patterns are quite common in Rust. We use them in [variable -bindings][bindings], [match expressions][match], and other places, too. Let’s go -on a whirlwind tour of all of the things patterns can do! - -[bindings]: variable-bindings.html -[match]: match.html - -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"), -} -``` - -This prints `one`. - -It's possible to create a binding for the value in the any case: - -```rust -let x = 1; - -match x { - y => println!("x: {} y: {}", x, y), -} -``` - -This prints: - -```text -x: 1 y: 1 -``` - -Note it is an error to have both a catch-all `_` and a catch-all binding in the same match block: - -```rust -let x = 1; - -match x { - y => println!("x: {} y: {}", x, y), - _ => println!("anything"), // this causes an error as it is unreachable -} -``` - -There’s one pitfall with patterns: like anything that introduces a new binding, -they introduce shadowing. For example: - -```rust -let x = 1; -let c = 'c'; - -match c { - x => println!("x: {} c: {}", x, c), -} - -println!("x: {}", x) -``` - -This prints: - -```text -x: c c: c -x: 1 -``` - -In other words, `x =>` matches the pattern and introduces a new binding named -`x`. This new binding is in scope for the match arm and takes on the value of -`c`. Notice that the value of `x` outside the scope of the match has no bearing -on the value of `x` within it. Because we already have a binding named `x`, this -new `x` shadows it. - -# Multiple patterns - -You can match multiple patterns with `|`: - -```rust -let x = 1; - -match x { - 1 | 2 => println!("one or two"), - 3 => println!("three"), - _ => println!("anything"), -} -``` - -This prints `one or two`. - -# Destructuring - -If you have a compound data type, like a [`struct`][struct], you can destructure it -inside of a pattern: - -```rust -struct Point { - x: i32, - y: i32, -} - -let origin = Point { x: 0, y: 0 }; - -match origin { - Point { x, y } => println!("({},{})", x, y), -} -``` - -[struct]: structs.html - -We can use `:` to give a value a different name. - -```rust -struct Point { - x: i32, - y: i32, -} - -let origin = Point { x: 0, y: 0 }; - -match origin { - Point { x: x1, y: y1 } => println!("({},{})", x1, y1), -} -``` - -If we only care about some of the values, we don’t have to give them all names: - -```rust -struct Point { - x: i32, - y: i32, -} - -let point = Point { x: 2, y: 3 }; - -match point { - Point { x, .. } => println!("x is {}", x), -} -``` - -This prints `x is 2`. - -You can do this kind of match on any member, not only the first: - -```rust -struct Point { - x: i32, - y: i32, -} - -let point = Point { x: 2, y: 3 }; - -match point { - Point { y, .. } => println!("y is {}", y), -} -``` - -This prints `y is 3`. - -This ‘destructuring’ behavior works on any compound data type, like -[tuples][tuples] or [enums][enums]. - -[tuples]: primitive-types.html#tuples -[enums]: enums.html - -# Ignoring bindings - -You can use `_` in a pattern to disregard the type and value. -For example, here’s a `match` against a `Result`: - -```rust -# let some_value: Result = Err("There was an error"); -match some_value { - Ok(value) => println!("got a value: {}", value), - Err(_) => println!("an error occurred"), -} -``` - -In the first arm, we bind the value inside the `Ok` variant to `value`. But -in the `Err` arm, we use `_` to disregard the specific error, and print -a general error message. - -`_` is valid in any pattern that creates a binding. This can be useful to -ignore parts of a larger structure: - -```rust -fn coordinate() -> (i32, i32, i32) { - // Generate and return some sort of triple tuple. -# (1, 2, 3) -} - -let (x, _, z) = coordinate(); -``` - -Here, we bind the first and last element of the tuple to `x` and `z`, but -ignore the middle element. - -It’s worth noting that using `_` never binds the value in the first place, -which means that the value does not move: - -```rust -let tuple: (u32, String) = (5, String::from("five")); - -// Here, tuple is moved, because the String moved: -let (x, _s) = tuple; - -// The next line would give "error: use of partially moved value: `tuple`". -// println!("Tuple is: {:?}", tuple); - -// However, - -let tuple = (5, String::from("five")); - -// Here, tuple is _not_ moved, as the String was never moved, and u32 is Copy: -let (x, _) = tuple; - -// That means this works: -println!("Tuple is: {:?}", tuple); -``` - -This also means that any temporary variables will be dropped at the end of the -statement: - -```rust -// Here, the String created will be dropped immediately, as it’s not bound: - -let _ = String::from(" hello ").trim(); -``` - -You can also use `..` in a pattern to disregard multiple values: - -```rust -enum OptionalTuple { - Value(i32, i32, i32), - Missing, -} - -let x = OptionalTuple::Value(5, -2, 3); - -match x { - OptionalTuple::Value(..) => println!("Got a tuple!"), - OptionalTuple::Missing => println!("No such luck."), -} -``` - -This prints `Got a tuple!`. - -# ref and ref mut - -If you want to get a [reference][ref], use the `ref` keyword: - -```rust -let x = 5; - -match x { - ref r => println!("Got a reference to {}", r), -} -``` - -This prints `Got a reference to 5`. - -[ref]: references-and-borrowing.html - -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), -} -``` - -# Ranges - -You can match a range of values with `...`: - -```rust -let x = 1; - -match x { - 1 ... 5 => println!("one through five"), - _ => println!("anything"), -} -``` - -This prints `one through five`. - -Ranges are mostly used with integers and `char`s: - -```rust -let x = '💅'; - -match x { - 'a' ... 'j' => println!("early letter"), - 'k' ... 'z' => println!("late letter"), - _ => println!("something else"), -} -``` - -This prints `something else`. - -# Bindings - -You can bind values to names with `@`: - -```rust -let x = 1; - -match x { - e @ 1 ... 5 => println!("got a range element {}", e), - _ => println!("anything"), -} -``` - -This prints `got a range element 1`. This is useful when you want to -do a complicated match of part of a data structure: - -```rust -#[derive(Debug)] -struct Person { - name: Option, -} - -let name = "Steve".to_string(); -let x: Option = Some(Person { name: Some(name) }); -match x { - Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a), - _ => {} -} -``` - -This prints `Some("Steve")`: we’ve bound the inner `name` to `a`. - -If you use `@` with `|`, you need to make sure the name is bound in each part -of the pattern: - -```rust -let x = 5; - -match x { - e @ 1 ... 5 | e @ 8 ... 10 => println!("got a range element {}", e), - _ => println!("anything"), -} -``` - -# Guards - -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."), -} -``` - -This prints `Got an int!`. - -If you’re using `if` with multiple patterns, the `if` applies to both sides: - -```rust -let x = 4; -let y = false; - -match x { - 4 | 5 if y => println!("yes"), - _ => println!("no"), -} -``` - -This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to -only the `5`. In other words, the precedence of `if` behaves like this: - -```text -(4 | 5) if y => ... -``` - -not this: - -```text -4 | (5 if y) => ... -``` - -# Mix and Match - -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/book/src/primitive-types.md b/src/doc/book/src/primitive-types.md deleted file mode 100644 index 8fd3d17c15e57..0000000000000 --- a/src/doc/book/src/primitive-types.md +++ /dev/null @@ -1,305 +0,0 @@ -# Primitive Types - -The Rust language has a number of types that are considered ‘primitive’. This -means that they’re built-in to the language. Rust is structured in such a way -that the standard library also provides a number of useful types built on top -of these ones, as well, but these are the most primitive. - -# Booleans - -Rust has a built-in boolean type, named `bool`. It has two values, `true` and `false`: - -```rust -let x = true; - -let y: bool = false; -``` - -A common use of booleans is in [`if` conditionals][if]. - -[if]: if.html - -You can find more documentation for `bool`s [in the standard library -documentation][bool]. - -[bool]: ../std/primitive.bool.html - -# `char` - -The `char` type represents a single Unicode scalar value. You can create `char`s -with a single tick: (`'`) - -```rust -let x = 'x'; -let two_hearts = '💕'; -``` - -Unlike some other languages, this means that Rust’s `char` is not a single byte, -but four. - -You can find more documentation for `char`s [in the standard library -documentation][char]. - -[char]: ../std/primitive.char.html - -# Numeric types - -Rust has a variety of numeric types in a few categories: signed and unsigned, -fixed and variable, floating-point and integer. - -These types consist of two parts: the category, and the size. For example, -`u16` is an unsigned type with sixteen bits of size. More bits lets you have -bigger numbers. - -If a number literal has nothing to cause its type to be inferred, it defaults: - -```rust -let x = 42; // `x` has type `i32`. - -let y = 1.0; // `y` has type `f64`. -``` - -Here’s a list of the different numeric types, with links to their documentation -in the standard library: - -* [i8](../std/primitive.i8.html) -* [i16](../std/primitive.i16.html) -* [i32](../std/primitive.i32.html) -* [i64](../std/primitive.i64.html) -* [u8](../std/primitive.u8.html) -* [u16](../std/primitive.u16.html) -* [u32](../std/primitive.u32.html) -* [u64](../std/primitive.u64.html) -* [isize](../std/primitive.isize.html) -* [usize](../std/primitive.usize.html) -* [f32](../std/primitive.f32.html) -* [f64](../std/primitive.f64.html) - -Let’s go over them by category: - -## Signed and Unsigned - -Integer types come in two varieties: signed and unsigned. To understand the -difference, let’s consider a number with four bits of size. A signed, four-bit -number would let you store numbers from `-8` to `+7`. Signed numbers use -“two’s complement representation”. An unsigned four bit number, since it does -not need to store negatives, can store values from `0` to `+15`. - -Unsigned types use a `u` for their category, and signed types use `i`. The `i` -is for ‘integer’. So `u8` is an eight-bit unsigned number, and `i8` is an -eight-bit signed number. - -## Fixed-size types - -Fixed-size types have a specific number of bits in their representation. Valid -bit sizes are `8`, `16`, `32`, and `64`. So, `u32` is an unsigned, 32-bit integer, -and `i64` is a signed, 64-bit integer. - -## Variable-size types - -Rust also provides types whose particular size depends on the underlying machine -architecture. Their range is sufficient to express the size of any collection, so -these types have ‘size’ as the category. They come in signed and unsigned varieties -which account for two types: `isize` and `usize`. - -## Floating-point types - -Rust also has two floating point types: `f32` and `f64`. These correspond to -IEEE-754 single and double precision numbers. - -# 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]; // m: [i32; 3] -``` - -Arrays have type `[T; N]`. We’ll talk about this `T` notation [in the generics -section][generics]. The `N` is a compile-time constant, for the length of the -array. - -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] -``` - -You can get the number of elements in an array `a` with `a.len()`: - -```rust -let a = [1, 2, 3]; - -println!("a has {} elements", a.len()); -``` - -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. - -You can find more documentation for `array`s [in the standard library -documentation][array]. - -[array]: ../std/primitive.array.html - -# Slices - -A ‘slice’ is a reference to (or “view” into) another data structure. They are -useful for allowing safe, efficient access to a portion of an array without -copying. For example, you might want to reference only one line of a file read -into memory. By nature, a slice is not created directly, but from an existing -variable binding. Slices have a defined length, and can be mutable or immutable. - -Internally, slices are represented as a pointer to the beginning of the data -and a length. - -## Slicing syntax - -You can use a combo of `&` and `[]` to create a slice from various things. The -`&` indicates that slices are similar to [references], which we will cover in -detail later in this section. The `[]`s, with a range, let you define the -length of the slice: - -```rust -let a = [0, 1, 2, 3, 4]; -let complete = &a[..]; // A slice containing all of the elements in `a`. -let middle = &a[1..4]; // A slice of `a`: only the elements `1`, `2`, and `3`. -``` - -Slices have type `&[T]`. We’ll talk about that `T` when we cover -[generics][generics]. - -[generics]: generics.html - -You can find more documentation for slices [in the standard library -documentation][slice]. - -[slice]: ../std/primitive.slice.html - -# `str` - -Rust’s `str` type is the most primitive string type. As an [unsized type][dst], -it’s not very useful by itself, but becomes useful when placed behind a -reference, like `&str`. We'll elaborate further when we cover -[Strings][strings] and [references]. - -[dst]: unsized-types.html -[strings]: strings.html -[references]: references-and-borrowing.html - -You can find more documentation for `str` [in the standard library -documentation][str]. - -[str]: ../std/primitive.str.html - -# Tuples - -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 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. -In systems programming languages, strings are a bit more complex than in other -languages. For now, read `&str` as a *string slice*, and we’ll learn more -soon. - -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. - -[arity]: glossary.html#arity - -```rust -let mut x = (1, 2); // x: (i32, i32) -let y = (2, 3); // y: (i32, i32) - -x = y; -``` - -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][let] when I said the left-hand side of a `let` statement was more -powerful than 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. - -[let]: variable-bindings.html - -This pattern is very powerful, and we’ll see it repeated more later. - -You can disambiguate a single-element tuple from a value in parentheses with a -comma: - -```rust -(0,); // A single-element tuple. -(0); // A zero in parentheses. -``` - -## Tuple Indexing - -You can also access fields of a tuple with indexing syntax: - - -```rust -let tuple = (1, 2, 3); - -let x = tuple.0; -let y = tuple.1; -let z = tuple.2; - -println!("x is {}", x); -``` - -Like array indexing, it starts at zero, but unlike array indexing, it uses a -`.`, rather than `[]`s. - -You can find more documentation for tuples [in the standard library -documentation][tuple]. - -[tuple]: ../std/primitive.tuple.html - -# Functions - -Functions also have a type! They look like this: - -```rust -fn foo(x: i32) -> i32 { x } - -let x: fn(i32) -> i32 = foo; -``` - -In this case, `x` is a ‘function pointer’ to a function that takes an `i32` and -returns an `i32`. diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md deleted file mode 100644 index e02b5a6cdd79b..0000000000000 --- a/src/doc/book/src/procedural-macros.md +++ /dev/null @@ -1,286 +0,0 @@ -# Procedural Macros (and custom Derive) - -As you've seen throughout the rest of the book, Rust provides a mechanism -called "derive" that lets you implement traits easily. For example, - -```rust -#[derive(Debug)] -struct Point { - x: i32, - y: i32, -} -``` - -is a lot simpler than - -```rust -struct Point { - x: i32, - y: i32, -} - -use std::fmt; - -impl fmt::Debug for Point { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y) - } -} -``` - -Rust includes several traits that you can derive, but it also lets you define -your own. We can accomplish this task through a feature of Rust called -"procedural macros." Eventually, procedural macros will allow for all sorts of -advanced metaprogramming in Rust, but today, they're only for custom derive. - -Let's build a very simple trait, and derive it with custom derive. - -## Hello World - -So the first thing we need to do is start a new crate for our project. - -```bash -$ cargo new --bin hello-world -``` - -All we want is to be able to call `hello_world()` on a derived type. Something -like this: - -```rust,ignore -#[derive(HelloWorld)] -struct Pancakes; - -fn main() { - Pancakes::hello_world(); -} -``` - -With some kind of nice output, like `Hello, World! My name is Pancakes.`. - -Let's go ahead and write up what we think our macro will look like from a user -perspective. In `src/main.rs` we write: - -```rust,ignore -#[macro_use] -extern crate hello_world_derive; - -trait HelloWorld { - fn hello_world(); -} - -#[derive(HelloWorld)] -struct FrenchToast; - -#[derive(HelloWorld)] -struct Waffles; - -fn main() { - FrenchToast::hello_world(); - Waffles::hello_world(); -} -``` - -Great. So now we just need to actually write the procedural macro. At the -moment, procedural macros need to be in their own crate. Eventually, this -restriction may be lifted, but for now, it's required. As such, there's a -convention; for a crate named `foo`, a custom derive procedural macro is called -`foo-derive`. Let's start a new crate called `hello-world-derive` inside our -`hello-world` project. - -```bash -$ cargo new hello-world-derive -``` - -To make sure that our `hello-world` crate is able to find this new crate we've -created, we'll add it to our toml: - -```toml -[dependencies] -hello-world-derive = { path = "hello-world-derive" } -``` - -As for the source of our `hello-world-derive` crate, here's an example: - -```rust,ignore -extern crate proc_macro; -extern crate syn; -#[macro_use] -extern crate quote; - -use proc_macro::TokenStream; - -#[proc_macro_derive(HelloWorld)] -pub fn hello_world(input: TokenStream) -> TokenStream { - // Construct a string representation of the type definition - let s = input.to_string(); - - // Parse the string representation - let ast = syn::parse_macro_input(&s).unwrap(); - - // Build the impl - let gen = impl_hello_world(&ast); - - // Return the generated impl - gen.parse().unwrap() -} -``` - -So there is a lot going on here. We have introduced two new crates: [`syn`] and -[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted -to a `String`. This `String` is a string representation of the Rust code for which -we are deriving `HelloWorld`. At the moment, the only thing you can do with a -`TokenStream` is convert it to a string. A richer API will exist in the future. - -So what we really need is to be able to _parse_ Rust code into something -usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust -code. The other crate we've introduced is `quote`. It's essentially the dual of -`syn` as it will make generating Rust code really easy. We could write this -stuff on our own, but it's much simpler to use these libraries. Writing a full -parser for Rust code is no simple task. - -[`syn`]: https://crates.io/crates/syn -[`quote`]: https://crates.io/crates/quote - -The comments seem to give us a pretty good idea of our overall strategy. We -are going to take a `String` of the Rust code for the type we are deriving, parse -it using `syn`, construct the implementation of `hello_world` (using `quote`), -then pass it back to Rust compiler. - -One last note: you'll see some `unwrap()`s there. If you want to provide an -error for a procedural macro, then you should `panic!` with the error message. -In this case, we're keeping it as simple as possible. - -Great, so let's write `impl_hello_world(&ast)`. - -```rust,ignore -fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { - let name = &ast.ident; - quote! { - impl HelloWorld for #name { - fn hello_world() { - println!("Hello, World! My name is {}", stringify!(#name)); - } - } - } -} -``` - -So this is where quotes comes in. The `ast` argument is a struct that gives us -a representation of our type (which can be either a `struct` or an `enum`). -Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html), -there is some useful information there. We are able to get the name of the -type using `ast.ident`. The `quote!` macro lets us write up the Rust code -that we wish to return and convert it into `Tokens`. `quote!` lets us use some -really cool templating mechanics; we simply write `#name` and `quote!` will -replace it with the variable named `name`. You can even do some repetition -similar to regular macros work. You should check out the -[docs](https://docs.rs/quote) for a good introduction. - -So I think that's it. Oh, well, we do need to add dependencies for `syn` and -`quote` in the `cargo.toml` for `hello-world-derive`. - -```toml -[dependencies] -syn = "0.10.5" -quote = "0.3.10" -``` - -That should be it. Let's try to compile `hello-world`. - -```bash -error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> hello-world-derive/src/lib.rs:8:3 - | -8 | #[proc_macro_derive(HelloWorld)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` - -Oh, so it appears that we need to declare that our `hello-world-derive` crate is -a `proc-macro` crate type. How do we do this? Like this: - -```toml -[lib] -proc-macro = true -``` - -Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: - -```bash -Hello, World! My name is FrenchToast -Hello, World! My name is Waffles -``` - -We've done it! - -## Custom Attributes - -In some cases it might make sense to allow users some kind of configuration. -For example, the user might want to overwrite the name that is printed in the `hello_world()` method. - -This can be achieved with custom attributes: - -```rust,ignore -#[derive(HelloWorld)] -#[HelloWorldName = "the best Pancakes"] -struct Pancakes; - -fn main() { - Pancakes::hello_world(); -} -``` - -If we try to compile this though, the compiler will respond with an error: - -```bash -error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) -``` - -The compiler needs to know that we're handling this attribute and to not respond with an error. -This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute: - -```rust,ignore -#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] -pub fn hello_world(input: TokenStream) -> TokenStream -``` - -Multiple attributes can be specified that way. - -## Raising Errors - -Let's assume that we do not want to accept enums as input to our custom derive method. - -This condition can be easily checked with the help of `syn`. -But how do we tell the user, that we do not accept enums? -The idiomatic way to report errors in procedural macros is to panic: - -```rust,ignore -fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { - let name = &ast.ident; - // Check if derive(HelloWorld) was specified for a struct - if let syn::Body::Struct(_) = ast.body { - // Yes, this is a struct - quote! { - impl HelloWorld for #name { - fn hello_world() { - println!("Hello, World! My name is {}", stringify!(#name)); - } - } - } - } else { - //Nope. This is an Enum. We cannot handle these! - panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); - } -} -``` - -If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error: - -```bash -error: custom derive attribute panicked - --> src/main.rs - | - | #[derive(HelloWorld)] - | ^^^^^^^^^^ - | - = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums! -``` diff --git a/src/doc/book/src/raw-pointers.md b/src/doc/book/src/raw-pointers.md deleted file mode 100644 index 1f75665f4b8c3..0000000000000 --- a/src/doc/book/src/raw-pointers.md +++ /dev/null @@ -1,121 +0,0 @@ -# Raw Pointers - -Rust has a number of different smart pointer types in its standard library, but -there are two types that are extra-special. Much of Rust’s safety comes from -compile-time checks, but raw pointers don’t have such guarantees, and are -[unsafe][unsafe] to use. - -`*const T` and `*mut T` are called ‘raw pointers’ in Rust. Sometimes, when -writing certain kinds of libraries, you’ll need to get around Rust’s safety -guarantees for some reason. In this case, you can use raw pointers to implement -your library, while exposing a safe interface for your users. For example, `*` -pointers are allowed to alias, allowing them to be used to write -shared-ownership types, and even thread-safe shared memory types (the `Rc` -and `Arc` types are both implemented entirely in Rust). - -Here are some things to remember about raw pointers that are different than -other pointer types. 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`. - -# Basics - -Creating a raw pointer is perfectly safe: - -```rust -let x = 5; -let raw = &x as *const i32; - -let mut y = 10; -let raw_mut = &mut y as *mut i32; -``` - -However, dereferencing one is not. This won’t work: - -```rust,ignore -let x = 5; -let raw = &x as *const i32; - -println!("raw points at {}", *raw); -``` - -It gives this error: - -```text -error: dereference of raw pointer requires unsafe function or block [E0133] - println!("raw points at {}", *raw); - ^~~~ -``` - -When you dereference a raw pointer, you’re taking responsibility that it’s not -pointing somewhere that would be incorrect. As such, you need `unsafe`: - -```rust -let x = 5; -let raw = &x as *const i32; - -let points_at = unsafe { *raw }; - -println!("raw points at {}", points_at); -``` - -For more operations on raw pointers, see [their API documentation][rawapi]. - -[unsafe]: unsafe.html -[rawapi]: ../std/primitive.pointer.html - -# FFI - -Raw pointers are useful for FFI: Rust’s `*const T` and `*mut T` are similar to -C’s `const T*` and `T*`, respectively. For more about this use, consult the -[FFI chapter][ffi]. - -[ffi]: ffi.html - -# 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: - -```rust -// Explicit cast: -let i: u32 = 1; -let p_imm: *const u32 = &i as *const u32; - -// Implicit coercion: -let mut m: u32 = 2; -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`). diff --git a/src/doc/book/src/references-and-borrowing.md b/src/doc/book/src/references-and-borrowing.md deleted file mode 100644 index f01aa45385acf..0000000000000 --- a/src/doc/book/src/references-and-borrowing.md +++ /dev/null @@ -1,411 +0,0 @@ -# References and Borrowing - -This is the second of three sections presenting Rust’s ownership system. This is one of -Rust’s most distinct and compelling features, with which Rust developers should -become quite acquainted. Ownership is how Rust achieves its largest goal, -memory safety. There are a few distinct concepts, each with its own -chapter: - -* [ownership][ownership], the key concept -* borrowing, which you’re reading now -* [lifetimes][lifetimes], an advanced concept of borrowing - -These three chapters are related, and in order. You’ll need all three to fully -understand the ownership system. - -[ownership]: ownership.html -[lifetimes]: lifetimes.html - -# 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 borrowing. - -# Borrowing - -At the end of the [ownership][ownership] section, we had a nasty function that looked -like this: - -```rust -fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // Do stuff with `v1` and `v2`. - - // Hand back ownership, and the result of our function. - (v1, v2, 42) -} - -let v1 = vec![1, 2, 3]; -let v2 = vec![1, 2, 3]; - -let (v1, v2, answer) = foo(v1, v2); -``` - -This is not idiomatic Rust, however, as it doesn’t take advantage of borrowing. Here’s -the first step: - -```rust -fn foo(v1: &Vec, v2: &Vec) -> i32 { - // Do stuff with `v1` and `v2`. - - // Return the answer. - 42 -} - -let v1 = vec![1, 2, 3]; -let v2 = vec![1, 2, 3]; - -let answer = foo(&v1, &v2); - -// We can use `v1` and `v2` here! -``` - -A more concrete example: - -```rust -fn main() { - // Don't worry if you don't understand how `fold` works, the point here is that an immutable reference is borrowed. - fn sum_vec(v: &Vec) -> i32 { - return v.iter().fold(0, |a, &b| a + b); - } - // Borrow two vectors and sum them. - // This kind of borrowing does not allow mutation through the borrowed reference. - fn foo(v1: &Vec, v2: &Vec) -> i32 { - // Do stuff with `v1` and `v2`. - let s1 = sum_vec(v1); - let s2 = sum_vec(v2); - // Return the answer. - s1 + s2 - } - - let v1 = vec![1, 2, 3]; - let v2 = vec![4, 5, 6]; - - let answer = foo(&v1, &v2); - println!("{}", answer); -} -``` - -Instead of taking `Vec`s as our arguments, we take a reference: -`&Vec`. And instead of passing `v1` and `v2` directly, we pass `&v1` and -`&v2`. We call the `&T` type a ‘reference’, and rather than owning the resource, -it borrows ownership. A binding that borrows something does not deallocate the -resource when it goes out of scope. This means that after the call to `foo()`, -we can use our original bindings again. - -References are immutable, like bindings. This means that inside of `foo()`, -the vectors can’t be changed at all: - -```rust,ignore -fn foo(v: &Vec) { - v.push(5); -} - -let v = vec![]; - -foo(&v); -``` - -will give us this error: - -```text -error: cannot borrow immutable borrowed content `*v` as mutable -v.push(5); -^ -``` - -Pushing a value mutates the vector, and so we aren’t allowed to do it. - -# &mut references - -There’s a second kind of reference: `&mut T`. A ‘mutable reference’ allows you -to mutate the resource you’re borrowing. For example: - -```rust -let mut x = 5; -{ - let y = &mut x; - *y += 1; -} -println!("{}", x); -``` - -This will print `6`. We make `y` a mutable reference to `x`, then add one to -the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well. -If it wasn’t, we couldn’t take a mutable borrow to an immutable value. - -You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`, -this is because `y` is a `&mut` reference. You'll need to use asterisks to -access the contents of a reference as well. - -Otherwise, `&mut` references are like references. There _is_ a large -difference between the two, and how they interact, though. You can tell -something is fishy in the above example, because we need that extra scope, with -the `{` and `}`. If we remove them, we get an error: - -```text -error: cannot borrow `x` as immutable because it is also borrowed as mutable - println!("{}", x); - ^ -note: previous borrow of `x` occurs here; the mutable borrow prevents -subsequent moves, borrows, or modification of `x` until the borrow ends - let y = &mut x; - ^ -note: previous borrow ends here -fn main() { - -} -^ -``` - -As it turns out, there are rules. - -# The Rules - -Here are the rules for borrowing in Rust: - -First, any borrow must last for a scope no greater than that of the owner. -Second, you may have one or the other of these two kinds of borrows, but not -both at the same time: - -* one or more references (`&T`) to a resource, -* exactly one mutable reference (`&mut T`). - - -You may notice that this is very similar to, though not exactly the same as, -the definition of a data race: - -> There is a ‘data race’ when two or more pointers access the same memory -> location at the same time, where at least one of them is writing, and the -> operations are not synchronized. - -With references, you may have as many as you’d like, since none of them are -writing. However, as we can only have one `&mut` at a time, it is impossible to -have a data race. This is how Rust prevents data races at compile time: we’ll -get errors if we break the rules. - -With this in mind, let’s consider our example again. - -## Thinking in scopes - -Here’s the code: - -```rust,ignore -fn main() { - let mut x = 5; - let y = &mut x; - - *y += 1; - - println!("{}", x); -} -``` - -This code gives us this error: - -```text -error: cannot borrow `x` as immutable because it is also borrowed as mutable - println!("{}", x); - ^ -``` - -This is because we’ve violated the rules: we have a `&mut T` pointing to `x`, -and so we aren’t allowed to create any `&T`s. It's one or the other. The note -hints at how to think about this problem: - -```text -note: previous borrow ends here -fn main() { - -} -^ -``` - -In other words, the mutable borrow is held through the rest of our example. What -we want is for the mutable borrow by `y` to end so that the resource can be -returned to the owner, `x`. `x` can then provide an immutable borrow to `println!`. -In Rust, borrowing is tied to the scope that the borrow is valid for. And our -scopes look like this: - -```rust,ignore -fn main() { - let mut x = 5; - - let y = &mut x; // -+ &mut borrow of `x` starts here. - // | - *y += 1; // | - // | - println!("{}", x); // -+ - Try to borrow `x` here. -} // -+ &mut borrow of `x` ends here. - -``` - -The scopes conflict: we can’t make an `&x` while `y` is in scope. - -So when we add the curly braces: - -```rust -let mut x = 5; - -{ - let y = &mut x; // -+ &mut borrow starts here. - *y += 1; // | -} // -+ ... and ends here. - -println!("{}", x); // <- Try to borrow `x` here. -``` - -There’s no problem. Our mutable borrow goes out of scope before we create an -immutable one. So scope is the key to seeing how long a borrow lasts for. - -## Issues borrowing prevents - -Why have these restrictive rules? Well, as we noted, these rules prevent data -races. What kinds of issues do data races cause? Here are a few. - -### Iterator invalidation - -One example is ‘iterator invalidation’, which happens when you try to mutate a -collection that you’re iterating over. Rust’s borrow checker prevents this from -happening: - -```rust -let mut v = vec![1, 2, 3]; - -for i in &v { - println!("{}", i); -} -``` - -This prints out one through three. As we iterate through the vector, we’re -only given references to the elements. And `v` is itself borrowed as immutable, -which means we can’t change it while we’re iterating: - -```rust,ignore -let mut v = vec![1, 2, 3]; - -for i in &v { - println!("{}", i); - v.push(34); -} -``` - -Here’s the error: - -```text -error: cannot borrow `v` as mutable because it is also borrowed as immutable - v.push(34); - ^ -note: previous borrow of `v` occurs here; the immutable borrow prevents -subsequent moves or mutable borrows of `v` until the borrow ends -for i in &v { - ^ -note: previous borrow ends here -for i in &v { - println!(“{}”, i); - v.push(34); -} -^ -``` - -We can’t modify `v` because it’s borrowed by the loop. - -### Use after free - -References must not live longer than the resource they refer to. Rust will -check the scopes of your references to ensure that this is true. - -If Rust didn’t check this property, we could accidentally use a reference -which was invalid. For example: - -```rust,ignore -let y: &i32; -{ - let x = 5; - y = &x; -} - -println!("{}", y); -``` - -We get this error: - -```text -error: `x` does not live long enough - y = &x; - ^ -note: reference must be valid for the block suffix following statement 0 at -2:16... -let y: &i32; -{ - let x = 5; - y = &x; -} - -note: ...but borrowed value is only valid for the block suffix following -statement 0 at 4:18 - let x = 5; - y = &x; -} -``` - -In other words, `y` is only valid for the scope where `x` exists. As soon as -`x` goes away, it becomes invalid to refer to it. As such, the error says that -the borrow ‘doesn’t live long enough’ because it’s not valid for the right -amount of time. - -The same problem occurs when the reference is declared _before_ the variable it -refers to. This is because resources within the same scope are freed in the -opposite order they were declared: - -```rust,ignore -let y: &i32; -let x = 5; -y = &x; - -println!("{}", y); -``` - -We get this error: - -```text -error: `x` does not live long enough -y = &x; - ^ -note: reference must be valid for the block suffix following statement 0 at -2:16... - let y: &i32; - let x = 5; - y = &x; - - println!("{}", y); -} - -note: ...but borrowed value is only valid for the block suffix following -statement 1 at 3:14 - let x = 5; - y = &x; - - println!("{}", y); -} -``` - -In the above example, `y` is declared before `x`, meaning that `y` lives longer -than `x`, which is not allowed. diff --git a/src/doc/book/src/release-channels.md b/src/doc/book/src/release-channels.md deleted file mode 100644 index af89ca8348424..0000000000000 --- a/src/doc/book/src/release-channels.md +++ /dev/null @@ -1,68 +0,0 @@ -# Release Channels - -The Rust project uses a concept called ‘release channels’ to manage releases. -It’s important to understand this process to choose which version of Rust -your project should use. - -# Overview - -There are three channels for Rust releases: - -* Nightly -* Beta -* Stable - -New nightly releases are created once a day. Every six weeks, the latest -nightly release is promoted to ‘Beta’. At that point, it will only receive -patches to fix serious errors. Six weeks later, the beta is promoted to -‘Stable’, and becomes the next release of `1.x`. - -This process happens in parallel. So every six weeks, on the same day, -nightly goes to beta, beta goes to stable. When `1.x` is released, at -the same time, `1.(x + 1)-beta` is released, and the nightly becomes the -first version of `1.(x + 2)-nightly`. - -# Choosing a version - -Generally speaking, unless you have a specific reason, you should be using the -stable release channel. These releases are intended for a general audience. - -However, depending on your interest in Rust, you may choose to use nightly -instead. The basic tradeoff is this: in the nightly channel, you can use -unstable, new Rust features. However, unstable features are subject to change, -and so any new nightly release may break your code. If you use the stable -release, you cannot use experimental features, but the next release of Rust -will not cause significant issues through breaking changes. - -# Helping the ecosystem through CI - -What about beta? We encourage all Rust users who use the stable release channel -to also test against the beta channel in their continuous integration systems. -This will help alert the team in case there’s an accidental regression. - -Additionally, testing against nightly can catch regressions even sooner, and so -if you don’t mind a third build, we’d appreciate testing against all channels. - -As an example, many Rust programmers use [Travis](https://travis-ci.org/) to -test their crates, which is free for open source projects. Travis [supports -Rust directly][travis], and you can use a `.travis.yml` file like this to -test on all channels: - -```yaml -language: rust -rust: - - nightly - - beta - - stable - -matrix: - allow_failures: - - rust: nightly -``` - -[travis]: http://docs.travis-ci.com/user/languages/rust/ - -With this configuration, Travis will test all three channels, but if something -breaks on nightly, it won’t fail your build. A similar configuration is -recommended for any CI system, check the documentation of the one you’re -using for more details. diff --git a/src/doc/book/src/strings.md b/src/doc/book/src/strings.md deleted file mode 100644 index ffc9d2b697684..0000000000000 --- a/src/doc/book/src/strings.md +++ /dev/null @@ -1,195 +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 a valid -encoding of UTF-8 sequences. Additionally, unlike some systems languages, -strings are not NUL-terminated and can contain NUL bytes. - -Rust has two main types of strings: `&str` and `String`. Let’s talk about -`&str` first. These are called ‘string slices’. A string slice has a fixed -size, and cannot be mutated. It is a reference to a sequence of UTF-8 bytes. - -```rust -let greeting = "Hello there."; // greeting: &'static str -``` - -`"Hello there."` is a string literal and its type is `&'static str`. A string -literal is a string slice that is statically allocated, meaning that it’s saved -inside our compiled program, and exists for the entire duration it runs. The -`greeting` binding is a reference to this statically allocated string. Any -function expecting a string slice will also accept a string literal. - -String literals can span multiple lines. There are two forms. The first will -include the newline and the leading spaces: - -```rust -let s = "foo - bar"; - -assert_eq!("foo\n bar", s); -``` - -The second, with a `\`, trims the spaces and the newline: - -```rust -let s = "foo\ - bar"; - -assert_eq!("foobar", s); -``` - -Note that you normally cannot access a `str` directly, but only through a `&str` -reference. This is because `str` is an unsized type which requires additional -runtime information to be usable. For more information see the chapter on -[unsized types][ut]. - -Rust has more than only `&str`s though. 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. - -```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 `&`: - -```rust -fn takes_slice(slice: &str) { - println!("Got: {}", slice); -} - -fn main() { - let s = "Hello".to_string(); - takes_slice(&s); -} -``` - -This coercion does not happen for functions that accept one of `&str`’s traits -instead of `&str`. For example, [`TcpStream::connect`][connect] has a parameter -of type `ToSocketAddrs`. A `&str` is okay but a `String` must be explicitly -converted using `&*`. - -```rust,no_run -use std::net::TcpStream; - -TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str. - -let addr_string = "192.168.0.1:3000".to_string(); -TcpStream::connect(&*addr_string); // Convert `addr_string` to &str. -``` - -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! - -## Indexing - -Because strings are valid UTF-8, they do not support indexing: - -```rust,ignore -let s = "hello"; - -println!("The first letter of s is {}", s[0]); // ERROR!!! -``` - -Usually, access to a vector with `[]` is very fast. But, because each character -in a UTF-8 encoded string can be multiple bytes, you have to walk over the -string to find the nᵗʰ letter of a string. This is a significantly more -expensive operation, and we don’t want to be misleading. Furthermore, ‘letter’ -isn’t something defined in Unicode, exactly. We can choose to look at a string as -individual bytes, or as codepoints: - -```rust -let hachiko = "忠犬ハチ公"; - -for b in hachiko.as_bytes() { - print!("{}, ", b); -} - -println!(""); - -for c in hachiko.chars() { - print!("{}, ", c); -} - -println!(""); -``` - -This prints: - -```text -229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172, -忠, 犬, ハ, チ, 公, -``` - -As you can see, there are more bytes than `char`s. - -You can get something similar to an index like this: - -```rust -# let hachiko = "忠犬ハチ公"; -let dog = hachiko.chars().nth(1); // Kinda like `hachiko[1]`. -``` - -This emphasizes that we have to walk from the beginning of the list of `chars`. - -## Slicing - -You can get a slice of a string with the slicing syntax: - -```rust -let dog = "hachiko"; -let hachi = &dog[0..5]; -``` - -But note that these are _byte_ offsets, not _character_ offsets. So -this will fail at runtime: - -```rust,should_panic -let dog = "忠犬ハチ公"; -let hachi = &dog[0..2]; -``` - -with this error: - -```text -thread 'main' panicked at 'byte index 2 is not a char boundary; it is inside '忠' -(bytes 0..3) of `忠犬ハチ公`' -``` - -## Concatenation - -If you have a `String`, you can concatenate a `&str` to the end of it: - -```rust -let hello = "Hello ".to_string(); -let world = "world!"; - -let hello_world = hello + world; -``` - -But if you have two `String`s, you need an `&`: - -```rust -let hello = "Hello ".to_string(); -let world = "world!".to_string(); - -let hello_world = hello + &world; -``` - -This is because `&String` can automatically coerce to a `&str`. This is a -feature called ‘[`Deref` coercions][dc]’. - -[ut]: unsized-types.html -[dc]: deref-coercions.html -[connect]: ../std/net/struct.TcpStream.html#method.connect diff --git a/src/doc/book/src/structs.md b/src/doc/book/src/structs.md deleted file mode 100644 index 3efa4f0e0a8d8..0000000000000 --- a/src/doc/book/src/structs.md +++ /dev/null @@ -1,279 +0,0 @@ -# Structs - -`struct`s are a way of creating more complex data types. For example, if we were -doing calculations involving coordinates in 2D space, we would need both an `x` -and a `y` value: - -```rust -let origin_x = 0; -let origin_y = 0; -``` - -A `struct` lets us combine these two into a single, unified datatype with `x` -and `y` as field labels: - -```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, `struct`s begin with -a capital letter and are 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 them through dot -notation: `origin.x`. - -The values in `struct`s 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)`. - -Rust does not support field mutability at the language level, so you cannot -write something like this: - -```rust,ignore -struct Point { - mut x: i32, // This causes an error. - y: i32, -} -``` - -Mutability is a property of the binding, not of the structure itself. If you’re -used to field-level mutability, this may seem strange at first, but it -significantly simplifies things. It even lets you make things mutable on a temporary -basis: - -```rust,ignore -struct Point { - x: i32, - y: i32, -} - -fn main() { - let mut point = Point { x: 0, y: 0 }; - - point.x = 5; - - let point = point; // `point` is now immutable. - - point.y = 6; // This causes an error. -} -``` - -Your structure can still contain `&mut` references, which will let -you do some kinds of mutation: - -```rust -struct Point { - x: i32, - y: i32, -} - -struct PointRef<'a> { - x: &'a mut i32, - y: &'a mut i32, -} - -fn main() { - let mut point = Point { x: 0, y: 0 }; - - { - let r = PointRef { x: &mut point.x, y: &mut point.y }; - - *r.x = 5; - *r.y = 6; - } - - assert_eq!(5, point.x); - assert_eq!(6, point.y); -} -``` - -Initialization of a data structure (struct, enum, union) can be simplified when -fields of the data structure are initialized with variables of the same -names as the fields. - -``` -#[derive(Debug)] -struct Person<'a> { - name: &'a str, - age: u8 -} - -fn main() { - // Create struct with field init shorthand - let name = "Peter"; - let age = 27; - let peter = Person { name, age }; - - // Debug-print struct - println!("{:?}", peter); -} -``` - -# Update syntax - -A `struct` can include `..` to indicate that you want to use a copy of some -other `struct` for some of the values. For example: - -```rust -struct Point3d { - x: i32, - y: i32, - z: i32, -} - -let mut point = Point3d { x: 0, y: 0, z: 0 }; -point = Point3d { y: 1, .. point }; -``` - -This gives `point` a new `y`, but keeps the old `x` and `z` values. It doesn’t -have to be the same `struct` either, you can use this syntax when making new -ones, and it will copy the values you don’t specify: - -```rust -# struct Point3d { -# x: i32, -# y: i32, -# z: i32, -# } -let origin = Point3d { x: 0, y: 0, z: 0 }; -let point = Point3d { z: 1, x: 2, .. origin }; -``` - -# Tuple structs - -Rust has another data type that’s like a hybrid between a [tuple][tuple] and a -`struct`, called a ‘tuple struct’. Tuple structs have a name, but their fields -don't. They are declared with the `struct` keyword, and then with a name -followed by a tuple: - -[tuple]: primitive-types.html#tuples - -```rust -struct Color(i32, i32, i32); -struct Point(i32, i32, i32); - -let black = Color(0, 0, 0); -let origin = Point(0, 0, 0); -``` - -Here, `black` and `origin` are not the same type, even though they contain the -same values. - -The members of a tuple struct may be accessed by dot notation or destructuring -`let`, just like regular tuples: - -```rust -# struct Color(i32, i32, i32); -# struct Point(i32, i32, i32); -# let black = Color(0, 0, 0); -# let origin = Point(0, 0, 0); -let black_r = black.0; -let Point(_, origin_y, origin_z) = origin; -``` - -Patterns like `Point(_, origin_y, origin_z)` are also used in -[match expressions][match]. - -One case when a tuple struct is very useful is when it has only one element. -We call this the ‘newtype’ pattern, because it allows you to create a new type -that is distinct from its contained value and also expresses its own semantic -meaning: - -```rust -struct Inches(i32); - -let length = Inches(10); - -let Inches(integer_length) = length; -println!("length is {} inches", integer_length); -``` - -As above, you can extract the inner integer type through a destructuring `let`. -In this case, the `let Inches(integer_length)` assigns `10` to `integer_length`. -We could have used dot notation to do the same thing: - -```rust -# struct Inches(i32); -# let length = Inches(10); -let integer_length = length.0; -``` - -It's always possible to use a `struct` instead of a tuple struct, and can be -clearer. We could write `Color` and `Point` like this instead: - -```rust -struct Color { - red: i32, - blue: i32, - green: i32, -} - -struct Point { - x: i32, - y: i32, - z: i32, -} -``` - -Good names are important, and while values in a tuple struct can be -referenced with dot notation as well, a `struct` gives us actual names, -rather than positions. - -[match]: match.html - -# Unit-like structs - -You can define a `struct` with no members at all: - -```rust,compile_fail,E0423 -struct Electron {} // Use empty braces... -struct Proton; // ...or just a semicolon. - -// Use the same notation when creating an instance. -let x = Electron {}; -let y = Proton; -let z = Electron; // Error -``` - -Such a `struct` is called ‘unit-like’ because it resembles the empty -tuple, `()`, sometimes called ‘unit’. Like a tuple struct, it defines a -new type. - -This is rarely useful on its own (although sometimes it can serve as a -marker type), but in combination with other features, it can become -useful. For instance, a library may ask you to create a structure that -implements a certain [trait][trait] to handle events. If you don’t have -any data you need to store in the structure, you can create a -unit-like `struct`. - -[trait]: traits.html diff --git a/src/doc/book/src/syntax-and-semantics.md b/src/doc/book/src/syntax-and-semantics.md deleted file mode 100644 index aa4c1251024de..0000000000000 --- a/src/doc/book/src/syntax-and-semantics.md +++ /dev/null @@ -1,10 +0,0 @@ -# Syntax and Semantics - -This chapter breaks Rust down into small chunks, one for each concept. - -If you’d like to learn Rust from the bottom up, reading this in order is a -great way to do that. - -These sections also form a reference for each concept, so if you’re reading -another tutorial and find something confusing, you can find it explained -somewhere in here. diff --git a/src/doc/book/src/syntax-index.md b/src/doc/book/src/syntax-index.md deleted file mode 100644 index a06520f4ac2f3..0000000000000 --- a/src/doc/book/src/syntax-index.md +++ /dev/null @@ -1,253 +0,0 @@ -# Syntax Index - -## Keywords - -* `as`: primitive casting, or disambiguating the specific trait containing an item. See [Casting Between Types (`as`)], [Universal Function Call Syntax (Angle-bracket Form)], [Associated Types]. -* `break`: break out of loop. See [Loops (Ending Iteration Early)]. -* `const`: constant items and constant raw pointers. See [`const` and `static`], [Raw Pointers]. -* `continue`: continue to next loop iteration. See [Loops (Ending Iteration Early)]. -* `crate`: external crate linkage. See [Crates and Modules (Importing External Crates)]. -* `else`: fallback for `if` and `if let` constructs. See [`if`], [`if let`]. -* `enum`: defining enumeration. See [Enums]. -* `extern`: external crate, function, and variable linkage. See [Crates and Modules (Importing External Crates)], [Foreign Function Interface]. -* `false`: boolean false literal. See [Primitive Types (Booleans)]. -* `fn`: function definition and function pointer types. See [Functions]. -* `for`: iterator loop, part of trait `impl` syntax, and higher-ranked lifetime syntax. See [Loops (`for`)], [Method Syntax]. -* `if`: conditional branching. See [`if`], [`if let`]. -* `impl`: inherent and trait implementation blocks. See [Method Syntax]. -* `in`: part of `for` loop syntax. See [Loops (`for`)]. -* `let`: variable binding. See [Variable Bindings]. -* `loop`: unconditional, infinite loop. See [Loops (`loop`)]. -* `match`: pattern matching. See [Match]. -* `mod`: module declaration. See [Crates and Modules (Defining Modules)]. -* `move`: part of closure syntax. See [Closures (`move` closures)]. -* `mut`: denotes mutability in pointer types and pattern bindings. See [Mutability]. -* `pub`: denotes public visibility in `struct` fields, `impl` blocks, and modules. See [Crates and Modules (Exporting a Public Interface)]. -* `ref`: by-reference binding. See [Patterns (`ref` and `ref mut`)]. -* `return`: return from function. See [Functions (Early Returns)]. -* `Self`: implementor type alias. See [Traits]. -* `self`: method subject. See [Method Syntax (Method Calls)]. -* `static`: global variable. See [`const` and `static` (`static`)]. -* `struct`: structure definition. See [Structs]. -* `trait`: trait definition. See [Traits]. -* `true`: boolean true literal. See [Primitive Types (Booleans)]. -* `type`: type alias, and associated type definition. See [`type` Aliases], [Associated Types]. -* `unsafe`: denotes unsafe code, functions, traits, and implementations. See [Unsafe]. -* `use`: import symbols into scope. See [Crates and Modules (Importing Modules with `use`)]. -* `where`: type constraint clauses. See [Traits (`where` clause)]. -* `while`: conditional loop. See [Loops (`while`)]. - -## Operators and Symbols - -* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion. See [Macros]. -* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). -* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`). -* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). -* `%=` (`var %= expr`): arithmetic remainder & assignment. Overloadable (`RemAssign`). -* `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`). -* `&` (`&expr`, `&mut expr`): borrow. See [References and Borrowing]. -* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. See [References and Borrowing]. -* `&=` (`var &= expr`): bitwise and & assignment. Overloadable (`BitAndAssign`). -* `&&` (`expr && expr`): logical and. -* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). -* `*` (`*expr`): dereference. -* `*` (`*const type`, `*mut type`): raw pointer. See [Raw Pointers]. -* `*=` (`var *= expr`): arithmetic multiplication & assignment. Overloadable (`MulAssign`). -* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). -* `+` (`trait + trait`, `'a + trait`): compound type constraint. See [Traits (Multiple Trait Bounds)]. -* `+=` (`var += expr`): arithmetic addition & assignment. Overloadable (`AddAssign`). -* `,`: argument and element separator. See [Attributes], [Functions], [Structs], [Generics], [Match], [Closures], [Crates and Modules (Importing Modules with `use`)]. -* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). -* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). -* `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`). -* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures]. -* `.` (`expr.ident`): member access. See [Structs], [Method Syntax]. -* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. -* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)]. -* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)]. -* `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. See [Iterators]. -* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. See [Patterns (Ranges)]. -* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). -* `/=` (`var /= expr`): arithmetic division & assignment. Overloadable (`DivAssign`). -* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits]. -* `:` (`ident: expr`): struct field initializer. See [Structs]. -* `:` (`'a: loop {…}`): loop label. See [Loops (Loops Labels)]. -* `;`: statement and item terminator. -* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)]. -* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). -* `<<=` (`var <<= expr`): left-shift & assignment. Overloadable (`ShlAssign`). -* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`). -* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`). -* `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults. -* `==` (`var == expr`): equality comparison. Overloadable (`PartialEq`). -* `=>` (`pat => expr`): part of match arm syntax. See [Match]. -* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`). -* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`). -* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). -* `>>=` (`var >>= expr`): right-shift & assignment. Overloadable (`ShrAssign`). -* `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)]. -* `^` (`expr ^ expr`): bitwise exclusive or. Overloadable (`BitXor`). -* `^=` (`var ^= expr`): bitwise exclusive or & assignment. Overloadable (`BitXorAssign`). -* `|` (`expr | expr`): bitwise or. Overloadable (`BitOr`). -* `|` (`pat | pat`): pattern alternatives. See [Patterns (Multiple patterns)]. -* `|` (`|…| expr`): closures. See [Closures]. -* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). -* `||` (`expr || expr`): logical or. -* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). -* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro]. - -## Other Syntax - - - -* `'ident`: named lifetime or loop label. See [Lifetimes], [Loops (Loops Labels)]. -* `…u8`, `…i32`, `…f64`, `…usize`, …: numeric literal of specific type. -* `"…"`: string literal. See [Strings]. -* `r"…"`, `r#"…"#`, `r##"…"##`, …: raw string literal, escape characters are not processed. See [Reference (Raw String Literals)]. -* `b"…"`: byte string literal, constructs a `[u8]` instead of a string. See [Reference (Byte String Literals)]. -* `br"…"`, `br#"…"#`, `br##"…"##`, …: raw byte string literal, combination of raw and byte string literal. See [Reference (Raw Byte String Literals)]. -* `'…'`: character literal. See [Primitive Types (`char`)]. -* `b'…'`: ASCII byte literal. -* `|…| expr`: closure. See [Closures]. - - - -* `ident::ident`: path. See [Crates and Modules (Defining Modules)]. -* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). See [Crates and Modules (Re-exporting with `pub use`)]. -* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). See [Crates and Modules (Re-exporting with `pub use`)]. -* `super::path`: path relative to the parent of the current module. See [Crates and Modules (Re-exporting with `pub use`)]. -* `type::ident`, `::ident`: associated constants, functions, and types. See [Associated Types]. -* `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). See [Associated Types]. -* `trait::method(…)`: disambiguating a method call by naming the trait which defines it. See [Universal Function Call Syntax]. -* `type::method(…)`: disambiguating a method call by naming the type for which it's defined. See [Universal Function Call Syntax]. -* `::method(…)`: disambiguating a method call by naming the trait _and_ type. See [Universal Function Call Syntax (Angle-bracket Form)]. - - - -* `path<…>` (*e.g.* `Vec`): specifies parameters to generic type *in a type*. See [Generics]. -* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. See [Generics § Resolving ambiguities](generics.html#resolving-ambiguities). -* `fn ident<…> …`: define generic function. See [Generics]. -* `struct ident<…> …`: define generic structure. See [Generics]. -* `enum ident<…> …`: define generic enumeration. See [Generics]. -* `impl<…> …`: define generic implementation. -* `for<…> type`: higher-ranked lifetime bounds. -* `type` (*e.g.* `Iterator`): a generic type where one or more associated types have specific assignments. See [Associated Types]. - - - -* `T: U`: generic parameter `T` constrained to types that implement `U`. See [Traits]. -* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type 'outlives' the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. -* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones. -* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. -* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. See [Unsized Types (`?Sized`)]. -* `'a + trait`, `trait + trait`: compound type constraint. See [Traits (Multiple Trait Bounds)]. - - - -* `#[meta]`: outer attribute. See [Attributes]. -* `#![meta]`: inner attribute. See [Attributes]. -* `$ident`: macro substitution. See [Macros]. -* `$ident:kind`: macro capture. See [Macros]. -* `$(…)…`: macro repetition. See [Macros]. - - - -* `//`: line comment. See [Comments]. -* `//!`: inner line doc comment. See [Comments]. -* `///`: outer line doc comment. See [Comments]. -* `/*…*/`: block comment. See [Comments]. -* `/*!…*/`: inner block doc comment. See [Comments]. -* `/**…*/`: outer block doc comment. See [Comments]. - - - -* `!`: always empty Never type. See [Diverging Functions]. - - - -* `()`: empty tuple (*a.k.a.* unit), both literal and type. -* `(expr)`: parenthesized expression. -* `(expr,)`: single-element tuple expression. See [Primitive Types (Tuples)]. -* `(type,)`: single-element tuple type. See [Primitive Types (Tuples)]. -* `(expr, …)`: tuple expression. See [Primitive Types (Tuples)]. -* `(type, …)`: tuple type. See [Primitive Types (Tuples)]. -* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. See [Functions]. -* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. See [Macros]. -* `expr.0`, `expr.1`, …: tuple indexing. See [Primitive Types (Tuple Indexing)]. - - - -* `{…}`: block expression. -* `Type {…}`: `struct` literal. See [Structs]. - - - -* `[…]`: array literal. See [Primitive Types (Arrays)]. -* `[expr; len]`: array literal containing `len` copies of `expr`. See [Primitive Types (Arrays)]. -* `[type; len]`: array type containing `len` instances of `type`. See [Primitive Types (Arrays)]. -* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). -* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the "index". - -[`const` and `static` (`static`)]: const-and-static.html#static -[`const` and `static`]: const-and-static.html -[`if let`]: if-let.html -[`if`]: if.html -[`type` Aliases]: type-aliases.html -[Associated Types]: associated-types.html -[Attributes]: attributes.html -[Casting Between Types (`as`)]: casting-between-types.html#as -[Closures (`move` closures)]: closures.html#move-closures -[Closures]: closures.html -[Comments]: comments.html -[Crates and Modules (Defining Modules)]: crates-and-modules.html#defining-modules -[Crates and Modules (Exporting a Public Interface)]: crates-and-modules.html#exporting-a-public-interface -[Crates and Modules (Importing External Crates)]: crates-and-modules.html#importing-external-crates -[Crates and Modules (Importing Modules with `use`)]: crates-and-modules.html#importing-modules-with-use -[Crates and Modules (Re-exporting with `pub use`)]: crates-and-modules.html#re-exporting-with-pub-use -[Diverging Functions]: functions.html#diverging-functions -[Enums]: enums.html -[Foreign Function Interface]: ffi.html -[Functions (Early Returns)]: functions.html#early-returns -[Functions]: functions.html -[Generics]: generics.html -[Iterators]: iterators.html -[`try!` macro]: error-handling.html#the-try-macro -[Lifetimes]: lifetimes.html -[Loops (`for`)]: loops.html#for -[Loops (`loop`)]: loops.html#loop -[Loops (`while`)]: loops.html#while -[Loops (Ending Iteration Early)]: loops.html#ending-iteration-early -[Loops (Loops Labels)]: loops.html#loop-labels -[Macros]: macros.html -[Match]: match.html -[Method Syntax (Method Calls)]: method-syntax.html#method-calls -[Method Syntax]: method-syntax.html -[Mutability]: mutability.html -[Operators and Overloading]: operators-and-overloading.html -[Patterns (`ref` and `ref mut`)]: patterns.html#ref-and-ref-mut -[Patterns (Bindings)]: patterns.html#bindings -[Patterns (Ignoring bindings)]: patterns.html#ignoring-bindings -[Patterns (Multiple patterns)]: patterns.html#multiple-patterns -[Patterns (Ranges)]: patterns.html#ranges -[Primitive Types (`char`)]: primitive-types.html#char -[Primitive Types (Arrays)]: primitive-types.html#arrays -[Primitive Types (Booleans)]: primitive-types.html#booleans -[Primitive Types (Tuple Indexing)]: primitive-types.html#tuple-indexing -[Primitive Types (Tuples)]: primitive-types.html#tuples -[Raw Pointers]: raw-pointers.html -[Reference (Byte String Literals)]: ../reference/tokens.html/#byte-string-literals -[Reference (Integer literals)]: ../reference/tokens.html#integer-literals -[Reference (Raw Byte String Literals)]: ../reference/tokens.html#raw-byte-string-literals -[Reference (Raw String Literals)]: ../reference/tokens.html#raw-string-literals -[References and Borrowing]: references-and-borrowing.html -[Strings]: strings.html -[Structs (Update syntax)]: structs.html#update-syntax -[Structs]: structs.html -[Traits (`where` clause)]: traits.html#where-clause -[Traits (Multiple Trait Bounds)]: traits.html#multiple-trait-bounds -[Traits]: traits.html -[Universal Function Call Syntax]: ufcs.html -[Universal Function Call Syntax (Angle-bracket Form)]: ufcs.html#angle-bracket-form -[Unsafe]: unsafe.html -[Unsized Types (`?Sized`)]: unsized-types.html#sized -[Variable Bindings]: variable-bindings.html diff --git a/src/doc/book/src/testing.md b/src/doc/book/src/testing.md deleted file mode 100644 index b4f580fcdfbef..0000000000000 --- a/src/doc/book/src/testing.md +++ /dev/null @@ -1,633 +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,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - } -} -``` - -For now, let's remove the `mod` bit, and focus on just the function: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -#[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.1.0 (file:///home/you/projects/adder) - Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs - Running target/debug/deps/adder-941f01916ca4a642 - -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 main() { -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,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -#[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 will `panic!`. Let's -run our tests again: - -```bash -$ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs - Running target/debug/deps/adder-941f01916ca4a642 - -running 1 test -test it_works ... FAILED - -failures: - ----- it_works stdout ---- - thread 'it_works' panicked at 'assertion failed: false', src/lib.rs:5 -note: Run with `RUST_BACKTRACE=1` for a backtrace. - - -failures: - it_works - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured - -error: test failed -``` - -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. We can use `$?` on macOS and Linux: - -```bash -$ echo $? -101 -``` - -On Windows, if you’re using `cmd`: - -```bash -> echo %ERRORLEVEL% -``` - -And if you’re using PowerShell: - -```bash -> echo $LASTEXITCODE # the code itself -> echo $? # a boolean, fail or succeed -``` - -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,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -#[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.1.0 (file:///home/you/projects/adder) - Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs - Running target/debug/deps/adder-941f01916ca4a642 - -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,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -#[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.1.0 (file:///home/you/projects/adder) - Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs - Running target/debug/deps/adder-941f01916ca4a642 - -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: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -#[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 -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -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 `ignore` attribute - -Sometimes a few specific tests can be very time-consuming to execute. These -can be disabled by default by using the `ignore` attribute: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[test] -fn it_works() { - assert_eq!(4, add_two(2)); -} - -#[test] -#[ignore] -fn expensive_test() { - // Code that takes an hour to run... -} -``` - -Now we run our tests and see that `it_works` is run, but `expensive_test` is -not: - -```bash -$ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs - Running target/debug/deps/adder-941f01916ca4a642 - -running 2 tests -test expensive_test ... ignored -test it_works ... ok - -test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured - - Doc-tests adder - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -The expensive tests can be run explicitly using `cargo test -- --ignored`: - -```bash -$ cargo test -- --ignored - Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs - Running target/debug/deps/adder-941f01916ca4a642 - -running 1 test -test expensive_test ... 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 -``` - -The `--ignored` argument is an argument to the test binary, and not to Cargo, -which is why the command is `cargo test -- --ignored`. - -# The `tests` module - -There is one way in which our existing example is not idiomatic: it's -missing the `tests` module. You might have noticed this test module was -present in the code that was initially generated with `cargo new` but -was missing from our last example. Let's explain what this does. - -The idiomatic way of writing our example looks like this: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod tests { - 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 tests` 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 the tested function into scope. This can be annoying if you have -a large module, and so this is a common use of globs. Let's change our -`src/lib.rs` to make use of it: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -pub fn add_two(a: i32) -> i32 { - a + 2 -} - -#[cfg(test)] -mod tests { - 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.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a - -running 1 test -test tests::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 `tests` module to hold your "unit-style" -tests. Anything that 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 - -Each file in `tests/*.rs` directory is treated as an individual crate. -To write an integration test, let's make a `tests` directory and -put a `tests/integration_test.rs` file inside with this as its contents: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -# // Sadly, this code will not work in play.rust-lang.org, because we have no -# // crate adder to import. You'll need to try this part on your own machine. -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 each test in the `tests` -directory is 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.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a - -running 1 test -test tests::it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Running target/debug/integration_test-68064b69521c828a - -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. - -Cargo will ignore files in subdirectories of the `tests/` directory. -Therefore shared modules in integrations tests are possible. -For example `tests/common/mod.rs` is not separately compiled by cargo but can -be imported in every test with `mod common;` - -That's all there is to the `tests` directory. The `tests` module isn't needed -here, since the whole thing is focused on tests. - -Note, when building integration tests, cargo will not pass the `test` attribute -to the compiler. It means that all parts in `cfg(test)` won't be included in -the build used in your integration 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 (**note:** this only works in library -crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples: - -```rust,ignore -# // The next line exists to trick play.rust-lang.org into running our code as a -# // test: -# // fn main -# -//! 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 tests { - 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.1.0. (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a - -running 1 test -test tests::it_works ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - - Running target/debug/integration_test-68064b69521c828a - -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. - -We haven’t covered all of the details with writing documentation tests. For more, -please see the [Documentation chapter](documentation.html). - -# Testing and concurrency - -It is important to note that tests are run concurrently using threads. For this -reason, care should be taken to ensure your tests do not depend on each-other, -or on any shared state. "Shared state" can also include the environment, such -as the current working directory, or environment variables. - -If this is an issue it is possible to control this concurrency, either by -setting the environment variable `RUST_TEST_THREADS`, or by passing the argument -`--test-threads` to the tests: - -```bash -$ RUST_TEST_THREADS=1 cargo test # Run tests with no concurrency -... -$ cargo test -- --test-threads=1 # Same as above -... -``` - -# Test output - -By default Rust's test library captures and discards output to standard -out/error, e.g. output from `println!()`. This too can be controlled using the -environment or a switch: - - -```bash -$ RUST_TEST_NOCAPTURE=1 cargo test # Preserve stdout/stderr -... -$ cargo test -- --nocapture # Same as above -... -``` - -However a better method avoiding capture is to use logging rather than raw -output. Rust has a [standard logging API][log], which provides a frontend to -multiple logging implementations. This can be used in conjunction with the -default [env_logger] to output any debugging information in a manner that can be -controlled at runtime. - -[log]: https://crates.io/crates/log -[env_logger]: https://crates.io/crates/env_logger diff --git a/src/doc/book/src/the-stack-and-the-heap.md b/src/doc/book/src/the-stack-and-the-heap.md deleted file mode 100644 index 6866505df1310..0000000000000 --- a/src/doc/book/src/the-stack-and-the-heap.md +++ /dev/null @@ -1,583 +0,0 @@ -# The Stack and the Heap - -As a systems language, Rust operates at a low level. If you’re coming from a -high-level language, there are some aspects of systems programming that you may -not be familiar with. The most important one is how memory works, with a stack -and a heap. If you’re familiar with how C-like languages use stack allocation, -this chapter will be a refresher. If you’re not, you’ll learn about this more -general concept, but with a Rust-y focus. - -As with most things, when learning about them, we’ll use a simplified model to -start. This lets you get a handle on the basics, without getting bogged down -with details which are, for now, irrelevant. The examples we’ll use aren’t 100% -accurate, but are representative for the level we’re trying to learn at right -now. Once you have the basics down, learning more about how allocators are -implemented, virtual memory, and other advanced topics will reveal the leaks in -this particular abstraction. - -# Memory management - -These two terms are about memory management. The stack and the heap are -abstractions that help you determine when to allocate and deallocate memory. - -Here’s a high-level comparison: - -The stack is very fast, and is where memory is allocated in Rust by default. -But the allocation is local to a function call, and is limited in size. The -heap, on the other hand, is slower, and is explicitly allocated by your -program. But it’s effectively unlimited in size, and is globally accessible. -Note this meaning of heap, which allocates arbitrary-sized blocks of memory in arbitrary -order, is quite different from the heap data structure. - -# The Stack - -Let’s talk about this Rust program: - -```rust -fn main() { - let x = 42; -} -``` - -This program has one variable binding, `x`. This memory needs to be allocated -from somewhere. Rust ‘stack allocates’ by default, which means that basic -values ‘go on the stack’. What does that mean? - -Well, when a function gets called, some memory gets allocated for all of its -local variables and some other information. This is called a ‘stack frame’, and -for the purpose of this tutorial, we’re going to ignore the extra information -and only consider the local variables we’re allocating. So in this case, when -`main()` is run, we’ll allocate a single 32-bit integer for our stack frame. -This is automatically handled for you, as you can see; we didn’t have to write -any special Rust code or anything. - -When the function exits, its stack frame gets deallocated. This happens -automatically as well. - -That’s all there is for this simple program. The key thing to understand here -is that stack allocation is very, very fast. Since we know all the local -variables we have ahead of time, we can grab the memory all at once. And since -we’ll throw them all away at the same time as well, we can get rid of it very -fast too. - -The downside is that we can’t keep values around if we need them for longer -than a single function. We also haven’t talked about what the word, ‘stack’, -means. To do that, we need a slightly more complicated example: - -```rust -fn foo() { - let y = 5; - let z = 100; -} - -fn main() { - let x = 42; - - foo(); -} -``` - -This program has three variables total: two in `foo()`, one in `main()`. Just -as before, when `main()` is called, a single integer is allocated for its stack -frame. But before we can show what happens when `foo()` is called, we need to -visualize what’s going on with memory. Your operating system presents a view of -memory to your program that’s pretty simple: a huge list of addresses, from 0 -to a large number, representing how much RAM your computer has. For example, if -you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That -number comes from 230, the number of bytes in a gigabyte. [^gigabyte] - -[^gigabyte]: ‘Gigabyte’ can mean two things: 109, or 230. The IEC standard resolved this by stating that ‘gigabyte’ is 109, and ‘gibibyte’ is 230. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. - -This memory is kind of like a giant array: addresses start at zero and go -up to the final number. So here’s a diagram of our first stack frame: - -| Address | Name | Value | -|---------|------|-------| -| 0 | x | 42 | - -We’ve got `x` located at address `0`, with the value `42`. - -When `foo()` is called, a new stack frame is allocated: - -| Address | Name | Value | -|---------|------|-------| -| 2 | z | 100 | -| 1 | y | 5 | -| 0 | x | 42 | - -Because `0` was taken by the first frame, `1` and `2` are used for `foo()`’s -stack frame. It grows upward, the more functions we call. - - -There are some important things we have to take note of here. The numbers 0, 1, -and 2 are all solely for illustrative purposes, and bear no relationship to the -address values the computer will use in reality. In particular, the series of -addresses are in reality going to be separated by some number of bytes that -separate each address, and that separation may even exceed the size of the -value being stored. - -After `foo()` is over, its frame is deallocated: - -| Address | Name | Value | -|---------|------|-------| -| 0 | x | 42 | - -And then, after `main()`, even this last value goes away. Easy! - -It’s called a ‘stack’ because it works like a stack of dinner plates: the first -plate you put down is the last plate to pick back up. Stacks are sometimes -called ‘last in, first out queues’ for this reason, as the last value you put -on the stack is the first one you retrieve from it. - -Let’s try a three-deep example: - -```rust -fn italic() { - let i = 6; -} - -fn bold() { - let a = 5; - let b = 100; - let c = 1; - - italic(); -} - -fn main() { - let x = 42; - - bold(); -} -``` - -We have some kooky function names to make the diagrams clearer. - -Okay, first, we call `main()`: - -| Address | Name | Value | -|---------|------|-------| -| 0 | x | 42 | - -Next up, `main()` calls `bold()`: - -| Address | Name | Value | -|---------|------|-------| -| **3** | **c**|**1** | -| **2** | **b**|**100**| -| **1** | **a**| **5** | -| 0 | x | 42 | - -And then `bold()` calls `italic()`: - -| Address | Name | Value | -|---------|------|-------| -| *4* | *i* | *6* | -| **3** | **c**|**1** | -| **2** | **b**|**100**| -| **1** | **a**| **5** | -| 0 | x | 42 | - -Whew! Our stack is growing tall. - -After `italic()` is over, its frame is deallocated, leaving only `bold()` and -`main()`: - -| Address | Name | Value | -|---------|------|-------| -| **3** | **c**|**1** | -| **2** | **b**|**100**| -| **1** | **a**| **5** | -| 0 | x | 42 | - -And then `bold()` ends, leaving only `main()`: - -| Address | Name | Value | -|---------|------|-------| -| 0 | x | 42 | - -And then we’re done. Getting the hang of it? It’s like piling up dishes: you -add to the top, you take away from the top. - -# The Heap - -Now, this works pretty well, but not everything can work like this. Sometimes, -you need to pass some memory between different functions, or keep it alive for -longer than a single function’s execution. For this, we can use the heap. - -In Rust, you can allocate memory on the heap with the [`Box` type][box]. -Here’s an example: - -```rust -fn main() { - let x = Box::new(5); - let y = 42; -} -``` - -[box]: ../std/boxed/index.html - -Here’s what happens in memory when `main()` is called: - -| Address | Name | Value | -|---------|------|--------| -| 1 | y | 42 | -| 0 | x | ?????? | - -We allocate space for two variables on the stack. `y` is `42`, as it always has -been, but what about `x`? Well, `x` is a `Box`, and boxes allocate memory -on the heap. The actual value of the box is a structure which has a pointer to -‘the heap’. When we start executing the function, and `Box::new()` is called, -it allocates some memory for the heap, and puts `5` there. The memory now looks -like this: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 5 | -| ... | ... | ... | -| 1 | y | 42 | -| 0 | x | → (230) - 1 | - -We have (230) - 1 addresses in our hypothetical computer with 1GB of RAM. And since -our stack grows from zero, the easiest place to allocate memory is from the -other end. So our first value is at the highest place in memory. And the value -of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve -allocated on the heap, so the value of `x` is (230) - 1, the memory -location we’ve asked for. - -[rawpointer]: raw-pointers.html - -We haven’t really talked too much about what it actually means to allocate and -deallocate memory in these contexts. Getting into very deep detail is out of -the scope of this tutorial, but what’s important to point out here is that -the heap isn’t a stack that grows from the opposite end. We’ll have an -example of this later in the book, but because the heap can be allocated and -freed in any order, it can end up with ‘holes’. Here’s a diagram of the memory -layout of a program which has been running for a while now: - - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 5 | -| (230) - 2 | | | -| (230) - 3 | | | -| (230) - 4 | | 42 | -| ... | ... | ... | -| 2 | z | → (230) - 4 | -| 1 | y | 42 | -| 0 | x | → (230) - 1 | - -In this case, we’ve allocated four things on the heap, but deallocated two of -them. There’s a gap between (230) - 1 and (230) - 4 which isn’t -currently being used. The specific details of how and why this happens depends -on what kind of strategy you use to manage the heap. Different programs can use -different ‘memory allocators’, which are libraries that manage this for you. -Rust programs use [jemalloc][jemalloc] for this purpose. - -[jemalloc]: http://www.canonware.com/jemalloc/ - -Anyway, back to our example. Since this memory is on the heap, it can stay -alive longer than the function which allocates the box. In this case, however, -it doesn’t.[^moving] When the function is over, we need to free the stack frame -for `main()`. `Box`, though, has a trick up its sleeve: [Drop][drop]. The -implementation of `Drop` for `Box` deallocates the memory that was allocated -when it was created. Great! So when `x` goes away, it first frees the memory -allocated on the heap: - -| Address | Name | Value | -|---------|------|--------| -| 1 | y | 42 | -| 0 | x | ?????? | - -[drop]: drop.html -[^moving]: We can make the memory live longer by transferring ownership, - sometimes called ‘moving out of the box’. More complex examples will - be covered later. - - -And then the stack frame goes away, freeing all of our memory. - -# Arguments and borrowing - -We’ve got some basic examples with the stack and the heap going, but what about -function arguments and borrowing? Here’s a small Rust program: - -```rust -fn foo(i: &i32) { - let z = 42; -} - -fn main() { - let x = 5; - let y = &x; - - foo(y); -} -``` - -When we enter `main()`, memory looks like this: - -| Address | Name | Value | -|---------|------|--------| -| 1 | y | → 0 | -| 0 | x | 5 | - -`x` is a plain old `5`, and `y` is a reference to `x`. So its value is the -memory location that `x` lives at, which in this case is `0`. - -What about when we call `foo()`, passing `y` as an argument? - -| Address | Name | Value | -|---------|------|--------| -| 3 | z | 42 | -| 2 | i | → 0 | -| 1 | y | → 0 | -| 0 | x | 5 | - -Stack frames aren’t only for local bindings, they’re for arguments too. So in -this case, we need to have both `i`, our argument, and `z`, our local variable -binding. `i` is a copy of the argument, `y`. Since `y`’s value is `0`, so is -`i`’s. - -This is one reason why borrowing a variable doesn’t deallocate any memory: the -value of a reference is a pointer to a memory location. If we got rid of -the underlying memory, things wouldn’t work very well. - -# A complex example - -Okay, let’s go through this complex program step-by-step: - -```rust -fn foo(x: &i32) { - let y = 10; - let z = &y; - - baz(z); - bar(x, z); -} - -fn bar(a: &i32, b: &i32) { - let c = 5; - let d = Box::new(5); - let e = &d; - - baz(e); -} - -fn baz(f: &i32) { - let g = 100; -} - -fn main() { - let h = 3; - let i = Box::new(20); - let j = &h; - - foo(j); -} -``` - -First, we call `main()`: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| ... | ... | ... | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a -value pointing there. - -Next, at the end of `main()`, `foo()` gets called: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| ... | ... | ... | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value -as `j`, since that’s what we passed it in. It’s a pointer to the `0` address, -since `j` points at `h`. - -Next, `foo()` calls `baz()`, passing `z`: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| ... | ... | ... | -| 7 | g | 100 | -| 6 | f | → 4 | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s -over, we get rid of its stack frame: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| ... | ... | ... | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -Next, `foo()` calls `bar()` with `x` and `z`: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| (230) - 2 | | 5 | -| ... | ... | ... | -| 10 | e | → 9 | -| 9 | d | → (230) - 2 | -| 8 | c | 5 | -| 7 | b | → 4 | -| 6 | a | → 0 | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -We end up allocating another value on the heap, and so we have to subtract one -from (230) - 1. It’s easier to write that than `1,073,741,822`. In any -case, we set up the variables as usual. - -At the end of `bar()`, it calls `baz()`: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| (230) - 2 | | 5 | -| ... | ... | ... | -| 12 | g | 100 | -| 11 | f | → (230) - 2 | -| 10 | e | → 9 | -| 9 | d | → (230) - 2 | -| 8 | c | 5 | -| 7 | b | → 4 | -| 6 | a | → 0 | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -With this, we’re at our deepest point! Whew! Congrats for following along this -far. - -After `baz()` is over, we get rid of `f` and `g`: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| (230) - 2 | | 5 | -| ... | ... | ... | -| 10 | e | → 9 | -| 9 | d | → (230) - 2 | -| 8 | c | 5 | -| 7 | b | → 4 | -| 6 | a | → 0 | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -Next, we return from `bar()`. `d` in this case is a `Box`, so it also frees -what it points to: (230) - 2. - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| ... | ... | ... | -| 5 | z | → 4 | -| 4 | y | 10 | -| 3 | x | → 0 | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -And after that, `foo()` returns: - -| Address | Name | Value | -|----------------------|------|------------------------| -| (230) - 1 | | 20 | -| ... | ... | ... | -| 2 | j | → 0 | -| 1 | i | → (230) - 1 | -| 0 | h | 3 | - -And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped, -it will clean up the last of the heap too. - -# What do other languages do? - -Most languages with a garbage collector heap-allocate by default. This means -that every value is boxed. There are a number of reasons why this is done, but -they’re out of scope for this tutorial. There are some possible optimizations -that don’t make it true 100% of the time, too. Rather than relying on the stack -and `Drop` to clean up memory, the garbage collector deals with the heap -instead. - -# Which to use? - -So if the stack is faster and easier to manage, why do we need the heap? A big -reason is that Stack-allocation alone means you only have 'Last In First Out (LIFO)' semantics for -reclaiming storage. Heap-allocation is strictly more general, allowing storage -to be taken from and returned to the pool in arbitrary order, but at a -complexity cost. - -Generally, you should prefer stack allocation, and so, Rust stack-allocates by -default. The LIFO model of the stack is simpler, at a fundamental level. This -has two big impacts: runtime efficiency and semantic impact. - -## Runtime Efficiency - -Managing the memory for the stack is trivial: The machine -increments or decrements a single value, the so-called “stack pointer”. -Managing memory for the heap is non-trivial: heap-allocated memory is freed at -arbitrary points, and each block of heap-allocated memory can be of arbitrary -size, so the memory manager must generally work much harder to -identify memory for reuse. - -If you’d like to dive into this topic in greater detail, [this paper][wilson] -is a great introduction. - -[wilson]: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.143.4688 - -## Semantic impact - -Stack-allocation impacts the Rust language itself, and thus the developer’s -mental model. The LIFO semantics is what drives how the Rust language handles -automatic memory management. Even the deallocation of a uniquely-owned -heap-allocated box can be driven by the stack-based LIFO semantics, as -discussed throughout this chapter. The flexibility (i.e. expressiveness) of non -LIFO-semantics means that in general the compiler cannot automatically infer at -compile-time where memory should be freed; it has to rely on dynamic protocols, -potentially from outside the language itself, to drive deallocation (reference -counting, as used by `Rc` and `Arc`, is one example of this). - -When taken to the extreme, the increased expressive power of heap allocation -comes at the cost of either significant runtime support (e.g. in the form of a -garbage collector) or significant programmer effort (in the form of explicit -memory management calls that require verification not provided by the Rust -compiler). diff --git a/src/doc/book/src/trait-objects.md b/src/doc/book/src/trait-objects.md deleted file mode 100644 index a77d5fe93b524..0000000000000 --- a/src/doc/book/src/trait-objects.md +++ /dev/null @@ -1,335 +0,0 @@ -# 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 optimizations 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. - -Suppose we’ve got some values that implement `Foo`. The explicit form of -construction and use of `Foo` trait objects might look a bit like (ignoring the -type mismatches: they’re all 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); -``` - -## Object Safety - -Not every trait can be used to make a trait object. For example, vectors implement -`Clone`, but if we try to make a trait object: - -```rust,ignore -let v = vec![1, 2, 3]; -let o = &v as &Clone; -``` - -We get an error: - -```text -error: cannot convert to a trait object because trait `core::clone::Clone` is not object-safe [E0038] -let o = &v as &Clone; - ^~ -note: the trait cannot require that `Self : Sized` -let o = &v as &Clone; - ^~ -``` - -The error says that `Clone` is not ‘object-safe’. Only traits that are -object-safe can be made into trait objects. A trait is object-safe if both of -these are true: - -* the trait does not require that `Self: Sized` -* all of its methods are object-safe - -So what makes a method object-safe? Each method must require that `Self: Sized` -or all of the following: - -* must not have any type parameters -* must not use `Self` - -Whew! As we can see, almost all of these rules talk about `Self`. A good intuition -is “except in special circumstances, if your trait’s method uses `Self`, it is not -object-safe.” diff --git a/src/doc/book/src/traits.md b/src/doc/book/src/traits.md deleted file mode 100644 index 19a133f84b0b6..0000000000000 --- a/src/doc/book/src/traits.md +++ /dev/null @@ -1,551 +0,0 @@ -# Traits - -A trait is a language feature that tells the Rust compiler about -functionality a type must provide. - -Recall the `impl` keyword, used to call a function with [method -syntax][methodsyntax]: - -```rust -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -impl Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } -} -``` - -[methodsyntax]: method-syntax.html - -Traits are similar, except that we first define a trait with a method -signature, then implement the trait for a type. In this example, we implement the trait `HasArea` for `Circle`: - -```rust -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, only a type signature. When we `impl` a trait, -we use `impl Trait for Item`, rather than only `impl Item`. - -`Self` may be used in a type annotation to refer to an instance of the type -implementing this trait passed as a parameter. `Self`, `&Self` or `&mut Self` -may be used depending on the level of ownership required. - -```rust -struct Circle { - x: f64, - y: f64, - radius: f64, -} - -trait HasArea { - fn area(&self) -> f64; - - fn is_larger(&self, &Self) -> bool; -} - -impl HasArea for Circle { - fn area(&self) -> f64 { - std::f64::consts::PI * (self.radius * self.radius) - } - - fn is_larger(&self, other: &Self) -> bool { - self.area() > other.area() - } -} -``` - -## Trait bounds on generic functions - -Traits are useful because they allow a type to make certain promises about its -behavior. Generic functions can exploit this to constrain, or [bound][bounds], the types they -accept. Consider this function, which does not compile: - -[bounds]: glossary.html#bounds - -```rust,ignore -fn print_area(shape: T) { - println!("This shape has an area of {}", shape.area()); -} -``` - -Rust complains: - -```text -error: no method named `area` found for type `T` in the current scope -``` - -Because `T` can be any type, we can’t be sure that it implements the `area` -method. But we can add a trait bound 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 -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: the trait bound `_ : HasArea` is not satisfied [E0277] -``` - -## Trait bounds on generic structs - -Your generic structs can also benefit from trait bounds. All you need to -do is append the bound when you declare type parameters. Here is a new -type `Rectangle` and its operation `is_square()`: - -```rust -struct Rectangle { - x: T, - y: T, - width: T, - height: T, -} - -impl Rectangle { - fn is_square(&self) -> bool { - self.width == self.height - } -} - -fn main() { - let mut r = Rectangle { - x: 0, - y: 0, - width: 47, - height: 47, - }; - - assert!(r.is_square()); - - r.height = 42; - assert!(!r.is_square()); -} -``` - -`is_square()` needs to check that the sides are equal, so the sides must be of -a type that implements the [`core::cmp::PartialEq`][PartialEq] trait: - -```rust,ignore -impl Rectangle { ... } -``` - -Now, a rectangle can be defined in terms of any type that can be compared for -equality. - -[PartialEq]: ../core/cmp/trait.PartialEq.html - -Here we defined a new struct `Rectangle` that accepts numbers of any -precision—really, objects of pretty much any type—as long as they can be -compared for equality. Could we do the same for our `HasArea` structs, `Square` -and `Circle`? Yes, but they need multiplication, and to work with that we need -to know more about [operator traits][operators-and-overloading]. - -[operators-and-overloading]: operators-and-overloading.html - -# Rules for implementing traits - -So far, we’ve only added trait implementations to structs, but you can -implement a trait for any type such as `f32`: - -```rust -trait ApproxEqual { - fn approx_equal(&self, other: &Self) -> bool; -} -impl ApproxEqual for f32 { - fn approx_equal(&self, other: &Self) -> bool { - // Appropriate for `self` and `other` being close to 1.0. - (self - other).abs() <= ::std::f32::EPSILON - } -} - -println!("{}", 1.0.approx_equal(&1.00000001)); -``` - -This may seem like the Wild West, but there are two restrictions around -implementing traits that prevent this from getting out of hand. The first is -that if the trait isn’t defined in your scope, it doesn’t apply. Here’s an -example: the standard library provides a [`Write`][write] trait which adds -extra functionality to `File`s, for doing file I/O. By default, a `File` -won’t have its methods: - -[write]: ../std/io/trait.Write.html - -```rust,ignore -let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); -let buf = b"whatever"; // buf: &[u8; 8], a byte string literal. -let result = f.write(buf); -# result.unwrap(); // Ignore the error. -``` - -Here’s the error: - -```text -error: type `std::fs::File` does not implement any method in scope named `write` -let result = f.write(buf); - ^~~~~~~~~~ -``` - -We need to `use` the `Write` trait first: - -```rust,no_run -use std::io::Write; - -let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); -let buf = b"whatever"; -let result = f.write(buf); -# result.unwrap(); // Ignore the error. -``` - -This will compile without error. - -This means that even if someone does something bad like add methods to `i32`, -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 implementing it for must be defined by you. Or more -precisely, one of them must be defined in the same crate as the `impl` -you're writing. For more on Rust's module and package system, see the -chapter on [crates and modules][cm]. - -So, we could implement the `HasArea` type for `i32`, because we defined -`HasArea` in our code. But if we tried to implement `ToString`, a trait -provided by Rust, for `i32`, we could not, because neither the trait nor -the type are defined 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 [trait objects][to] for more details. - -[cm]: crates-and-modules.html -[to]: trait-objects.html - -# 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: - -```rust -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’: - -```rust -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", "world"); -} -``` - -`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: - -```rust -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: - -```rust -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(x: i32) -> T - // This is using ConvertTo as if it were "ConvertTo". - where i32: ConvertTo { - x.convert() -} -``` - -This shows off the additional feature of `where` clauses: they allow bounds -on the left-hand side not only of type parameters `T`, but also of types (`i32` in this case). In this example, `i32` must implement -`ConvertTo`. Rather than defining what `i32` is (since that's obvious), the -`where` clause here constrains `T`. - -# Default methods - -A default method can be added to a trait definition if it is already known how a typical implementor will define a method. For example, `is_invalid()` is defined as the opposite of `is_valid()`: - -```rust -trait Foo { - fn is_valid(&self) -> bool; - - fn is_invalid(&self) -> bool { !self.is_valid() } -} -``` - -Implementors of the `Foo` trait need to implement `is_valid()` but not `is_invalid()` due to the added default behavior. This default behavior can still be overridden as in: - -```rust -# trait Foo { -# fn is_valid(&self) -> bool; -# -# fn is_invalid(&self) -> bool { !self.is_valid() } -# } -struct UseDefault; - -impl Foo for UseDefault { - fn is_valid(&self) -> bool { - println!("Called UseDefault.is_valid."); - true - } -} - -struct OverrideDefault; - -impl Foo for OverrideDefault { - fn is_valid(&self) -> bool { - println!("Called OverrideDefault.is_valid."); - true - } - - fn is_invalid(&self) -> bool { - println!("Called OverrideDefault.is_invalid!"); - true // Overrides the expected value of `is_invalid()`. - } -} - -let default = UseDefault; -assert!(!default.is_invalid()); // Prints "Called UseDefault.is_valid." - -let over = OverrideDefault; -assert!(over.is_invalid()); // Prints "Called OverrideDefault.is_invalid!" -``` - -# Inheritance - -Sometimes, implementing a trait requires implementing another trait: - -```rust -trait Foo { - fn foo(&self); -} - -trait FooBar : Foo { - fn foobar(&self); -} -``` - -Implementors of `FooBar` must also implement `Foo`, like this: - -```rust -# trait Foo { -# fn foo(&self); -# } -# trait FooBar : Foo { -# fn foobar(&self); -# } -struct Baz; - -impl Foo for Baz { - fn foo(&self) { println!("foo"); } -} - -impl FooBar for Baz { - fn foobar(&self) { println!("foobar"); } -} -``` - -If we forget to implement `Foo`, Rust will tell us: - -```text -error: the trait bound `main::Baz : main::Foo` is not satisfied [E0277] -``` - -# Deriving - -Implementing traits like `Debug` and `Default` repeatedly can become -quite tedious. For that reason, Rust provides an [attribute][attributes] that -allows you to let Rust automatically implement traits for you: - -```rust -#[derive(Debug)] -struct Foo; - -fn main() { - println!("{:?}", Foo); -} -``` - -[attributes]: attributes.html - -However, deriving is limited to a certain set of traits: - -- [`Clone`](../core/clone/trait.Clone.html) -- [`Copy`](../core/marker/trait.Copy.html) -- [`Debug`](../core/fmt/trait.Debug.html) -- [`Default`](../core/default/trait.Default.html) -- [`Eq`](../core/cmp/trait.Eq.html) -- [`Hash`](../core/hash/trait.Hash.html) -- [`Ord`](../core/cmp/trait.Ord.html) -- [`PartialEq`](../core/cmp/trait.PartialEq.html) -- [`PartialOrd`](../core/cmp/trait.PartialOrd.html) diff --git a/src/doc/book/src/type-aliases.md b/src/doc/book/src/type-aliases.md deleted file mode 100644 index 1bd0f78e36853..0000000000000 --- a/src/doc/book/src/type-aliases.md +++ /dev/null @@ -1,78 +0,0 @@ -# Type Aliases - -The `type` keyword lets you declare an alias of another type: - -```rust -type Name = String; -``` - -You can then use this type as if it were a real type: - -```rust -type Name = String; - -let x: Name = "Hello".to_string(); -``` - -Note, however, that this is an _alias_, not a new type entirely. In other -words, because Rust is strongly typed, you’d expect a comparison between two -different types to fail: - -```rust,ignore -let x: i32 = 5; -let y: i64 = 5; - -if x == y { - // ... -} -``` - -this gives - -```text -error: mismatched types: - expected `i32`, - found `i64` -(expected i32, - found i64) [E0308] - if x == y { - ^ -``` - -But, if we had an alias: - -```rust -type Num = i32; - -let x: i32 = 5; -let y: Num = 5; - -if x == y { - // ... -} -``` - -This compiles without error. Values of a `Num` type are the same as a value of -type `i32`, in every way. You can use [tuple struct] to really get a new type. - -[tuple struct]: structs.html#tuple-structs - -You can also use type aliases with generics: - -```rust -use std::result; - -enum ConcreteError { - Foo, - Bar, -} - -type Result = result::Result; -``` - -This creates a specialized version of the `Result` type, which always has a -`ConcreteError` for the `E` part of `Result`. This is commonly used -in the standard library to create custom errors for each subsection. For -example, [io::Result][ioresult]. - -[ioresult]: ../std/io/type.Result.html diff --git a/src/doc/book/src/ufcs.md b/src/doc/book/src/ufcs.md deleted file mode 100644 index 016ecc7097657..0000000000000 --- a/src/doc/book/src/ufcs.md +++ /dev/null @@ -1,136 +0,0 @@ -# Universal Function Call Syntax - -Sometimes, functions can have the same names. Consider this code: - -```rust -trait Foo { - fn f(&self); -} - -trait Bar { - fn f(&self); -} - -struct Baz; - -impl Foo for Baz { - fn f(&self) { println!("Baz’s impl of Foo"); } -} - -impl Bar for Baz { - fn f(&self) { println!("Baz’s impl of Bar"); } -} - -let b = Baz; -``` - -If we were to try to call `b.f()`, we’d get an error: - -```text -error: multiple applicable methods in scope [E0034] -b.f(); - ^~~ -note: candidate #1 is defined in an impl of the trait `main::Foo` for the type -`main::Baz` - fn f(&self) { println!("Baz’s impl of Foo"); } - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -note: candidate #2 is defined in an impl of the trait `main::Bar` for the type -`main::Baz` - fn f(&self) { println!("Baz’s impl of Bar"); } - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``` - -We need a way to disambiguate which method we need. This feature is called -‘universal function call syntax’, and it looks like this: - -```rust -# trait Foo { -# fn f(&self); -# } -# trait Bar { -# fn f(&self); -# } -# struct Baz; -# impl Foo for Baz { -# fn f(&self) { println!("Baz’s impl of Foo"); } -# } -# impl Bar for Baz { -# fn f(&self) { println!("Baz’s impl of Bar"); } -# } -# let b = Baz; -Foo::f(&b); -Bar::f(&b); -``` - -Let’s break it down. - -```rust,ignore -Foo:: -Bar:: -``` - -These halves of the invocation are the types of the two traits: `Foo` and -`Bar`. This is what ends up actually doing the disambiguation between the two: -Rust calls the one from the trait name you use. - -```rust,ignore -f(&b) -``` - -When we call a method like `b.f()` using [method syntax][methodsyntax], Rust -will automatically borrow `b` if `f()` takes `&self`. In this case, Rust will -not, and so we need to pass an explicit `&b`. - -[methodsyntax]: method-syntax.html - -# Angle-bracket Form - -The form of UFCS we just talked about: - -```rust,ignore -Trait::method(args); -``` - -Is a short-hand. There’s an expanded form of this that’s needed in some -situations: - -```rust,ignore -::method(args); -``` - -The `<>::` syntax is a means of providing a type hint. The type goes inside -the `<>`s. In this case, the type is `Type as Trait`, indicating that we want -`Trait`’s version of `method` to be called here. The `as Trait` part is -optional if it’s not ambiguous. Same with the angle brackets, hence the -shorter form. - -Here’s an example of using the longer form. - -```rust -trait Foo { - fn foo() -> i32; -} - -struct Bar; - -impl Bar { - fn foo() -> i32 { - 20 - } -} - -impl Foo for Bar { - fn foo() -> i32 { - 10 - } -} - -fn main() { - assert_eq!(10, ::foo()); - assert_eq!(20, Bar::foo()); -} -``` - -Using the angle bracket syntax lets you call the trait method instead of the -inherent one. diff --git a/src/doc/book/src/unsafe.md b/src/doc/book/src/unsafe.md deleted file mode 100644 index 9bf59fe2abdc3..0000000000000 --- a/src/doc/book/src/unsafe.md +++ /dev/null @@ -1,142 +0,0 @@ -# Unsafe - -Rust’s main draw is its powerful static guarantees about behavior. But safety -checks are conservative by nature: there are some programs that are actually -safe, but the compiler is not able to verify this is true. To write these kinds -of programs, we need to tell the compiler to relax its restrictions a bit. For -this, Rust has a keyword, `unsafe`. Code using `unsafe` has fewer restrictions -than normal code does. - -Let’s go over the syntax, and then we’ll talk semantics. `unsafe` is used in -four contexts. The first one is to mark a function as unsafe: - -```rust -unsafe fn danger_will_robinson() { - // Scary stuff... -} -``` - -All functions called from [FFI][ffi] must be marked as `unsafe`, for example. -The second use of `unsafe` is an unsafe block: - -[ffi]: ffi.html - -```rust -unsafe { - // Scary stuff... -} -``` - -The third is for unsafe traits: - -```rust -unsafe trait Scary { } -``` - -And the fourth is for `impl`ementing one of those traits: - -```rust -# unsafe trait Scary { } -unsafe impl Scary for i32 {} -``` - -It’s important to be able to explicitly delineate code that may have bugs that -cause big problems. If a Rust program segfaults, you can be sure the cause is -related to something marked `unsafe`. - -# What does ‘safe’ mean? - -Safe, in the context of Rust, means ‘doesn’t do anything unsafe’. It’s also -important to know that there are certain behaviors that are probably not -desirable in your code, but are expressly _not_ unsafe: - -* Deadlocks -* Leaks of memory or other resources -* Exiting without calling destructors -* Integer overflow - -Rust cannot prevent all kinds of software problems. Buggy code can and will be -written in Rust. These things aren’t great, but they don’t qualify as `unsafe` -specifically. - -In addition, the following are all undefined behaviors in Rust, and must be -avoided, even when writing `unsafe` code: - -* Data races -* Dereferencing a NULL/dangling raw pointer -* Reads of [undef][undef] (uninitialized) memory -* Breaking the [pointer aliasing rules][aliasing] with raw pointers. -* `&mut T` and `&T` follow LLVM’s scoped [noalias][noalias] model, except if - the `&T` contains an `UnsafeCell`. Unsafe code must not violate these - aliasing guarantees. -* Mutating an immutable value/reference without `UnsafeCell` -* Invoking undefined behavior via compiler intrinsics: - * Indexing outside of the bounds of an object with `std::ptr::offset` - (`offset` intrinsic), with - the exception of one byte past the end which is permitted. - * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64` - intrinsics) on overlapping buffers -* Invalid values in primitive types, even in private fields/locals: - * NULL/dangling references or boxes - * A value other than `false` (0) or `true` (1) in a `bool` - * A discriminant in an `enum` not included in its type definition - * A value in a `char` which is a surrogate or above `char::MAX` - * Non-UTF-8 byte sequences in a `str` -* Unwinding into Rust from foreign code or unwinding from Rust into foreign - code. - -[noalias]: http://llvm.org/docs/LangRef.html#noalias -[undef]: http://llvm.org/docs/LangRef.html#undefined-values -[aliasing]: http://llvm.org/docs/LangRef.html#pointer-aliasing-rules - -# Unsafe Superpowers - -In both unsafe functions and unsafe blocks, Rust will let you do three things -that you normally can not do. Just three. Here they are: - -1. Access or update a [static mutable variable][static]. -2. Dereference a raw pointer. -3. Call unsafe functions. This is the most powerful ability. - -That’s it. It’s important that `unsafe` does not, for example, ‘turn off the -borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its -semantics, it won’t start accepting anything. But it will let you write -things that _do_ break some of the rules. - -You will also encounter the `unsafe` keyword when writing bindings to foreign -(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface -around the methods provided by the library. - -Let’s go over the basic three abilities listed, in order. - -## Access or update a `static mut` - -Rust has a feature called ‘`static mut`’ which allows for mutable global state. -Doing so can cause a data race, and as such is inherently not safe. For more -details, see the [static][static] section of the book. - -[static]: const-and-static.html#static - -## Dereference a raw pointer - -Raw pointers let you do arbitrary pointer arithmetic, and can cause a number of -different memory safety and security issues. In some senses, the ability to -dereference an arbitrary pointer is one of the most dangerous things you can -do. For more on raw pointers, see [their section of the book][rawpointers]. - -[rawpointers]: raw-pointers.html - -## Call unsafe functions - -This last ability works with both aspects of `unsafe`: you can only call -functions marked `unsafe` from inside an unsafe block. - -This ability is powerful and varied. Rust exposes some [compiler -intrinsics][intrinsics] as unsafe functions, and some unsafe functions bypass -safety checks, trading safety for speed. - -I’ll repeat again: even though you _can_ do arbitrary things in unsafe blocks -and functions doesn’t mean you should. The compiler will act as though you’re -upholding its invariants, so be careful! - -[intrinsics]: ../unstable-book/intrinsics.html diff --git a/src/doc/book/src/unsized-types.md b/src/doc/book/src/unsized-types.md deleted file mode 100644 index 2d090925d51f6..0000000000000 --- a/src/doc/book/src/unsized-types.md +++ /dev/null @@ -1,61 +0,0 @@ -# Unsized Types - -Most types have a particular size, in bytes, that is knowable at compile time. -For example, an `i32` is thirty-two bits big, or four bytes. However, there are -some types which are useful to express, but do not have a defined size. These are -called ‘unsized’ or ‘dynamically sized’ types. One example is `[T]`. This type -represents a certain number of `T` in sequence. But we don’t know how many -there are, so the size is not known. - -Rust understands a few of these types, but they have some restrictions. There -are three: - -1. We can only manipulate an instance of an unsized type via a pointer. An - `&[T]` works fine, but a `[T]` does not. -2. Variables and arguments cannot have dynamically sized types. -3. Only the last field in a `struct` may have a dynamically sized type; the - other fields must not. Enum variants must not have dynamically sized types as - data. - -So why bother? Well, because `[T]` can only be used behind a pointer, if we -didn’t have language support for unsized types, it would be impossible to write -this: - -```rust,ignore -impl Foo for str { -``` - -or - -```rust,ignore -impl Foo for [T] { -``` - -Instead, you would have to write: - -```rust,ignore -impl Foo for &str { -``` - -Meaning, this implementation would only work for [references][ref], and not -other types of pointers. With the `impl for str`, all pointers, including (at -some point, there are some bugs to fix first) user-defined custom smart -pointers, can use this `impl`. - -[ref]: references-and-borrowing.html - -# ?Sized - -If you want to write a function that accepts a dynamically sized type, you -can use the special bound syntax, `?Sized`: - -```rust -struct Foo { - f: T, -} -``` - -This `?Sized`, read as “T may or may not be `Sized`”, which allows us to match -both sized and unsized types. All generic type parameters implicitly -have the `Sized` bound, so the `?Sized` can be used to opt-out of the implicit -bound. diff --git a/src/doc/book/src/using-rust-without-the-standard-library.md b/src/doc/book/src/using-rust-without-the-standard-library.md deleted file mode 100644 index 709d10f4e4791..0000000000000 --- a/src/doc/book/src/using-rust-without-the-standard-library.md +++ /dev/null @@ -1,42 +0,0 @@ -# Using Rust Without the Standard Library - -Rust’s standard library provides a lot of useful functionality, but assumes -support for various features of its host system: threads, networking, heap -allocation, and others. There are systems that do not have these features, -however, and Rust can work with those too! To do so, we tell Rust that we -don’t want to use the standard library via an attribute: `#![no_std]`. - -> Note: This feature is technically stable, but there are some caveats. For -> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. -> For details on binaries without the standard library, see [the nightly -> chapter on 'lang items'](../unstable-book/lang-items.html#using-libc) - -To use `#![no_std]`, add it to your crate root: - -```rust,ignore -#![no_std] - -fn plus_one(x: i32) -> i32 { - x + 1 -} -``` - -Much of the functionality that’s exposed in the standard library is also -available via the [`core` crate](../core/index.html). When we’re using the -standard library, Rust automatically brings `std` into scope, allowing you to -use its features without an explicit import. By the same token, when using -`#![no_std]`, Rust will bring `core` into scope for you, as well as [its -prelude](../core/prelude/v1/index.html). This means that a lot of code will Just -Work: - -```rust,ignore -#![no_std] - -fn may_fail(failure: bool) -> Result<(), &'static str> { - if failure { - Err("this didn’t work!") - } else { - Ok(()) - } -} -``` diff --git a/src/doc/book/src/variable-bindings.md b/src/doc/book/src/variable-bindings.md deleted file mode 100644 index d6aa8b1acb72f..0000000000000 --- a/src/doc/book/src/variable-bindings.md +++ /dev/null @@ -1,256 +0,0 @@ -# Variable Bindings - -Virtually every non-'Hello World’ Rust program uses *variable bindings*. They -bind some value to a name, so it can be used later. `let` is -used to introduce a binding, 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. - -# Patterns - -In many languages, a variable binding would be called a *variable*, but Rust’s -variable bindings have a few tricks up their sleeves. For example the -left-hand side of a `let` statement is a ‘[pattern][pattern]’, not a -variable name. This means we can do things like: - -```rust -let (x, y) = (1, 2); -``` - -After this statement is evaluated, `x` will be one, and `y` will be two. -Patterns are really powerful, and have [their own section][pattern] in the -book. We don’t need those features for now, so we’ll keep this in the back -of our minds as we go forward. - -[pattern]: patterns.html - -# Type annotations - -Rust is a statically typed language, which means that we specify our types up -front, and they’re checked at compile time. 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 explicitly 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 `5`.” - -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. - -# Mutability - -By default, bindings are *immutable*. This code will not compile: - -```rust,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 forbidden. - -# Initializing 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_variables)] - 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. - -Let us take a minute to 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 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][format]. -For now, we'll stick to the default: integers aren't very complicated to -print. - -[format]: ../std/fmt/index.html - -# Scope and shadowing - -Let’s get back to bindings. Variable bindings have a scope - they are -constrained to live in the block they were defined in. A block is a collection -of statements enclosed by `{` and `}`. Function definitions are also blocks! -In the following example we define two variable bindings, `x` and `y`, which -live in different blocks. `x` can be accessed from inside the `fn main() {}` -block, while `y` can be accessed only from inside the inner block: - -```rust,ignore -fn main() { - let x: i32 = 17; - { - let y: i32 = 3; - println!("The value of x is {} and value of y is {}", x, y); - } - println!("The value of x is {} and value of y is {}", x, y); // This won't work. -} -``` - -The first `println!` would print "The value of x is 17 and the value of y is -3", but this example cannot be compiled successfully, because the second -`println!` cannot access the value of `y`, since it is not in scope anymore. -Instead we get this error: - -```bash -$ cargo build - Compiling hello v0.1.0 (file:///home/you/projects/hello_world) -main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425] -main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work. - ^ -note: in expansion of format_args! -:2:25: 2:56 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! -main.rs:7:5: 7:65 note: expansion site -main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation -error: aborting due to previous error -Could not compile `hello`. - -To learn more, run the command again with --verbose. -``` - -Additionally, variable bindings can be shadowed. This means that a later -variable binding with the same name as another binding that is currently in -scope will override the previous binding. - -```rust -let x: i32 = 8; -{ - println!("{}", x); // Prints "8". - let x = 12; - println!("{}", x); // Prints "12". -} -println!("{}", x); // Prints "8". -let x = 42; -println!("{}", x); // Prints "42". -``` - -Shadowing and mutable bindings may appear as two sides of the same coin, but -they are two distinct concepts that can't always be used interchangeably. For -one, shadowing enables us to rebind a name to a value of a different type. It -is also possible to change the mutability of a binding. Note that shadowing a -name does not alter or destroy the value it was bound to, and the value will -continue to exist until it goes out of scope, even if it is no longer accessible -by any means. - -```rust -let mut x: i32 = 1; -x = 7; -let x = x; // `x` is now immutable and is bound to `7`. - -let y = 4; -let y = "I can also be bound to text!"; // `y` is now of a different type. -``` diff --git a/src/doc/book/src/vectors.md b/src/doc/book/src/vectors.md deleted file mode 100644 index aff078718dfb1..0000000000000 --- a/src/doc/book/src/vectors.md +++ /dev/null @@ -1,156 +0,0 @@ -# Vectors - -A ‘vector’ is a dynamic or ‘growable’ array, implemented as the standard -library type [`Vec`][vec]. The `T` means that we can have vectors -of any type (see the chapter on [generics][generic] for more). -Vectors always allocate their data on the heap. -You can create them with the `vec!` macro: - -```rust -let v = vec![1, 2, 3, 4, 5]; // v: Vec -``` - -(Notice that unlike the `println!` macro we’ve used in the past, we use square -brackets `[]` with `vec!` macro. 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: - -```rust -let v = vec![0; 10]; // A vector of ten zeroes. -``` - -Vectors store their contents as contiguous arrays of `T` on the heap. This means -that they must be able to know the size of `T` at compile time (that is, how -many bytes are needed to store a `T`?). The size of some things can't be known -at compile time. For these you'll have to store a pointer to that thing: -thankfully, the [`Box`][box] type works perfectly for this. - -## Accessing elements - -To get the value at a particular index in the vector, we use `[]`s: - -```rust -let v = vec![1, 2, 3, 4, 5]; - -println!("The third element of v is {}", v[2]); -``` - -The indices count from `0`, so the third element is `v[2]`. - -It’s also important to note that you must index with the `usize` type: - -```rust,ignore -let v = vec![1, 2, 3, 4, 5]; - -let i: usize = 0; -let j: i32 = 0; - -// Works: -v[i]; - -// Doesn’t: -v[j]; -``` - -Indexing with a non-`usize` type gives an error that looks like this: - -```text -error: the trait bound `collections::vec::Vec<_> : core::ops::Index` -is not satisfied [E0277] -v[j]; -^~~~ -note: the type `collections::vec::Vec<_>` cannot be indexed by `i32` -error: aborting due to previous error -``` - -There’s a lot of punctuation in that message, but the core of it makes sense: -you cannot index with an `i32`. - -## Out-of-bounds Access - -If you try to access an index that doesn’t exist: - -```rust,ignore -let v = vec![1, 2, 3]; -println!("Item 7 is {}", v[7]); -``` - -then the current thread will [panic] with a message like this: - -```text -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 7' -``` - -If you want to handle out-of-bounds errors without panicking, you can use -methods like [`get`][get] or [`get_mut`][get_mut] that return `None` when -given an invalid index: - -```rust -let v = vec![1, 2, 3]; -match v.get(7) { - Some(x) => println!("Item 7 is {}", x), - None => println!("Sorry, this vector is too short.") -} -``` - -## Iterating - -Once you have a vector, you can iterate through its elements with `for`. There -are three versions: - -```rust -let mut v = vec![1, 2, 3, 4, 5]; - -for i in &v { - println!("A reference to {}", i); -} - -for i in &mut v { - println!("A mutable reference to {}", i); -} - -for i in v { - println!("Take ownership of the vector and its element {}", i); -} -``` - -Note: You cannot use the vector again once you have iterated by taking ownership of the vector. -You can iterate the vector multiple times by taking a reference to the vector whilst iterating. -For example, the following code does not compile. - -```rust,ignore -let v = vec![1, 2, 3, 4, 5]; - -for i in v { - println!("Take ownership of the vector and its element {}", i); -} - -for i in v { - println!("Take ownership of the vector and its element {}", i); -} -``` - -Whereas the following works perfectly, - -```rust -let v = vec![1, 2, 3, 4, 5]; - -for i in &v { - println!("This is a reference to {}", i); -} - -for i in &v { - println!("This is a reference to {}", i); -} -``` - -Vectors have many more useful methods, which you can read about in [their -API documentation][vec]. - -[vec]: ../std/vec/index.html -[box]: ../std/boxed/index.html -[generic]: generics.html -[panic]: concurrency.html#panics -[get]: ../std/vec/struct.Vec.html#method.get -[get_mut]: ../std/vec/struct.Vec.html#method.get_mut From f17965da1e139f7f1f249ebcc3394d13302fc9b0 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 14:43:27 -0500 Subject: [PATCH 134/662] Import submodule for the book. It's all in the external repository now. --- .gitmodules | 3 +++ src/doc/book | 1 + 2 files changed, 4 insertions(+) create mode 160000 src/doc/book diff --git a/.gitmodules b/.gitmodules index a7063bbddc5f0..d2e1fb868a999 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,3 +27,6 @@ [submodule "reference"] path = src/doc/reference url = https://github.com/rust-lang-nursery/reference.git +[submodule "book"] + path = src/doc/book + url = https://github.com/rust-lang/book diff --git a/src/doc/book b/src/doc/book new file mode 160000 index 0000000000000..979c56634f3fe --- /dev/null +++ b/src/doc/book @@ -0,0 +1 @@ +Subproject commit 979c56634f3fe594c9554c555eee29311d7d4a50 From 8573a1319a63fa61d1db9b9ff8239b5eeb3c1d56 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 14:49:50 -0500 Subject: [PATCH 135/662] build both editions of the book --- src/bootstrap/doc.rs | 5 +++++ src/bootstrap/step.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index db8ed579cecdb..3c024f4c4efd4 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -53,6 +53,11 @@ pub fn rustbook(build: &Build, target: &str, name: &str) { .arg(out)); } +pub fn book(build: &Build, target: &str, name: &str) { + rustbook(build, target, &format!("{}/first-edition", name)); + rustbook(build, target, &format!("{}/second-edition", name)); +} + /// Generates all standalone documentation as compiled by the rustdoc in `stage` /// for the `target` into `out`. /// diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6b047c62d99be..6eb12fed5abb2 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -581,7 +581,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .stage(0) }) .default(build.config.docs) - .run(move |s| doc::rustbook(build, s.target, "book")); + .run(move |s| doc::book(build, s.target, "book")); rules.doc("doc-nomicon", "src/doc/nomicon") .dep(move |s| { s.name("tool-rustbook") From 5f2f3d07dc74f0c66e1d9d9c09bcaa6e9db7780c Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 15:31:41 -0500 Subject: [PATCH 136/662] build book index --- src/bootstrap/doc.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 3c024f4c4efd4..f94db1c26c14b 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -53,9 +53,58 @@ pub fn rustbook(build: &Build, target: &str, name: &str) { .arg(out)); } +/// Build the book and associated stuff. +/// +/// We need to build: +/// +/// * Book (first edition) +/// * Book (second edition) +/// * Index page +/// * Redirect pages pub fn book(build: &Build, target: &str, name: &str) { + // build book first edition rustbook(build, target, &format!("{}/first-edition", name)); + + // build book second edition rustbook(build, target, &format!("{}/second-edition", name)); + + // build the index page + let index = format!("{}/index.md", name); + invoke_rustdoc(build, target, &index); +} + +fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) { + let out = build.doc_out(target); + + let compiler = Compiler::new(0, &build.config.build); + + let path = build.src.join("src/doc").join(markdown); + + let rustdoc = build.rustdoc(&compiler); + + let favicon = build.src.join("src/doc/favicon.inc"); + let footer = build.src.join("src/doc/footer.inc"); + t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css"))); + + let version_info = out.join("version_info.html"); + + let mut cmd = Command::new(&rustdoc); + + build.add_rustc_lib_path(&compiler, &mut cmd); + + let out = out.join("book"); + + cmd.arg("--html-after-content").arg(&footer) + .arg("--html-before-content").arg(&version_info) + .arg("--html-in-header").arg(&favicon) + .arg("--markdown-playground-url") + .arg("https://play.rust-lang.org/") + .arg("-o").arg(&out) + .arg(&path) + .arg("--markdown-css") + .arg("rust.css"); + + build.run(&mut cmd); } /// Generates all standalone documentation as compiled by the rustdoc in `stage` From 422330df2853695987f47cc8c5e25a36e232ea27 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 16:07:55 -0500 Subject: [PATCH 137/662] Render redirect pages. These pages will help people who have links to the older book. --- src/bootstrap/doc.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f94db1c26c14b..26bcaf1345678 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -71,6 +71,15 @@ pub fn book(build: &Build, target: &str, name: &str) { // build the index page let index = format!("{}/index.md", name); invoke_rustdoc(build, target, &index); + + // build the redirect pages + for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { + let file = t!(file); + let path = file.path(); + let path = path.to_str().unwrap(); + + invoke_rustdoc(build, target, path); + } } fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) { From c97b48f261f05581ef0df161ff1cf0bc2946903e Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 16:29:05 -0500 Subject: [PATCH 138/662] Fix up some issues. Becuase I had run a `x.py doc` before doing this work, I had accidentally relied on some files existing in places that they didn't need to be. --- src/bootstrap/doc.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 26bcaf1345678..da87b3bfe0cd4 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -70,9 +70,11 @@ pub fn book(build: &Build, target: &str, name: &str) { // build the index page let index = format!("{}/index.md", name); + println!("Documenting book index ({})", target); invoke_rustdoc(build, target, &index); // build the redirect pages + println!("Documenting book redirect pages ({})", target); for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { let file = t!(file); let path = file.path(); @@ -93,16 +95,27 @@ fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) { let favicon = build.src.join("src/doc/favicon.inc"); let footer = build.src.join("src/doc/footer.inc"); - t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css"))); + let version_input = build.src.join("src/doc/version_info.html.template"); let version_info = out.join("version_info.html"); + if !up_to_date(&version_input, &version_info) { + let mut info = String::new(); + t!(t!(File::open(&version_input)).read_to_string(&mut info)); + let info = info.replace("VERSION", &build.rust_release()) + .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or("")) + .replace("STAMP", build.rust_info.sha().unwrap_or("")); + t!(t!(File::create(&version_info)).write_all(info.as_bytes())); + } + let mut cmd = Command::new(&rustdoc); build.add_rustc_lib_path(&compiler, &mut cmd); let out = out.join("book"); + t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css"))); + cmd.arg("--html-after-content").arg(&footer) .arg("--html-before-content").arg(&version_info) .arg("--html-in-header").arg(&favicon) From 966e72156ff8aae61b53009edbaaf765ca96b621 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 7 Mar 2017 17:19:25 -0500 Subject: [PATCH 139/662] fix whitespace --- src/bootstrap/doc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index da87b3bfe0cd4..baee1ada508f2 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -72,7 +72,7 @@ pub fn book(build: &Build, target: &str, name: &str) { let index = format!("{}/index.md", name); println!("Documenting book index ({})", target); invoke_rustdoc(build, target, &index); - + // build the redirect pages println!("Documenting book redirect pages ({})", target); for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { From 23304593a6790368aa84e3f11712173e8024e363 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 13 Mar 2017 16:41:31 -0400 Subject: [PATCH 140/662] skip nostarch directory This is for coordinating with our publishers; we don't ever want to test it. --- src/bootstrap/check.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0d962bd3b0c93..40cdb9242df15 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -285,6 +285,16 @@ pub fn docs(build: &Build, compiler: &Compiler) { continue } + // The nostarch directory in the book is for no starch, and so isn't guaranteed to build. + // we don't care if it doesn't build, so skip it. + use std::ffi::OsStr; + let path: &OsStr = p.as_ref(); + if let Some(path) = path.to_str() { + if path.contains("nostarch") { + continue; + } + } + println!("doc tests for: {}", p.display()); markdown_test(build, compiler, &p); } From c0e7b16f61e159cb1d4ed9be6e0dc822a02a0a56 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 14 Mar 2017 11:01:24 -0400 Subject: [PATCH 141/662] Update book and reference submodules Some links needed adjustment to support this new scheme. --- src/doc/book | 2 +- src/doc/reference | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book b/src/doc/book index 979c56634f3fe..e6d6caab41471 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 979c56634f3fe594c9554c555eee29311d7d4a50 +Subproject commit e6d6caab41471f7115a621029bd428a812c5260e diff --git a/src/doc/reference b/src/doc/reference index 2d23ea601f017..516549972d61c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 2d23ea601f017c106a2303094ee1c57ba856d246 +Subproject commit 516549972d61c8946542d1a34afeae97167ff77b From d1d9626e7577546585f216f8ee11be824b374f78 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Wed, 15 Mar 2017 12:13:55 -0400 Subject: [PATCH 142/662] Fix up various links The unstable book, libstd, libcore, and liballoc all needed some adjustment. --- src/doc/unstable-book/src/plugin.md | 2 +- src/liballoc/arc.rs | 2 +- src/liballoc/rc.rs | 2 +- src/libcore/char.rs | 4 ++-- src/libcore/iter/iterator.rs | 4 ++-- src/libcore/mem.rs | 10 +++++----- src/libcore/raw.rs | 2 +- src/libstd/lib.rs | 10 +++++----- src/libstd/primitive_docs.rs | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/doc/unstable-book/src/plugin.md b/src/doc/unstable-book/src/plugin.md index ca69b7084d3e6..3a1872e18ddb8 100644 --- a/src/doc/unstable-book/src/plugin.md +++ b/src/doc/unstable-book/src/plugin.md @@ -137,7 +137,7 @@ of extensions. See `Registry::register_syntax_extension` and the ## Tips and tricks -Some of the [macro debugging tips](../book/macros.html#debugging-macro-code) are applicable. +Some of the [macro debugging tips](../book/first-edition/macros.html#debugging-macro-code) are applicable. You can use `syntax::parse` to turn token trees into higher-level syntax elements like expressions: diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 1d616233881b4..28f6d97756f2c 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -102,7 +102,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// [downgrade]: struct.Arc.html#method.downgrade /// [upgrade]: struct.Weak.html#method.upgrade /// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [assoc]: ../../book/method-syntax.html#associated-functions +/// [assoc]: ../../book/first-edition/method-syntax.html#associated-functions /// /// # Examples /// diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index e9b59017692eb..561ccaa5ef5ca 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -215,7 +215,7 @@ //! [downgrade]: struct.Rc.html#method.downgrade //! [upgrade]: struct.Weak.html#method.upgrade //! [`None`]: ../../std/option/enum.Option.html#variant.None -//! [assoc]: ../../book/method-syntax.html#associated-functions +//! [assoc]: ../../book/first-edition/method-syntax.html#associated-functions //! [mutability]: ../../std/cell/index.html#introducing-mutability-inside-of-something-immutable #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 649fdf394e422..19e69ca296d8f 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -94,7 +94,7 @@ pub const MAX: char = '\u{10ffff}'; /// /// [`char`]: ../../std/primitive.char.html /// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/casting-between-types.html#as +/// [`as`]: ../../book/first-edition/casting-between-types.html#as /// /// For an unsafe version of this function which ignores these checks, see /// [`from_u32_unchecked`]. @@ -146,7 +146,7 @@ pub fn from_u32(i: u32) -> Option { /// /// [`char`]: ../../std/primitive.char.html /// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/casting-between-types.html#as +/// [`as`]: ../../book/first-edition/casting-between-types.html#as /// /// # Safety /// diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 1301c311c14ca..fb98e43aa614b 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -409,7 +409,7 @@ pub trait Iterator { /// If you're doing some sort of looping for a side effect, it's considered /// more idiomatic to use [`for`] than `map()`. /// - /// [`for`]: ../../book/loops.html#for + /// [`for`]: ../../book/first-edition/loops.html#for /// /// # Examples /// @@ -1306,7 +1306,7 @@ pub trait Iterator { /// use a `for` loop with a list of things to build up a result. Those /// can be turned into `fold()`s: /// - /// [`for`]: ../../book/loops.html#for + /// [`for`]: ../../book/first-edition/loops.html#for /// /// ``` /// let numbers = [1, 2, 3, 4, 5]; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index ba65e4494a8bb..f5cf3724d0711 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -164,7 +164,7 @@ pub use intrinsics::transmute; /// [uninit]: fn.uninitialized.html /// [clone]: ../clone/trait.Clone.html /// [swap]: fn.swap.html -/// [FFI]: ../../book/ffi.html +/// [FFI]: ../../book/first-edition/ffi.html /// [box]: ../../std/boxed/struct.Box.html /// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw /// [ub]: ../../reference/behavior-considered-undefined.html @@ -199,7 +199,7 @@ pub fn size_of() -> usize { /// then `size_of_val` can be used to get the dynamically-known size. /// /// [slice]: ../../std/primitive.slice.html -/// [trait object]: ../../book/trait-objects.html +/// [trait object]: ../../book/first-edition/trait-objects.html /// /// # Examples /// @@ -317,7 +317,7 @@ pub fn align_of_val(val: &T) -> usize { /// many of the same caveats. /// /// [uninit]: fn.uninitialized.html -/// [FFI]: ../../book/ffi.html +/// [FFI]: ../../book/first-edition/ffi.html /// [ub]: ../../reference/behavior-considered-undefined.html /// /// # Examples @@ -343,7 +343,7 @@ pub unsafe fn zeroed() -> T { /// This is useful for [FFI] functions and initializing arrays sometimes, /// but should generally be avoided. /// -/// [FFI]: ../../book/ffi.html +/// [FFI]: ../../book/first-edition/ffi.html /// /// # Undefined behavior /// @@ -525,7 +525,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// it will not release any borrows, as borrows are based on lexical scope. /// /// This effectively does nothing for -/// [types which implement `Copy`](../../book/ownership.html#copy-types), +/// [types which implement `Copy`](../../book/first-edition/ownership.html#copy-types), /// e.g. integers. Such values are copied and _then_ moved into the function, /// so the value persists after this function call. /// diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index a7d0d3899b181..a95f05227fb8b 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -25,7 +25,7 @@ /// Book][moreinfo] contains more details about the precise nature of /// these internals. /// -/// [moreinfo]: ../../book/trait-objects.html#representation +/// [moreinfo]: ../../book/first-edition/trait-objects.html#representation /// /// `TraitObject` is guaranteed to match layouts, but it is not the /// type of trait objects (e.g. the fields are not directly accessible diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d01ed1e3fe63a..3da5d4b94dd08 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -174,7 +174,7 @@ //! [slice]: primitive.slice.html //! [`atomic`]: sync/atomic/index.html //! [`collections`]: collections/index.html -//! [`for`]: ../book/loops.html#for +//! [`for`]: ../book/first-edition/loops.html#for //! [`format!`]: macro.format.html //! [`fs`]: fs/index.html //! [`io`]: io/index.html @@ -189,14 +189,14 @@ //! [`sync`]: sync/index.html //! [`thread`]: thread/index.html //! [`use std::env`]: env/index.html -//! [`use`]: ../book/crates-and-modules.html#importing-modules-with-use -//! [crate root]: ../book/crates-and-modules.html#basic-terminology-crates-and-modules +//! [`use`]: ../book/first-edition/crates-and-modules.html#importing-modules-with-use +//! [crate root]: ../book/first-edition/crates-and-modules.html#basic-terminology-crates-and-modules //! [crates.io]: https://crates.io -//! [deref coercions]: ../book/deref-coercions.html +//! [deref coercions]: ../book/first-edition/deref-coercions.html //! [files]: fs/struct.File.html //! [multithreading]: thread/index.html //! [other]: #what-is-in-the-standard-library-documentation -//! [primitive types]: ../book/primitive-types.html +//! [primitive types]: ../book/first-edition/primitive-types.html #![crate_name = "std"] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 7d6d16f474845..c738dc9440614 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -29,7 +29,7 @@ /// ``` /// /// [`assert!`]: macro.assert.html -/// [`if`]: ../book/if.html +/// [`if`]: ../book/first-edition/if.html /// [`BitAnd`]: ops/trait.BitAnd.html /// [`BitOr`]: ops/trait.BitOr.html /// [`Not`]: ops/trait.Not.html @@ -490,7 +490,7 @@ mod prim_str { } /// assert_eq!(tuple.2, 'c'); /// ``` /// -/// For more about tuples, see [the book](../book/primitive-types.html#tuples). +/// For more about tuples, see [the book](../book/first-edition/primitive-types.html#tuples). /// /// # Trait implementations /// From 4eef581817dc26e3952a18f26506f3e0f522062f Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Wed, 15 Mar 2017 17:03:50 -0400 Subject: [PATCH 143/662] exempt hbs from linkchecker --- src/tools/linkchecker/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index ba5ca44526b86..e83a1f8aea73f 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -121,6 +121,12 @@ fn check(cache: &mut Cache, if file.extension().and_then(|s| s.to_str()) == Some("js") { return None; } + + // ignore handlebars files as they use {{}} to build links, we only + // want to test the generated files + if file.extension().and_then(|s| s.to_str()) == Some("hbs") { + return None; + } // Unfortunately we're not 100% full of valid links today to we need a few // whitelists to get this past `make check` today. From 96d35947c36bba6c6545c06768b5358c0f8bf3dc Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 17 Mar 2017 09:25:29 -0400 Subject: [PATCH 144/662] fix trailing whitespace --- src/tools/linkchecker/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index e83a1f8aea73f..8c4eb728b7561 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -121,7 +121,7 @@ fn check(cache: &mut Cache, if file.extension().and_then(|s| s.to_str()) == Some("js") { return None; } - + // ignore handlebars files as they use {{}} to build links, we only // want to test the generated files if file.extension().and_then(|s| s.to_str()) == Some("hbs") { From aa83d7107fcecf63c1bbcf17a96b4fcb1e17aa98 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 20 Mar 2017 19:28:04 +0100 Subject: [PATCH 145/662] config.toml.example: nightlies.txt got removed Instead, stage0.txt got introduced. See also commit 02538d463a350f5c3658f7aabefca16eb599d31c --- src/bootstrap/config.toml.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 76fedae0f03eb..6b2cc6eb6474c 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -88,11 +88,11 @@ # for each target triple. #target = ["x86_64-unknown-linux-gnu"] # defaults to just the build triple -# Instead of downloading the src/nightlies.txt version of Cargo specified, use +# Instead of downloading the src/stage0.txt version of Cargo specified, use # this Cargo binary instead to build all Rust code #cargo = "/path/to/bin/cargo" -# Instead of downloading the src/nightlies.txt version of the compiler +# Instead of downloading the src/stage0.txt version of the compiler # specified, use this rustc binary instead as the stage0 snapshot compiler. #rustc = "/path/to/bin/rustc" From 67867c663593e60108d09310752e5758b291e6ce Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 20 Mar 2017 13:11:58 -0600 Subject: [PATCH 146/662] Update docs for std::str --- src/libcollections/str.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 90e54a383d623..40abc8a96f066 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -59,6 +59,27 @@ pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; +/// Unicode string slices. +/// +/// The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents +/// are borrowed and therefore cannot be moved someplace else. +/// +/// # Basic Usage +/// A basic string declaration of `&str` type: +/// +/// ``` +/// let hello_world = "Hello, World!"; +/// ``` +/// Here we have declared a string literal, also known as a string slice. +/// String literals have a static lifetime, which means the string `hello_world` +/// is guaranteed to be valid for the duration of the entire program. We can explicitly specify +/// `hello_world`'s lifetime as well: +/// +/// ``` +/// let hello_world:&'static str = "Hello, world!"; +/// ``` +/// + #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] From 63652726c39a0c018b7897f7c3e92690c3599207 Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 20 Mar 2017 15:21:28 -0600 Subject: [PATCH 147/662] Move str docs to proper place in file. --- src/libcollections/str.rs | 41 ++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 40abc8a96f066..c87e2b086adda 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,9 +10,27 @@ //! Unicode string slices. //! +//! The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents +//! are borrowed and therefore cannot be moved someplace else. +//! +//! # Basic Usage +//! A basic string declaration of `&str` type: +//! +//! ``` +//! let hello_world = "Hello, World!"; +//! ``` +//! +//! Here we have declared a string literal, also known as a string slice. +//! String literals have a static lifetime, which means the string `hello_world` +//! is guaranteed to be valid for the duration of the entire program. We can explicitly specify +//! `hello_world`'s lifetime as well: +//! +//! ``` +//! let hello_world:&'static str = "Hello, world!"; +//! ``` +//! //! *[See also the `str` primitive type](../../std/primitive.str.html).* - #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -59,27 +77,6 @@ pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; -/// Unicode string slices. -/// -/// The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents -/// are borrowed and therefore cannot be moved someplace else. -/// -/// # Basic Usage -/// A basic string declaration of `&str` type: -/// -/// ``` -/// let hello_world = "Hello, World!"; -/// ``` -/// Here we have declared a string literal, also known as a string slice. -/// String literals have a static lifetime, which means the string `hello_world` -/// is guaranteed to be valid for the duration of the entire program. We can explicitly specify -/// `hello_world`'s lifetime as well: -/// -/// ``` -/// let hello_world:&'static str = "Hello, world!"; -/// ``` -/// - #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] From 1a00c8fe0f2c5c20509a7337a5776386cb00f09b Mon Sep 17 00:00:00 2001 From: portal Date: Mon, 20 Mar 2017 23:29:04 +0200 Subject: [PATCH 148/662] Add missing associated type Item to Iterator --- src/doc/unstable-book/src/conservative-impl-trait.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/conservative-impl-trait.md b/src/doc/unstable-book/src/conservative-impl-trait.md index 62a7f8c16a0a7..0be6a321103f0 100644 --- a/src/doc/unstable-book/src/conservative-impl-trait.md +++ b/src/doc/unstable-book/src/conservative-impl-trait.md @@ -33,9 +33,9 @@ fn main() { In today's Rust, you can write function signatures like: ````rust,ignore -fn consume_iter_static>(iter: I) { } +fn consume_iter_static>(iter: I) { } -fn consume_iter_dynamic(iter: Box>) { } +fn consume_iter_dynamic(iter: Box>) { } ```` In both cases, the function does not depend on the exact type of the argument. @@ -50,13 +50,13 @@ The type held is "abstract", and is assumed only to satisfy a trait bound. On the other hand, while you can write: ````rust,ignore -fn produce_iter_dynamic() -> Box> { } +fn produce_iter_dynamic() -> Box> { } ```` ...but you _cannot_ write something like: ````rust,ignore -fn produce_iter_static() -> Iterator { } +fn produce_iter_static() -> Iterator { } ```` That is, in today's Rust, abstract return types can only be written using trait From 7305ca38529d6cd9cb916f9303f85aa99c36b3c7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Mar 2017 14:29:14 -0700 Subject: [PATCH 149/662] travis: Don't set `RUST_LOG` globally I have a suspicion that this caused a large regression in cycle times by forcing the compiler to perform more checks on every `debug!` statement, so let's test this out by removing the `RUST_LOG` env var globally. This regression in cycle time was witnessed between [two] [builds] where the [PR] in question didn't do much suspicious. Judging by how the stage0 times *also* regressed though then this is my best guess. [two]: https://travis-ci.org/rust-lang/rust/builds/210149932 [builds]: https://travis-ci.org/rust-lang/rust/builds/210179995 [PR]: https://github.com/rust-lang/rust/pull/40446 --- .travis.yml | 5 ----- appveyor.yml | 1 - src/Cargo.lock | 14 +++++++------- src/bootstrap/native.rs | 5 +++++ src/ci/docker/run.sh | 1 - 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index fb9e2136f1b09..b4f558099da51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,7 +47,6 @@ matrix: SRC=. RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - RUST_LOG=sccache=debug MACOSX_DEPLOYMENT_TARGET=10.8 MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx @@ -61,7 +60,6 @@ matrix: SRC=. RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - RUST_LOG=sccache=debug MACOSX_DEPLOYMENT_TARGET=10.8 MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx @@ -75,7 +73,6 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - RUST_LOG=sccache=debug MACOSX_DEPLOYMENT_TARGET=10.8 MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx @@ -90,7 +87,6 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - RUST_LOG=sccache=debug MACOSX_DEPLOYMENT_TARGET=10.8 MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx @@ -109,7 +105,6 @@ matrix: DEPLOY_ALT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - RUST_LOG=sccache=debug MACOSX_DEPLOYMENT_TARGET=10.8 MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx diff --git a/appveyor.yml b/appveyor.yml index 8de49cc834d33..499f7d602e368 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -131,7 +131,6 @@ install: - handle.exe -accepteula -help # Attempt to debug sccache failures - - set RUST_LOG=sccache=debug - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: diff --git a/src/Cargo.lock b/src/Cargo.lock index a9a6fabb5b23c..9ae894061a676 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -73,7 +73,7 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -119,7 +119,7 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", @@ -471,7 +471,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -614,7 +614,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -658,7 +658,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -752,7 +752,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -994,7 +994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" "checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" -"checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" +"checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index dea1a607255a8..62eed8be3ccb7 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -18,6 +18,7 @@ //! LLVM and compiler-rt are essentially just wired up to everything else to //! ensure that they're always in place if needed. +use std::env; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::Path; @@ -145,6 +146,10 @@ pub fn llvm(build: &Build, target: &str) { cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); } + if env::var_os("SCCACHE_ERROR_LOG").is_some() { + cfg.env("RUST_LOG", "sccache=debug"); + } + // FIXME: we don't actually need to build all LLVM tools and all LLVM // libraries here, e.g. we just want a few components and a few // tools. Figure out how to filter them down and only build the right diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index b5a713dc38259..c418d427b15b3 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -39,7 +39,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" args="$args --env SCCACHE_LOG_LEVEL=debug" - args="$args --env RUST_LOG=sccache=debug" args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache From f628117529dfb117d87d62803d0746bedd6e0e83 Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 20 Mar 2017 20:20:12 -0600 Subject: [PATCH 150/662] Fix Rust linting error --- src/libcollections/str.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c87e2b086adda..d4480ce77d646 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,8 +10,9 @@ //! Unicode string slices. //! -//! The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents -//! are borrowed and therefore cannot be moved someplace else. +//! The `&str` type is one of the two main string types, the other being `String`. +//! Unlike its `String` counterpart, its contents are borrowed and therefore +//! cannot be moved someplace else. //! //! # Basic Usage //! A basic string declaration of `&str` type: @@ -22,8 +23,8 @@ //! //! Here we have declared a string literal, also known as a string slice. //! String literals have a static lifetime, which means the string `hello_world` -//! is guaranteed to be valid for the duration of the entire program. We can explicitly specify -//! `hello_world`'s lifetime as well: +//! is guaranteed to be valid for the duration of the entire program. +//! We can explicitly specify `hello_world`'s lifetime as well: //! //! ``` //! let hello_world:&'static str = "Hello, world!"; From 8e58d9eb8f5b86c2b2f740aaebdb984fed065f8d Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 21 Mar 2017 00:09:20 -0700 Subject: [PATCH 151/662] Use Iterator::find in associated_item search --- src/librustc/ty/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 610a6d6d8eeaf..9c17138a9322a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2585,24 +2585,22 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let parent_item = tcx.hir.expect_item(parent_id); match parent_item.node { hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { - for impl_item_ref in impl_item_refs { + if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.node_id == id) { let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id, impl_trait_ref.is_some(), impl_item_ref); - if assoc_item.def_id == def_id { - return assoc_item; - } + debug_assert_eq!(assoc_item.def_id, def_id); + return assoc_item; } } hir::ItemTrait(.., ref trait_item_refs) => { - for trait_item_ref in trait_item_refs { + if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.node_id == id) { let assoc_item = tcx.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref); - if assoc_item.def_id == def_id { - return assoc_item; - } + debug_assert_eq!(assoc_item.def_id, def_id); + return assoc_item; } } From 27151017e987044a35ae45f8c9bd8530af9e5f47 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Mar 2017 16:23:27 +0100 Subject: [PATCH 152/662] Add missing urls in ptr docs --- src/libstd/primitive_docs.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 7d6d16f474845..ba14a3d6b47e7 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -183,9 +183,9 @@ mod prim_unit { } /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// -/// Use the `null` function to create null pointers, and the `is_null` method +/// Use the [`null`] function to create null pointers, and the [`is_null`] method /// of the `*const T` type to check for null. The `*const T` type also defines -/// the `offset` method, for pointer math. +/// the [`offset`] method, for pointer math. /// /// # Common ways to create raw pointers /// @@ -213,7 +213,7 @@ mod prim_unit { } /// /// ## 2. Consume a box (`Box`). /// -/// The `into_raw` function consumes a box and returns +/// The [`into_raw`] function consumes a box and returns /// the raw pointer. It doesn't destroy `T` or deallocate any memory. /// /// ``` @@ -227,7 +227,7 @@ mod prim_unit { } /// } /// ``` /// -/// Note that here the call to `drop` is for clarity - it indicates +/// Note that here the call to [`drop`] is for clarity - it indicates /// that we are done with the given value and it should be destroyed. /// /// ## 3. Get it from C. @@ -255,6 +255,11 @@ mod prim_unit { } /// /// *[See also the `std::ptr` module](ptr/index.html).* /// +/// [`null`]: ../std/ptr/fn.null.html +/// [`is_null`]: ../std/primitive.pointer.html#method.is_null +/// [`offset`]: ../std/primitive.pointer.html#method.offset +/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw +/// [`drop`]: ../std/mem/fn.drop.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer { } From 1f656106750c7fc37f8f9d666b560294b80894f0 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 17 Mar 2017 20:52:44 +0100 Subject: [PATCH 153/662] ci/netbsd: use the "official" cross compiler --- .../docker/dist-s390x-linux-netbsd/Dockerfile | 12 +- .../build-netbsd-toolchain.sh | 145 ++++++------------ src/librustc_llvm/build.rs | 6 + 3 files changed, 63 insertions(+), 100 deletions(-) diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index fd67f185162d9..c68f30a6e563b 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -64,17 +64,17 @@ COPY patches/ /tmp/patches/ COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ RUN ./build-s390x-toolchain.sh -USER root - COPY build-netbsd-toolchain.sh /tmp/ RUN ./build-netbsd-toolchain.sh -ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin +USER root + +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin ENV \ - AR_x86_64_unknown_netbsd=x86_64-unknown-netbsd-ar \ - CC_x86_64_unknown_netbsd=x86_64-unknown-netbsd-gcc \ - CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ \ + AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ + CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ + CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot \ CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh index 654b458ea409e..ad5db04179262 100755 --- a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh @@ -13,108 +13,65 @@ set -ex -BINUTILS=2.25.1 -GCC=5.3.0 +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} -# First up, build binutils -mkdir binutils -cd binutils -curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - -mkdir binutils-build -cd binutils-build -../binutils-$BINUTILS/configure \ - --target=x86_64-unknown-netbsd -make -j10 -make install -cd ../.. -rm -rf binutils - -# Next, download the NetBSD libc and relevant header files mkdir netbsd -# originally from: -# https://ftp.netbsd.org/pub/NetBSD/NetBSD-7.0/amd64/binary/sets/base.tgz -curl https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-16-netbsd-base.tgz | \ - tar xzf - -C netbsd ./usr/include ./usr/lib ./lib -# originally from: -# https://ftp.netbsd.org/pub/NetBSD/NetBSD-7.0/amd64/binary/sets/comp.tgz -curl https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-16-netbsd-comp.tgz | \ - tar xzf - -C netbsd ./usr/include ./usr/lib +cd netbsd -dst=/usr/local/x86_64-unknown-netbsd -cp -r netbsd/usr/include $dst -cp netbsd/usr/lib/crt0.o $dst/lib -cp netbsd/usr/lib/crti.o $dst/lib -cp netbsd/usr/lib/crtn.o $dst/lib -cp netbsd/usr/lib/crtbeginS.o $dst/lib -cp netbsd/usr/lib/crtendS.o $dst/lib -cp netbsd/usr/lib/crtbegin.o $dst/lib -cp netbsd/usr/lib/crtend.o $dst/lib -cp netbsd/usr/lib/gcrt0.o $dst/lib -cp netbsd/usr/lib/libc.a $dst/lib -cp netbsd/usr/lib/libc_p.a $dst/lib -cp netbsd/usr/lib/libc_pic.a $dst/lib -cp netbsd/lib/libc.so.12.193.1 $dst/lib -cp netbsd/lib/libutil.so.7.21 $dst/lib -cp netbsd/usr/lib/libm.a $dst/lib -cp netbsd/usr/lib/libm_p.a $dst/lib -cp netbsd/usr/lib/libm_pic.a $dst/lib -cp netbsd/lib/libm.so.0.11 $dst/lib -cp netbsd/usr/lib/librt.so.1.1 $dst/lib -cp netbsd/usr/lib/libpthread.a $dst/lib -cp netbsd/usr/lib/libpthread_p.a $dst/lib -cp netbsd/usr/lib/libpthread_pic.a $dst/lib -cp netbsd/usr/lib/libpthread.so.1.2 $dst/lib +mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -ln -s libc.so.12.193.1 $dst/lib/libc.so -ln -s libc.so.12.193.1 $dst/lib/libc.so.12 -ln -s libm.so.0.11 $dst/lib/libm.so -ln -s libm.so.0.11 $dst/lib/libm.so.0 -ln -s libutil.so.7.21 $dst/lib/libutil.so -ln -s libutil.so.7.21 $dst/lib/libutil.so.7 -ln -s libpthread.so.1.2 $dst/lib/libpthread.so -ln -s libpthread.so.1.2 $dst/lib/libpthread.so.1 -ln -s librt.so.1.1 $dst/lib/librt.so +BSD=7.0.2 -rm -rf netbsd +# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz +curl https://dl.timnn.me/69608745091236e7/$BSD/src.tgz | tar xzf - +curl https://dl.timnn.me/69608745091236e7/$BSD/gnusrc.tgz | tar xzf - +curl https://dl.timnn.me/69608745091236e7/$BSD/sharesrc.tgz | tar xzf - +curl https://dl.timnn.me/69608745091236e7/$BSD/syssrc.tgz | tar xzf - -# Finally, download and build gcc to target NetBSD -mkdir gcc -cd gcc -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - -cd gcc-$GCC -./contrib/download_prerequisites +# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/amd64/binary/sets/*.tgz +curl https://dl.timnn.me/69608745091236e7/$BSD/base.tgz | \ + tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib +curl https://dl.timnn.me/69608745091236e7/$BSD/comp.tgz | \ + tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib -# Originally from -# ftp://ftp.netbsd.org/pub/pkgsrc/pkgsrc-2016Q4/pkgsrc/lang/gcc5/patches/patch-libstdc%2B%2B-v3_config_os_bsd_netbsd_ctype__base.h -PATCHES="https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-13-netbsd-patch1.patch" +cd usr/src -# Originally from -# ftp://ftp.netbsd.org/pub/pkgsrc/pkgsrc-2016Q4/pkgsrc/lang/gcc5/patches/patch-libstdc%2B%2B-v3_config_os_bsd_netbsd_ctype__configure__char.cc -PATCHES="$PATCHES https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-13-netbsd-patch2.patch" +# The options, in order, do the following +# * this is an unpriviledged build +# * output to a predictable location +# * disable various uneeded stuff +MKUNPRIVED=yes TOOLDIR=/x-tools/x86_64-unknown-netbsd \ +MKSHARE=no MKDOC=no MKHTML=no MKINFO=no MKKMOD=no MKLINT=no MKMAN=no MKNLS=no MKPROFILE=no \ +hide_output ./build.sh -j10 -m amd64 tools -for patch in $PATCHES; do - curl $patch | patch -Np0 -done +cd ../.. -mkdir ../gcc-build -cd ../gcc-build -../gcc-$GCC/configure \ - --enable-languages=c,c++ \ - --target=x86_64-unknown-netbsd \ - --disable-libcilkrts \ - --disable-multilib \ - --disable-nls \ - --disable-libgomp \ - --disable-libquadmath \ - --disable-libssp \ - --disable-libvtv \ - --disable-libcilkrt \ - --disable-libada \ - --disable-libsanitizer \ - --disable-libquadmath-support \ - --disable-lto -make -j10 -make install +rm -rf usr -cd ../.. -rm -rf gcc +cat > /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot <<'EOF' +#!/bin/bash +exec /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc --sysroot=/x-tools/x86_64-unknown-netbsd/sysroot "$@" +EOF + +cat > /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot <<'EOF' +#!/bin/bash +exec /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++ --sysroot=/x-tools/x86_64-unknown-netbsd/sysroot "$@" +EOF + +chmod +x /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot +chmod +x /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index b74bccb70593f..7f53e21675c78 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -131,6 +131,12 @@ fn main() { if is_crossed && flag.starts_with("-m") { continue; } + + // -Wdate-time is not supported by the netbsd cross compiler + if is_crossed && target.contains("netbsd") && flag.contains("date-time") { + continue; + } + cfg.flag(flag); } From 7ae7bf31e24fc2c149ccf50f09a4305eb49b8147 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Mar 2017 14:01:06 -0700 Subject: [PATCH 154/662] Switch to rust-lang-ci mirror URLs --- .../build-netbsd-toolchain.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh index ad5db04179262..6d9728a06fd8c 100755 --- a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh @@ -35,18 +35,18 @@ cd netbsd mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -BSD=7.0.2 +URL=https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz -curl https://dl.timnn.me/69608745091236e7/$BSD/src.tgz | tar xzf - -curl https://dl.timnn.me/69608745091236e7/$BSD/gnusrc.tgz | tar xzf - -curl https://dl.timnn.me/69608745091236e7/$BSD/sharesrc.tgz | tar xzf - -curl https://dl.timnn.me/69608745091236e7/$BSD/syssrc.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-src.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-gnusrc.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-sharesrc.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-syssrc.tgz | tar xzf - # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/amd64/binary/sets/*.tgz -curl https://dl.timnn.me/69608745091236e7/$BSD/base.tgz | \ +curl $URL/2017-03-17-netbsd-base.tgz | \ tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib -curl https://dl.timnn.me/69608745091236e7/$BSD/comp.tgz | \ +curl $URL/2017-03-17-netbsd-comp.tgz | \ tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib cd usr/src From ba90248dac1f3ee124623209b3eaa3e310679298 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 19 Mar 2017 11:42:30 +0100 Subject: [PATCH 155/662] include compiler hash in wrapper scripts --- .../dist-s390x-linux-netbsd/build-netbsd-toolchain.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh index 6d9728a06fd8c..ea335a249736c 100755 --- a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh @@ -73,5 +73,11 @@ cat > /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot <<'EOF' exec /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++ --sysroot=/x-tools/x86_64-unknown-netbsd/sysroot "$@" EOF +GCC_SHA1=`sha1sum -b /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc | cut -d' ' -f1` +GPP_SHA1=`sha1sum -b /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++ | cut -d' ' -f1` + +echo "# $GCC_SHA1" >> /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot +echo "# $GPP_SHA1" >> /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot + chmod +x /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot chmod +x /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot From 43a51b78b8c24f2bd40b20d1a082db1443075c19 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 19 Mar 2017 19:31:49 +0100 Subject: [PATCH 156/662] link agains relocatable libstdc++ --- src/librustc_llvm/build.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 7f53e21675c78..42717ec289c34 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -233,16 +233,21 @@ fn main() { } } - // OpenBSD has a particular C++ runtime library name + let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP"); + let stdcppname = if target.contains("openbsd") { + // OpenBSD has a particular C++ runtime library name "estdc++" + } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { + // NetBSD uses a separate library when relocation is required + "stdc++_pic" } else { "stdc++" }; // C++ runtime library if !target.contains("msvc") { - if let Some(s) = env::var_os("LLVM_STATIC_STDCPP") { + if let Some(s) = llvm_static_stdcpp { assert!(!cxxflags.contains("stdlib=libc++")); let path = PathBuf::from(s); println!("cargo:rustc-link-search=native={}", From 88d5645fb861354f46d507f8d5764e79ae099519 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Wed, 1 Mar 2017 19:54:30 +0100 Subject: [PATCH 157/662] dist-x86-linux: ugrade gcc to 4.8.5 --- src/ci/docker/dist-x86-linux/Dockerfile | 1 + src/ci/docker/dist-x86-linux/build-gcc.sh | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 852ce1806ec62..cd4c81912dff5 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -6,6 +6,7 @@ RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ gcc \ + gcc-c++ \ make \ glibc-devel \ perl \ diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-x86-linux/build-gcc.sh index 06198eb0c97fc..ab2562538d6d7 100755 --- a/src/ci/docker/dist-x86-linux/build-gcc.sh +++ b/src/ci/docker/dist-x86-linux/build-gcc.sh @@ -13,12 +13,14 @@ set -ex source shared.sh -curl https://ftp.gnu.org/gnu/gcc/gcc-4.7.4/gcc-4.7.4.tar.bz2 | tar xjf - -cd gcc-4.7.4 +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC ./contrib/download_prerequisites mkdir ../gcc-build cd ../gcc-build -hide_output ../gcc-4.7.4/configure \ +hide_output ../gcc-$GCC/configure \ --prefix=/rustroot \ --enable-languages=c,c++ hide_output make -j10 @@ -27,5 +29,5 @@ ln -nsf gcc /rustroot/bin/cc cd .. rm -rf gcc-build -rm -rf gcc-4.7.4 -yum erase -y gcc binutils +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils From f1913e2a305f2ad9a655cb0a08cbce886e37ac27 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 17 Mar 2017 15:05:44 +0100 Subject: [PATCH 158/662] Implement feature sort_unstable --- src/libcollections/benches/lib.rs | 1 + src/libcollections/benches/slice.rs | 110 +++-- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 156 ++++-- src/libcollectionstest/slice.rs | 14 +- src/libcore/lib.rs | 11 +- src/libcore/{slice.rs => slice/mod.rs} | 112 ++++- src/libcore/slice/sort.rs | 628 +++++++++++++++++++++++++ src/libcoretest/lib.rs | 6 +- src/libcoretest/slice.rs | 41 +- 10 files changed, 967 insertions(+), 113 deletions(-) rename src/libcore/{slice.rs => slice/mod.rs} (97%) create mode 100644 src/libcore/slice/sort.rs diff --git a/src/libcollections/benches/lib.rs b/src/libcollections/benches/lib.rs index 1a21db5e344e3..42064e9ca5750 100644 --- a/src/libcollections/benches/lib.rs +++ b/src/libcollections/benches/lib.rs @@ -11,6 +11,7 @@ #![deny(warnings)] #![feature(rand)] +#![feature(sort_unstable)] #![feature(test)] extern crate test; diff --git a/src/libcollections/benches/slice.rs b/src/libcollections/benches/slice.rs index eb4b76509f913..7195a9f9bf2c6 100644 --- a/src/libcollections/benches/slice.rs +++ b/src/libcollections/benches/slice.rs @@ -169,6 +169,7 @@ fn random_inserts(b: &mut Bencher) { } }) } + #[bench] fn random_removes(b: &mut Bencher) { let mut rng = thread_rng(); @@ -216,65 +217,76 @@ fn gen_mostly_descending(len: usize) -> Vec { v } -fn gen_big_random(len: usize) -> Vec<[u64; 16]> { +fn gen_strings(len: usize) -> Vec { let mut rng = thread_rng(); - rng.gen_iter().map(|x| [x; 16]).take(len).collect() -} - -fn gen_big_ascending(len: usize) -> Vec<[u64; 16]> { - (0..len as u64).map(|x| [x; 16]).take(len).collect() + let mut v = vec![]; + for _ in 0..len { + let n = rng.gen::() % 20 + 1; + v.push(rng.gen_ascii_chars().take(n).collect()); + } + v } -fn gen_big_descending(len: usize) -> Vec<[u64; 16]> { - (0..len as u64).rev().map(|x| [x; 16]).take(len).collect() +fn gen_big_random(len: usize) -> Vec<[u64; 16]> { + let mut rng = thread_rng(); + rng.gen_iter().map(|x| [x; 16]).take(len).collect() } -macro_rules! sort_bench { - ($name:ident, $gen:expr, $len:expr) => { +macro_rules! sort { + ($f:ident, $name:ident, $gen:expr, $len:expr) => { #[bench] fn $name(b: &mut Bencher) { - b.iter(|| $gen($len).sort()); + b.iter(|| $gen($len).$f()); b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; } } } -sort_bench!(sort_small_random, gen_random, 10); -sort_bench!(sort_small_ascending, gen_ascending, 10); -sort_bench!(sort_small_descending, gen_descending, 10); - -sort_bench!(sort_small_big_random, gen_big_random, 10); -sort_bench!(sort_small_big_ascending, gen_big_ascending, 10); -sort_bench!(sort_small_big_descending, gen_big_descending, 10); - -sort_bench!(sort_medium_random, gen_random, 100); -sort_bench!(sort_medium_ascending, gen_ascending, 100); -sort_bench!(sort_medium_descending, gen_descending, 100); - -sort_bench!(sort_large_random, gen_random, 10000); -sort_bench!(sort_large_ascending, gen_ascending, 10000); -sort_bench!(sort_large_descending, gen_descending, 10000); -sort_bench!(sort_large_mostly_ascending, gen_mostly_ascending, 10000); -sort_bench!(sort_large_mostly_descending, gen_mostly_descending, 10000); - -sort_bench!(sort_large_big_random, gen_big_random, 10000); -sort_bench!(sort_large_big_ascending, gen_big_ascending, 10000); -sort_bench!(sort_large_big_descending, gen_big_descending, 10000); +macro_rules! sort_expensive { + ($f:ident, $name:ident, $gen:expr, $len:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut v = $gen($len); + let mut count = 0; + v.$f(|a: &u64, b: &u64| { + count += 1; + if count % 1_000_000_000 == 0 { + panic!("should not happen"); + } + (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap() + }); + black_box(count); + }); + b.bytes = $len as u64 * mem::size_of::() as u64; + } + } +} -#[bench] -fn sort_large_random_expensive(b: &mut Bencher) { - let len = 10000; - b.iter(|| { - let mut v = gen_random(len); - let mut count = 0; - v.sort_by(|a: &u64, b: &u64| { - count += 1; - if count % 1_000_000_000 == 0 { - panic!("should not happen"); - } - (*a as f64).cos().partial_cmp(&(*b as f64).cos()).unwrap() - }); - black_box(count); - }); - b.bytes = len as u64 * mem::size_of::() as u64; -} \ No newline at end of file +sort!(sort, sort_small_ascending, gen_ascending, 10); +sort!(sort, sort_small_descending, gen_descending, 10); +sort!(sort, sort_small_random, gen_random, 10); +sort!(sort, sort_small_big_random, gen_big_random, 10); +sort!(sort, sort_medium_random, gen_random, 100); +sort!(sort, sort_large_ascending, gen_ascending, 10000); +sort!(sort, sort_large_descending, gen_descending, 10000); +sort!(sort, sort_large_mostly_ascending, gen_mostly_ascending, 10000); +sort!(sort, sort_large_mostly_descending, gen_mostly_descending, 10000); +sort!(sort, sort_large_random, gen_random, 10000); +sort!(sort, sort_large_big_random, gen_big_random, 10000); +sort!(sort, sort_large_strings, gen_strings, 10000); +sort_expensive!(sort_by, sort_large_random_expensive, gen_random, 10000); + +sort!(sort_unstable, sort_unstable_small_ascending, gen_ascending, 10); +sort!(sort_unstable, sort_unstable_small_descending, gen_descending, 10); +sort!(sort_unstable, sort_unstable_small_random, gen_random, 10); +sort!(sort_unstable, sort_unstable_small_big_random, gen_big_random, 10); +sort!(sort_unstable, sort_unstable_medium_random, gen_random, 100); +sort!(sort_unstable, sort_unstable_large_ascending, gen_ascending, 10000); +sort!(sort_unstable, sort_unstable_large_descending, gen_descending, 10000); +sort!(sort_unstable, sort_unstable_large_mostly_ascending, gen_mostly_ascending, 10000); +sort!(sort_unstable, sort_unstable_large_mostly_descending, gen_mostly_descending, 10000); +sort!(sort_unstable, sort_unstable_large_random, gen_random, 10000); +sort!(sort_unstable, sort_unstable_large_big_random, gen_big_random, 10000); +sort!(sort_unstable, sort_unstable_large_strings, gen_strings, 10000); +sort_expensive!(sort_unstable_by, sort_unstable_large_random_expensive, gen_random, 10000); diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 10650dab583c3..9809db77f080e 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -52,6 +52,7 @@ #![feature(shared)] #![feature(slice_get_slice)] #![feature(slice_patterns)] +#![feature(sort_unstable)] #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 653310b8cb591..c915d8b9e563d 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1092,6 +1092,39 @@ impl [T] { merge_sort(self, |a, b| a.lt(b)); } + /// Sorts the slice using `compare` to compare elements. + /// + /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is an adaptive, iterative merge sort inspired by + /// [timsort](https://en.wikipedia.org/wiki/Timsort). + /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of + /// two or more sorted sequences concatenated one after another. + /// + /// Also, it allocates temporary storage half the size of `self`, but for short slices a + /// non-allocating insertion sort is used instead. + /// + /// # Examples + /// + /// ``` + /// let mut v = [5, 4, 1, 3, 2]; + /// v.sort_by(|a, b| a.cmp(b)); + /// assert!(v == [1, 2, 3, 4, 5]); + /// + /// // reverse sorting + /// v.sort_by(|a, b| b.cmp(a)); + /// assert!(v == [5, 4, 3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sort_by(&mut self, mut compare: F) + where F: FnMut(&T, &T) -> Ordering + { + merge_sort(self, |a, b| compare(a, b) == Less); + } + /// Sorts the slice using `f` to extract a key to compare elements by. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. @@ -1122,37 +1155,112 @@ impl [T] { merge_sort(self, |a, b| f(a).lt(&f(b))); } - /// Sorts the slice using `compare` to compare elements. + /// Sorts the slice, but may not preserve the order of equal elements. /// - /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. /// /// # Current implementation /// - /// The current algorithm is an adaptive, iterative merge sort inspired by - /// [timsort](https://en.wikipedia.org/wiki/Timsort). - /// It is designed to be very fast in cases where the slice is nearly sorted, or consists of - /// two or more sorted sequences concatenated one after another. + /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort], + /// which is a quicksort variant designed to be very fast on certain kinds of patterns, + /// sometimes achieving linear time. It is randomized but deterministic, and falls back to + /// heapsort on degenerate inputs. /// - /// Also, it allocates temporary storage half the size of `self`, but for short slices a - /// non-allocating insertion sort is used instead. + /// It is generally faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5, 4, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert!(v == [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + // FIXME #40585: Mention `sort_unstable` in the documentation for `sort`. + #[unstable(feature = "sort_unstable", issue = "40585")] + #[inline] + pub fn sort_unstable(&mut self) + where T: Ord + { + core_slice::SliceExt::sort_unstable(self); + } + + /// Sorts the slice using `compare` to compare elements, but may not preserve the order of + /// equal elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort], + /// which is a quicksort variant designed to be very fast on certain kinds of patterns, + /// sometimes achieving linear time. It is randomized but deterministic, and falls back to + /// heapsort on degenerate inputs. + /// + /// It is generally faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. /// /// # Examples /// /// ``` /// let mut v = [5, 4, 1, 3, 2]; - /// v.sort_by(|a, b| a.cmp(b)); + /// v.sort_unstable_by(|a, b| a.cmp(b)); /// assert!(v == [1, 2, 3, 4, 5]); /// /// // reverse sorting - /// v.sort_by(|a, b| b.cmp(a)); + /// v.sort_unstable_by(|a, b| b.cmp(a)); /// assert!(v == [5, 4, 3, 2, 1]); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + // FIXME #40585: Mention `sort_unstable_by` in the documentation for `sort_by`. + #[unstable(feature = "sort_unstable", issue = "40585")] #[inline] - pub fn sort_by(&mut self, mut compare: F) + pub fn sort_unstable_by(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering { - merge_sort(self, |a, b| compare(a, b) == Less); + core_slice::SliceExt::sort_unstable_by(self, compare); + } + + /// Sorts the slice using `f` to extract a key to compare elements by, but may not preserve the + /// order of equal elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort], + /// which is a quicksort variant designed to be very fast on certain kinds of patterns, + /// sometimes achieving linear time. It is randomized but deterministic, and falls back to + /// heapsort on degenerate inputs. + /// + /// It is generally faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert!(v == [1, 2, -3, 4, -5]); + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + /// ``` + // FIXME #40585: Mention `sort_unstable_by_key` in the documentation for `sort_by_key`. + #[unstable(feature = "sort_unstable", issue = "40585")] + #[inline] + pub fn sort_unstable_by_key(&mut self, f: F) + where F: FnMut(&T) -> B, + B: Ord + { + core_slice::SliceExt::sort_unstable_by_key(self, f); } /// Copies the elements from `src` into `self`. @@ -1553,28 +1661,20 @@ unsafe fn merge(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F) fn merge_sort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool { + // Slices of up to this length get sorted using insertion sort. + const MAX_INSERTION: usize = 16; + // Very short runs are extended using insertion sort to span at least this many elements. + const MIN_RUN: usize = 8; + // Sorting has no meaningful behavior on zero-sized types. if size_of::() == 0 { return; } - // FIXME #12092: These numbers are platform-specific and need more extensive testing/tuning. - // - // If `v` has length up to `max_insertion`, simply switch to insertion sort because it is going - // to perform better than merge sort. For bigger types `T`, the threshold is smaller. - // - // Short runs are extended using insertion sort to span at least `min_run` elements, in order - // to improve performance. - let (max_insertion, min_run) = if size_of::() <= 2 * mem::size_of::() { - (64, 32) - } else { - (32, 16) - }; - let len = v.len(); // Short arrays get sorted in-place via insertion sort to avoid allocations. - if len <= max_insertion { + if len <= MAX_INSERTION { if len >= 2 { for i in (0..len-1).rev() { insert_head(&mut v[i..], &mut is_less); @@ -1618,7 +1718,7 @@ fn merge_sort(v: &mut [T], mut is_less: F) // Insert some more elements into the run if it's too short. Insertion sort is faster than // merge sort on short sequences, so this significantly improves performance. - while start > 0 && end - start < min_run { + while start > 0 && end - start < MIN_RUN { start -= 1; insert_head(&mut v[start..end], &mut is_less); } diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index a7f7baf38518c..00d4dbe9c0458 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -399,9 +399,10 @@ fn test_sort() { } } - // shouldn't panic - let mut v: [i32; 0] = []; - v.sort(); + // Should not panic. + [0i32; 0].sort(); + [(); 10].sort(); + [(); 100].sort(); let mut v = [0xDEADBEEFu64]; v.sort(); @@ -441,13 +442,6 @@ fn test_sort_stability() { } } -#[test] -fn test_sort_zero_sized_type() { - // Should not panic. - [(); 10].sort(); - [(); 100].sort(); -} - #[test] fn test_concat() { let v: [Vec; 0] = []; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3d124a8aa8b75..af61342749319 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -71,26 +71,27 @@ #![feature(asm)] #![feature(associated_type_defaults)] #![feature(cfg_target_feature)] +#![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] -#![feature(cfg_target_has_atomic)] #![feature(custom_attribute)] #![feature(fundamental)] +#![feature(i128_type)] #![feature(inclusive_range_syntax)] #![feature(intrinsics)] #![feature(lang_items)] +#![feature(never_type)] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] -#![feature(unwind_attributes)] +#![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] -#![feature(never_type)] -#![feature(i128_type)] -#![feature(prelude_import)] +#![feature(untagged_unions)] +#![feature(unwind_attributes)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/slice.rs b/src/libcore/slice/mod.rs similarity index 97% rename from src/libcore/slice.rs rename to src/libcore/slice/mod.rs index 22658f9a81b0d..53cbdd84c3a8d 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -51,6 +51,8 @@ use mem; use marker::{Copy, Send, Sync, Sized, self}; use iter_private::TrustedRandomAccess; +mod sort; + #[repr(C)] struct Repr { pub data: *const T, @@ -71,86 +73,119 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn split_at(&self, mid: usize) -> (&[Self::Item], &[Self::Item]); + #[stable(feature = "core", since = "1.6.0")] fn iter(&self) -> Iter; + #[stable(feature = "core", since = "1.6.0")] fn split

(&self, pred: P) -> Split - where P: FnMut(&Self::Item) -> bool; + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn

(&self, n: usize, pred: P) -> SplitN - where P: FnMut(&Self::Item) -> bool; + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn rsplitn

(&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&Self::Item) -> bool; + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn windows(&self, size: usize) -> Windows; + #[stable(feature = "core", since = "1.6.0")] fn chunks(&self, size: usize) -> Chunks; + #[stable(feature = "core", since = "1.6.0")] fn get(&self, index: I) -> Option<&I::Output> where I: SliceIndex; + #[stable(feature = "core", since = "1.6.0")] fn first(&self) -> Option<&Self::Item>; + #[stable(feature = "core", since = "1.6.0")] fn split_first(&self) -> Option<(&Self::Item, &[Self::Item])>; + #[stable(feature = "core", since = "1.6.0")] fn split_last(&self) -> Option<(&Self::Item, &[Self::Item])>; + #[stable(feature = "core", since = "1.6.0")] fn last(&self) -> Option<&Self::Item>; + #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked(&self, index: I) -> &I::Output where I: SliceIndex; + #[stable(feature = "core", since = "1.6.0")] fn as_ptr(&self) -> *const Self::Item; + #[stable(feature = "core", since = "1.6.0")] fn binary_search(&self, x: &Q) -> Result where Self::Item: Borrow, Q: Ord; + #[stable(feature = "core", since = "1.6.0")] fn binary_search_by<'a, F>(&'a self, f: F) -> Result where F: FnMut(&'a Self::Item) -> Ordering; + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] fn binary_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, f: F) -> Result where F: FnMut(&'a Self::Item) -> B, B: Borrow, Q: Ord; + #[stable(feature = "core", since = "1.6.0")] fn len(&self) -> usize; + #[stable(feature = "core", since = "1.6.0")] fn is_empty(&self) -> bool { self.len() == 0 } + #[stable(feature = "core", since = "1.6.0")] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where I: SliceIndex; + #[stable(feature = "core", since = "1.6.0")] fn iter_mut(&mut self) -> IterMut; + #[stable(feature = "core", since = "1.6.0")] fn first_mut(&mut self) -> Option<&mut Self::Item>; + #[stable(feature = "core", since = "1.6.0")] fn split_first_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; + #[stable(feature = "core", since = "1.6.0")] fn split_last_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; + #[stable(feature = "core", since = "1.6.0")] fn last_mut(&mut self) -> Option<&mut Self::Item>; + #[stable(feature = "core", since = "1.6.0")] fn split_mut

(&mut self, pred: P) -> SplitMut - where P: FnMut(&Self::Item) -> bool; + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&Self::Item) -> bool; + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn rsplitn_mut

(&mut self, n: usize, pred: P) -> RSplitNMut - where P: FnMut(&Self::Item) -> bool; + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut; + #[stable(feature = "core", since = "1.6.0")] fn swap(&mut self, a: usize, b: usize); + #[stable(feature = "core", since = "1.6.0")] fn split_at_mut(&mut self, mid: usize) -> (&mut [Self::Item], &mut [Self::Item]); + #[stable(feature = "core", since = "1.6.0")] fn reverse(&mut self); + #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: SliceIndex; + #[stable(feature = "core", since = "1.6.0")] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -165,8 +200,22 @@ pub trait SliceExt { #[stable(feature = "clone_from_slice", since = "1.7.0")] fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone; + #[stable(feature = "copy_from_slice", since = "1.9.0")] fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; + + #[unstable(feature = "sort_unstable", issue = "40585")] + fn sort_unstable(&mut self) + where Self::Item: Ord; + + #[unstable(feature = "sort_unstable", issue = "40585")] + fn sort_unstable_by(&mut self, compare: F) + where F: FnMut(&Self::Item, &Self::Item) -> Ordering; + + #[unstable(feature = "sort_unstable", issue = "40585")] + fn sort_unstable_by_key(&mut self, f: F) + where F: FnMut(&Self::Item) -> B, + B: Ord; } // Use macros to be generic over const/mut @@ -238,7 +287,9 @@ impl SliceExt for [T] { } #[inline] - fn split

(&self, pred: P) -> Split where P: FnMut(&T) -> bool { + fn split

(&self, pred: P) -> Split + where P: FnMut(&T) -> bool + { Split { v: self, pred: pred, @@ -247,8 +298,8 @@ impl SliceExt for [T] { } #[inline] - fn splitn

(&self, n: usize, pred: P) -> SplitN where - P: FnMut(&T) -> bool, + fn splitn

(&self, n: usize, pred: P) -> SplitN + where P: FnMut(&T) -> bool { SplitN { inner: GenericSplitN { @@ -260,8 +311,8 @@ impl SliceExt for [T] { } #[inline] - fn rsplitn

(&self, n: usize, pred: P) -> RSplitN where - P: FnMut(&T) -> bool, + fn rsplitn

(&self, n: usize, pred: P) -> RSplitN + where P: FnMut(&T) -> bool { RSplitN { inner: GenericSplitN { @@ -422,13 +473,15 @@ impl SliceExt for [T] { } #[inline] - fn split_mut

(&mut self, pred: P) -> SplitMut where P: FnMut(&T) -> bool { + fn split_mut

(&mut self, pred: P) -> SplitMut + where P: FnMut(&T) -> bool + { SplitMut { v: self, pred: pred, finished: false } } #[inline] - fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut where - P: FnMut(&T) -> bool + fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut + where P: FnMut(&T) -> bool { SplitNMut { inner: GenericSplitN { @@ -450,7 +503,7 @@ impl SliceExt for [T] { invert: true } } - } + } #[inline] fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { @@ -512,7 +565,10 @@ impl SliceExt for [T] { m >= n && needle == &self[m-n..] } - fn binary_search(&self, x: &Q) -> Result where T: Borrow, Q: Ord { + fn binary_search(&self, x: &Q) -> Result + where T: Borrow, + Q: Ord + { self.binary_search_by(|p| p.borrow().cmp(x)) } @@ -548,6 +604,28 @@ impl SliceExt for [T] { { self.binary_search_by(|k| f(k).borrow().cmp(b)) } + + #[inline] + fn sort_unstable(&mut self) + where Self::Item: Ord + { + sort::quicksort(self, |a, b| a.lt(b)); + } + + #[inline] + fn sort_unstable_by(&mut self, mut compare: F) + where F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); + } + + #[inline] + fn sort_unstable_by_key(&mut self, mut f: F) + where F: FnMut(&Self::Item) -> B, + B: Ord + { + sort::quicksort(self, |a, b| f(a).lt(&f(b))); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs new file mode 100644 index 0000000000000..7c751b5c5a386 --- /dev/null +++ b/src/libcore/slice/sort.rs @@ -0,0 +1,628 @@ +// Copyright 2017 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. + +//! Slice sorting +//! +//! This module contains an sort algorithm based on Orson Peters' pattern-defeating quicksort, +//! published at: https://github.com/orlp/pdqsort +//! +//! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our +//! stable sorting implementation. + +#![unstable(feature = "sort_unstable", issue = "40585")] + +use cmp; +use mem; +use ptr; + +/// Holds a value, but never drops it. +#[allow(unions_with_drop_fields)] +union NoDrop { + value: T +} + +/// When dropped, copies from `src` into `dest`. +struct CopyOnDrop { + src: *mut T, + dest: *mut T, +} + +impl Drop for CopyOnDrop { + fn drop(&mut self) { + unsafe { ptr::copy_nonoverlapping(self.src, self.dest, 1); } + } +} + +/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case. +fn insertion_sort(v: &mut [T], is_less: &mut F) + where F: FnMut(&T, &T) -> bool +{ + let len = v.len(); + + for i in 1..len { + unsafe { + if is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) { + // There are three ways to implement insertion here: + // + // 1. Swap adjacent elements until the first one gets to its final destination. + // However, this way we copy data around more than is necessary. If elements are + // big structures (costly to copy), this method will be slow. + // + // 2. Iterate until the right place for the first element is found. Then shift the + // elements succeeding it to make room for it and finally place it into the + // remaining hole. This is a good method. + // + // 3. Copy the first element into a temporary variable. Iterate until the right + // place for it is found. As we go along, copy every traversed element into the + // slot preceding it. Finally, copy data from the temporary variable into the + // remaining hole. This method is very good. Benchmarks demonstrated slightly + // better performance than with the 2nd method. + // + // All methods were benchmarked, and the 3rd showed best results. So we chose that + // one. + let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(i)) }; + + // Intermediate state of the insertion process is always tracked by `hole`, which + // serves two purposes: + // 1. Protects integrity of `v` from panics in `is_less`. + // 2. Fills the remaining hole in `v` in the end. + // + // Panic safety: + // + // If `is_less` panics at any point during the process, `hole` will get dropped and + // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object + // it initially held exactly once. + let mut hole = CopyOnDrop { + src: &mut tmp.value, + dest: v.get_unchecked_mut(i - 1), + }; + ptr::copy_nonoverlapping(v.get_unchecked(i - 1), v.get_unchecked_mut(i), 1); + + for h in (0..i-1).rev() { + if !is_less(&tmp.value, v.get_unchecked(h)) { + break; + } + ptr::copy_nonoverlapping(v.get_unchecked(h), v.get_unchecked_mut(h + 1), 1); + hole.dest = v.get_unchecked_mut(h); + } + // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. + } + } + } +} + +/// Sorts `v` using heapsort, which guarantees `O(n log n)` worst-case. +#[cold] +fn heapsort(v: &mut [T], is_less: &mut F) + where F: FnMut(&T, &T) -> bool +{ + // This binary heap respects the invariant `parent >= child`. + let mut sift_down = |v: &mut [T], mut node| { + loop { + // Children of `node`: + let left = 2 * node + 1; + let right = 2 * node + 2; + + // Choose the greater child. + let greater = if right < v.len() && is_less(&v[left], &v[right]) { + right + } else { + left + }; + + // Stop if the invariant holds at `node`. + if greater >= v.len() || !is_less(&v[node], &v[greater]) { + break; + } + + // Swap `node` with the greater child, move one step down, and continue sifting. + v.swap(node, greater); + node = greater; + } + }; + + // Build the heap in linear time. + for i in (0 .. v.len() / 2).rev() { + sift_down(v, i); + } + + // Pop maximal elements from the heap. + for i in (1 .. v.len()).rev() { + v.swap(0, i); + sift_down(&mut v[..i], 0); + } +} + +/// Partitions `v` into elements smaller than `pivot`, followed by elements greater than or equal +/// to `pivot`. +/// +/// Returns the number of elements smaller than `pivot`. +/// +/// Partitioning is performed block-by-block in order to minimize the cost of branching operations. +/// This idea is presented in the [BlockQuicksort][pdf] paper. +/// +/// [pdf]: http://drops.dagstuhl.de/opus/volltexte/2016/6389/pdf/LIPIcs-ESA-2016-38.pdf +fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize + where F: FnMut(&T, &T) -> bool +{ + // Number of elements in a typical block. + const BLOCK: usize = 128; + + // The partitioning algorithm repeats the following steps until completion: + // + // 1. Trace a block from the left side to identify elements greater than or equal to the pivot. + // 2. Trace a block from the right side to identify elements less than the pivot. + // 3. Exchange the identified elements between the left and right side. + // + // We keep the following variables for a block of elements: + // + // 1. `block` - Number of elements in the block. + // 2. `start` - Start pointer into the `offsets` array. + // 3. `end` - End pointer into the `offsets` array. + // 4. `offsets - Indices of out-of-order elements within the block. + + // The current block on the left side: `v[l .. l + block_l]`. + let mut l = v.as_mut_ptr(); + let mut block_l = BLOCK; + let mut start_l = ptr::null_mut(); + let mut end_l = ptr::null_mut(); + let mut offsets_l: [u8; BLOCK] = unsafe { mem::uninitialized() }; + + // The current block on the right side: `v[r - block_r .. r]`. + let mut r = unsafe { l.offset(v.len() as isize) }; + let mut block_r = BLOCK; + let mut start_r = ptr::null_mut(); + let mut end_r = ptr::null_mut(); + let mut offsets_r: [u8; BLOCK] = unsafe { mem::uninitialized() }; + + // Returns the number of elements between pointers `l` (inclusive) and `r` (exclusive). + fn width(l: *mut T, r: *mut T) -> usize { + assert!(mem::size_of::() > 0); + (r as usize - l as usize) / mem::size_of::() + } + + loop { + // We are done with partitioning block-by-block when `l` and `r` get very close. Then we do + // some patch-up work in order to partition the remaining elements in between. + let is_done = width(l, r) <= 2 * BLOCK; + + if is_done { + // Number of remaining elements (still not compared to the pivot). + let mut rem = width(l, r); + if start_l < end_l || start_r < end_r { + rem -= BLOCK; + } + + // Adjust block sizes so that the left and right block don't overlap, but get perfectly + // aligned to cover the whole remaining gap. + if start_l < end_l { + block_r = rem; + } else if start_r < end_r { + block_l = rem; + } else { + block_l = rem / 2; + block_r = rem - block_l; + } + debug_assert!(block_l <= BLOCK && block_r <= BLOCK); + debug_assert!(width(l, r) == block_l + block_r); + } + + if start_l == end_l { + // Trace `block_l` elements from the left side. + start_l = offsets_l.as_mut_ptr(); + end_l = offsets_l.as_mut_ptr(); + let mut elem = l; + + for i in 0..block_l { + unsafe { + // Branchless comparison. + *end_l = i as u8; + end_l = end_l.offset(!is_less(&*elem, pivot) as isize); + elem = elem.offset(1); + } + } + } + + if start_r == end_r { + // Trace `block_r` elements from the right side. + start_r = offsets_r.as_mut_ptr(); + end_r = offsets_r.as_mut_ptr(); + let mut elem = r; + + for i in 0..block_r { + unsafe { + // Branchless comparison. + elem = elem.offset(-1); + *end_r = i as u8; + end_r = end_r.offset(is_less(&*elem, pivot) as isize); + } + } + } + + // Number of out-of-order elements to swap between the left and right side. + let count = cmp::min(width(start_l, end_l), width(start_r, end_r)); + + if count > 0 { + macro_rules! left { () => { l.offset(*start_l as isize) } } + macro_rules! right { () => { r.offset(-(*start_r as isize) - 1) } } + + // Instead of swapping one pair at the time, it is more efficient to perform a cyclic + // permutation. This is not strictly equivalent to swapping, but produces a similar + // result using fewer memory operations. + unsafe { + let tmp = ptr::read(left!()); + ptr::copy_nonoverlapping(right!(), left!(), 1); + + for _ in 1..count { + start_l = start_l.offset(1); + ptr::copy_nonoverlapping(left!(), right!(), 1); + start_r = start_r.offset(1); + ptr::copy_nonoverlapping(right!(), left!(), 1); + } + + ptr::copy_nonoverlapping(&tmp, right!(), 1); + mem::forget(tmp); + start_l = start_l.offset(1); + start_r = start_r.offset(1); + } + } + + if start_l == end_l { + // All out-of-order elements in the left block were moved. Move to the next block. + l = unsafe { l.offset(block_l as isize) }; + } + + if start_r == end_r { + // All out-of-order elements in the right block were moved. Move to the previous block. + r = unsafe { r.offset(-(block_r as isize)) }; + } + + if is_done { + break; + } + } + + // All that remains now is at most one block (either the left or the right) with out-of-order + // elements that need to be moved. Such remaining elements can be simply shifted to the end + // within their block. + + if start_l < end_l { + // The left block remains. + // Move it's remaining out-of-order elements to the far right. + debug_assert_eq!(width(l, r), block_l); + while start_l < end_l { + unsafe { + end_l = end_l.offset(-1); + ptr::swap(l.offset(*end_l as isize), r.offset(-1)); + r = r.offset(-1); + } + } + width(v.as_mut_ptr(), r) + } else if start_r < end_r { + // The right block remains. + // Move it's remaining out-of-order elements to the far left. + debug_assert_eq!(width(l, r), block_r); + while start_r < end_r { + unsafe { + end_r = end_r.offset(-1); + ptr::swap(l, r.offset(-(*end_r as isize) - 1)); + l = l.offset(1); + } + } + width(v.as_mut_ptr(), l) + } else { + // Nothing else to do, we're done. + width(v.as_mut_ptr(), l) + } +} + +/// Partitions `v` into elements smaller than `v[pivot]`, followed by elements greater than or +/// equal to `v[pivot]`. +/// +/// Returns a tuple of: +/// +/// 1. Number of elements smaller than `v[pivot]`. +/// 2. True if `v` was already partitioned. +fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) + where F: FnMut(&T, &T) -> bool +{ + let (mid, was_partitioned) = { + // Place the pivot at the beginning of slice. + v.swap(0, pivot); + let (pivot, v) = v.split_at_mut(1); + let pivot = &mut pivot[0]; + + // Read the pivot into a stack-allocated variable for efficiency. If a following comparison + // operation panics, the pivot will be automatically written back into the slice. + let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let _pivot_guard = CopyOnDrop { + src: unsafe { &mut tmp.value }, + dest: pivot, + }; + let pivot = unsafe { &tmp.value }; + + // Find the first pair of out-of-order elements. + let mut l = 0; + let mut r = v.len(); + unsafe { + // Find the first element greater then or equal to the pivot. + while l < r && is_less(v.get_unchecked(l), pivot) { + l += 1; + } + + // Find the last element lesser that the pivot. + while l < r && !is_less(v.get_unchecked(r - 1), pivot) { + r -= 1; + } + } + + (l + partition_in_blocks(&mut v[l..r], pivot, is_less), l >= r) + + // `_pivot_guard` goes out of scope and writes the pivot (which is a stack-allocated + // variable) back into the slice where it originally was. This step is critical in ensuring + // safety! + }; + + // Place the pivot between the two partitions. + v.swap(0, mid); + + (mid, was_partitioned) +} + +/// Partitions `v` into elements equal to `v[pivot]` followed by elements greater than `v[pivot]`. +/// +/// Returns the number of elements equal to the pivot. It is assumed that `v` does not contain +/// elements smaller than the pivot. +fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize + where F: FnMut(&T, &T) -> bool +{ + // Place the pivot at the beginning of slice. + v.swap(0, pivot); + let (pivot, v) = v.split_at_mut(1); + let pivot = &mut pivot[0]; + + // Read the pivot into a stack-allocated variable for efficiency. If a following comparison + // operation panics, the pivot will be automatically written back into the slice. + let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let _pivot_guard = CopyOnDrop { + src: unsafe { &mut tmp.value }, + dest: pivot, + }; + let pivot = unsafe { &tmp.value }; + + // Now partition the slice. + let mut l = 0; + let mut r = v.len(); + loop { + unsafe { + // Find the first element greater that the pivot. + while l < r && !is_less(pivot, v.get_unchecked(l)) { + l += 1; + } + + // Find the last element equal to the pivot. + while l < r && is_less(pivot, v.get_unchecked(r - 1)) { + r -= 1; + } + + // Are we done? + if l >= r { + break; + } + + // Swap the found pair of out-of-order elements. + r -= 1; + ptr::swap(v.get_unchecked_mut(l), v.get_unchecked_mut(r)); + l += 1; + } + } + + // We found `l` elements equal to the pivot. Add 1 to account for the pivot itself. + l + 1 + + // `_pivot_guard` goes out of scope and writes the pivot (which is a stack-allocated variable) + // back into the slice where it originally was. This step is critical in ensuring safety! +} + +/// Scatters some elements around in an attempt to break patterns that might cause imbalanced +/// partitions in quicksort. +#[cold] +fn break_patterns(v: &mut [T]) { + let len = v.len(); + + if len >= 8 { + // A random number will be taken modulo this one. The modulus is a power of two so that we + // can simply take bitwise "and", thus avoiding costly CPU operations. + let modulus = (len / 4).next_power_of_two(); + debug_assert!(modulus >= 1 && modulus <= len / 2); + + // Pseudorandom number generation from the "Xorshift RNGs" paper by George Marsaglia. + let mut random = len; + random ^= random << 13; + random ^= random >> 17; + random ^= random << 5; + random &= modulus - 1; + debug_assert!(random < len / 2); + + // The first index. + let a = len / 4 * 2; + debug_assert!(a >= 1 && a < len - 2); + + // The second index. + let b = len / 4 + random; + debug_assert!(b >= 1 && b < len - 2); + + // Swap neighbourhoods of `a` and `b`. + for i in 0..3 { + v.swap(a - 1 + i, b - 1 + i); + } + } +} + +/// Chooses a pivot in `v` and returns it's index. +/// +/// Elements in `v` might be reordered in the process. +fn choose_pivot(v: &mut [T], is_less: &mut F) -> usize + where F: FnMut(&T, &T) -> bool +{ + // Minimal length to choose the median-of-medians method. + // Shorter slices use the simple median-of-three method. + const SHORTEST_MEDIAN_OF_MEDIANS: usize = 90; + // Maximal number of swaps that can be performed in this function. + const MAX_SWAPS: usize = 4 * 3; + + let len = v.len(); + + // Three indices near which we are going to choose a pivot. + let mut a = len / 4 * 1; + let mut b = len / 4 * 2; + let mut c = len / 4 * 3; + + // Counts the total number of swaps we are about to perform while sorting indices. + let mut swaps = 0; + + if len >= 8 { + // Swaps indices so that `v[a] <= v[b]`. + let mut sort2 = |a: &mut usize, b: &mut usize| unsafe { + if is_less(v.get_unchecked(*b), v.get_unchecked(*a)) { + ptr::swap(a, b); + swaps += 1; + } + }; + + // Swaps indices so that `v[a] <= v[b] <= v[c]`. + let mut sort3 = |a: &mut usize, b: &mut usize, c: &mut usize| { + sort2(a, b); + sort2(b, c); + sort2(a, b); + }; + + if len >= SHORTEST_MEDIAN_OF_MEDIANS { + // Finds the median of `v[a - 1], v[a], v[a + 1]` and stores the index into `a`. + let mut sort_adjacent = |a: &mut usize| { + let tmp = *a; + sort3(&mut (tmp - 1), a, &mut (tmp + 1)); + }; + + // Find medians in the neighborhoods of `a`, `b`, and `c`. + sort_adjacent(&mut a); + sort_adjacent(&mut b); + sort_adjacent(&mut c); + } + + // Find the median among `a`, `b`, and `c`. + sort3(&mut a, &mut b, &mut c); + } + + if swaps < MAX_SWAPS { + b + } else { + // The maximal number of swaps was performed. Chances are the slice is descending or mostly + // descending, so reversing will probably help sort it faster. + v.reverse(); + len - 1 - b + } +} + +/// Sorts `v` recursively. +/// +/// If the slice had a predecessor in the original array, it is specified as `pred`. +/// +/// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, +/// this function will immediately switch to heapsort. +fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: usize) + where F: FnMut(&T, &T) -> bool +{ + // Slices of up to this length get sorted using insertion sort. + const MAX_INSERTION: usize = 16; + + // This is `true` if the last partitioning was balanced. + let mut was_balanced = true; + + loop { + let len = v.len(); + + // Very short slices get sorted using insertion sort. + if len <= MAX_INSERTION { + insertion_sort(v, is_less); + return; + } + + // If too many bad pivot choices were made, simply fall back to heapsort in order to + // guarantee `O(n log n)` worst-case. + if limit == 0 { + heapsort(v, is_less); + return; + } + + // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling + // some elements around. Hopefully we'll choose a better pivot this time. + if !was_balanced { + break_patterns(v); + limit -= 1; + } + + let pivot = choose_pivot(v, is_less); + + // If the chosen pivot is equal to the predecessor, then it's the smallest element in the + // slice. Partition the slice into elements equal to and elements greater than the pivot. + // This case is usually hit when the slice contains many duplicate elements. + if let Some(p) = pred { + if !is_less(p, &v[pivot]) { + let mid = partition_equal(v, pivot, is_less); + + // Continue sorting elements greater than the pivot. + v = &mut {v}[mid..]; + continue; + } + } + + let (mid, was_partitioned) = partition(v, pivot, is_less); + was_balanced = cmp::min(mid, len - mid) >= len / 8; + + // If the partitioning is decently balanced and the slice was already partitioned, there + // are good chances it is also completely sorted. If so, we're done. + if was_balanced && was_partitioned && v.windows(2).all(|w| !is_less(&w[1], &w[0])) { + return; + } + + // Split the slice into `left`, `pivot`, and `right`. + let (left, right) = {v}.split_at_mut(mid); + let (pivot, right) = right.split_at_mut(1); + let pivot = &pivot[0]; + + // Recurse into the shorter side only in order to minimize the total number of recursive + // calls and consume less stack space. Then just continue with the longer side (this is + // akin to tail recursion). + if left.len() < right.len() { + recurse(left, is_less, pred, limit); + v = right; + pred = Some(pivot); + } else { + recurse(right, is_less, Some(pivot), limit); + v = left; + } + } +} + +/// Sorts `v` using pattern-defeating quicksort, which is `O(n log n)` worst-case. +pub fn quicksort(v: &mut [T], mut is_less: F) + where F: FnMut(&T, &T) -> bool +{ + // Sorting has no meaningful behavior on zero-sized types. + if mem::size_of::() == 0 { + return; + } + + // Limit the number of imbalanced partitions to `floor(log2(len)) + 2`. + let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize + 1; + + recurse(v, &mut is_less, None, limit); +} diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index d84a1e227560e..e8dbbd55df259 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -19,18 +19,22 @@ #![feature(decode_utf8)] #![feature(fixed_size_array)] #![feature(flt2dec)] +#![feature(fmt_internals)] #![feature(libc)] +#![feature(move_cell)] #![feature(nonzero)] +#![feature(ordering_chaining)] +#![feature(ptr_unaligned)] #![feature(rand)] #![feature(raw)] #![feature(sip_hash_13)] #![feature(slice_patterns)] +#![feature(sort_unstable)] #![feature(step_by)] #![feature(test)] #![feature(try_from)] #![feature(unicode)] #![feature(unique)] -#![feature(fmt_internals)] extern crate core; extern crate test; diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index ad39e6b081b42..b51bae4db2251 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -9,6 +9,7 @@ // except according to those terms. use core::result::Result::{Ok, Err}; +use rand::{Rng, XorShiftRng}; #[test] fn test_binary_search() { @@ -139,9 +140,6 @@ fn test_chunks_mut_last() { assert_eq!(c2.last().unwrap()[0], 4); } - - - #[test] fn test_windows_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -224,3 +222,40 @@ fn get_unchecked_mut_range() { assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]); } } + +#[test] +fn sort_unstable() { + let mut v = [0; 600]; + let mut v1 = [0; 600]; + let mut rng = XorShiftRng::new_unseeded(); + + for len in (2..25).chain(500..510) { + for &modulus in &[10, 1000] { + for _ in 0..100 { + for i in 0..len { + let num = rng.gen::() % modulus; + v[i] = num; + v1[i] = num; + } + + v.sort_unstable(); + assert!(v.windows(2).all(|w| w[0] <= w[1])); + + v1.sort_unstable_by(|a, b| a.cmp(b)); + assert!(v1.windows(2).all(|w| w[0] <= w[1])); + + v1.sort_unstable_by(|a, b| b.cmp(a)); + assert!(v1.windows(2).all(|w| w[0] >= w[1])); + } + } + } + + // Should not panic. + [0i32; 0].sort_unstable(); + [(); 10].sort_unstable(); + [(); 100].sort_unstable(); + + let mut v = [0xDEADBEEFu64]; + v.sort_unstable(); + assert!(v == [0xDEADBEEF]); +} From e365974750570c4e17cb02e66f0aa4f27b6776f5 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 17 Mar 2017 22:51:59 +0100 Subject: [PATCH 159/662] Address Alex's PR comments --- src/libcollections/lib.rs | 2 +- src/libcollections/slice.rs | 6 ++++++ src/libcore/slice/sort.rs | 2 -- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 9809db77f080e..72e950bc91fa9 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -52,7 +52,7 @@ #![feature(shared)] #![feature(slice_get_slice)] #![feature(slice_patterns)] -#![feature(sort_unstable)] +#![cfg_attr(not(test), feature(sort_unstable))] #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index c915d8b9e563d..ca87ee1063b87 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1173,6 +1173,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(sort_unstable)] + /// /// let mut v = [-5, 4, 1, -3, 2]; /// /// v.sort_unstable(); @@ -1208,6 +1210,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(sort_unstable)] + /// /// let mut v = [5, 4, 1, 3, 2]; /// v.sort_unstable_by(|a, b| a.cmp(b)); /// assert!(v == [1, 2, 3, 4, 5]); @@ -1246,6 +1250,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(sort_unstable)] + /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// v.sort_unstable_by_key(|k| k.abs()); diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 7c751b5c5a386..5434bbbbf8c03 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -16,8 +16,6 @@ //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our //! stable sorting implementation. -#![unstable(feature = "sort_unstable", issue = "40585")] - use cmp; use mem; use ptr; From f0e58686277d66207a466fd07e953de98663edb6 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 17 Mar 2017 23:17:59 +0100 Subject: [PATCH 160/662] Fix a doctest --- src/libcollections/slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ca87ee1063b87..7090e90a6e493 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1256,9 +1256,9 @@ impl [T] { /// /// v.sort_unstable_by_key(|k| k.abs()); /// assert!(v == [1, 2, -3, 4, -5]); + /// ``` /// /// [pdqsort]: https://github.com/orlp/pdqsort - /// ``` // FIXME #40585: Mention `sort_unstable_by_key` in the documentation for `sort_by_key`. #[unstable(feature = "sort_unstable", issue = "40585")] #[inline] From cfe6e13b119b311c8846b762d1dabe0d58eb5e5c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 18 Mar 2017 13:21:56 +0100 Subject: [PATCH 161/662] Faster sort_unstable on presorted inputs --- src/libcore/slice/sort.rs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 5434bbbbf8c03..74a0a14a4c554 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -464,10 +464,10 @@ fn break_patterns(v: &mut [T]) { } } -/// Chooses a pivot in `v` and returns it's index. +/// Chooses a pivot in `v` and returns the index and true if the slice is likely already sorted. /// /// Elements in `v` might be reordered in the process. -fn choose_pivot(v: &mut [T], is_less: &mut F) -> usize +fn choose_pivot(v: &mut [T], is_less: &mut F) -> (usize, bool) where F: FnMut(&T, &T) -> bool { // Minimal length to choose the median-of-medians method. @@ -520,12 +520,12 @@ fn choose_pivot(v: &mut [T], is_less: &mut F) -> usize } if swaps < MAX_SWAPS { - b + (b, swaps == 0) } else { // The maximal number of swaps was performed. Chances are the slice is descending or mostly // descending, so reversing will probably help sort it faster. v.reverse(); - len - 1 - b + (len - 1 - b, true) } } @@ -541,8 +541,10 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T // Slices of up to this length get sorted using insertion sort. const MAX_INSERTION: usize = 16; - // This is `true` if the last partitioning was balanced. + // True if the last partitioning was reasonably balanced. let mut was_balanced = true; + // True if the last partitioning didn't shuffle elements (the slice was already partitioned). + let mut was_partitioned = true; loop { let len = v.len(); @@ -567,7 +569,17 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T limit -= 1; } - let pivot = choose_pivot(v, is_less); + // Choose a pivot and try guessing whether the slice is already sorted. + let (pivot, likely_sorted) = choose_pivot(v, is_less); + + // If the last partitioning was decently balanced and didn't shuffle elements, and if pivot + // selection predicts the slice is likely already sorted... + if was_balanced && was_partitioned && likely_sorted { + // Check whether the slice really is sorted. If so, we're done. + if v.windows(2).all(|w| !is_less(&w[1], &w[0])) { + return; + } + } // If the chosen pivot is equal to the predecessor, then it's the smallest element in the // slice. Partition the slice into elements equal to and elements greater than the pivot. @@ -582,14 +594,10 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T } } - let (mid, was_partitioned) = partition(v, pivot, is_less); + // Partition the slice. + let (mid, was_p) = partition(v, pivot, is_less); was_balanced = cmp::min(mid, len - mid) >= len / 8; - - // If the partitioning is decently balanced and the slice was already partitioned, there - // are good chances it is also completely sorted. If so, we're done. - if was_balanced && was_partitioned && v.windows(2).all(|w| !is_less(&w[1], &w[0])) { - return; - } + was_partitioned = was_p; // Split the slice into `left`, `pivot`, and `right`. let (left, right) = {v}.split_at_mut(mid); From 942173b38fc0c202e8f28f266d6c4df4acfc5a91 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 18 Mar 2017 15:42:07 +0100 Subject: [PATCH 162/662] Fix grammar --- src/libcore/slice/sort.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 74a0a14a4c554..9cd7009ad2908 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -156,7 +156,7 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize // The partitioning algorithm repeats the following steps until completion: // // 1. Trace a block from the left side to identify elements greater than or equal to the pivot. - // 2. Trace a block from the right side to identify elements less than the pivot. + // 2. Trace a block from the right side to identify elements smaller than the pivot. // 3. Exchange the identified elements between the left and right side. // // We keep the following variables for a block of elements: @@ -166,14 +166,14 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize // 3. `end` - End pointer into the `offsets` array. // 4. `offsets - Indices of out-of-order elements within the block. - // The current block on the left side: `v[l .. l + block_l]`. + // The current block on the left side (from `l` to `l.offset(block_l)`). let mut l = v.as_mut_ptr(); let mut block_l = BLOCK; let mut start_l = ptr::null_mut(); let mut end_l = ptr::null_mut(); let mut offsets_l: [u8; BLOCK] = unsafe { mem::uninitialized() }; - // The current block on the right side: `v[r - block_r .. r]`. + // The current block on the right side (from `r.offset(-block_r)` to `r`). let mut r = unsafe { l.offset(v.len() as isize) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); From c4454a5507be95da969712ac0326055635efe778 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 18 Mar 2017 20:24:44 +0100 Subject: [PATCH 163/662] Tweak the constants a bit --- src/libcollections/slice.rs | 4 ++-- src/libcore/slice/sort.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 7090e90a6e493..5233887620a91 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1668,9 +1668,9 @@ fn merge_sort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool { // Slices of up to this length get sorted using insertion sort. - const MAX_INSERTION: usize = 16; + const MAX_INSERTION: usize = 20; // Very short runs are extended using insertion sort to span at least this many elements. - const MIN_RUN: usize = 8; + const MIN_RUN: usize = 10; // Sorting has no meaningful behavior on zero-sized types. if size_of::() == 0 { diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 9cd7009ad2908..2ff059b464ab4 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -355,7 +355,7 @@ fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) l += 1; } - // Find the last element lesser that the pivot. + // Find the last element smaller that the pivot. while l < r && !is_less(v.get_unchecked(r - 1), pivot) { r -= 1; } @@ -472,7 +472,7 @@ fn choose_pivot(v: &mut [T], is_less: &mut F) -> (usize, bool) { // Minimal length to choose the median-of-medians method. // Shorter slices use the simple median-of-three method. - const SHORTEST_MEDIAN_OF_MEDIANS: usize = 90; + const SHORTEST_MEDIAN_OF_MEDIANS: usize = 80; // Maximal number of swaps that can be performed in this function. const MAX_SWAPS: usize = 4 * 3; @@ -539,7 +539,7 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T where F: FnMut(&T, &T) -> bool { // Slices of up to this length get sorted using insertion sort. - const MAX_INSERTION: usize = 16; + const MAX_INSERTION: usize = 20; // True if the last partitioning was reasonably balanced. let mut was_balanced = true; @@ -627,8 +627,8 @@ pub fn quicksort(v: &mut [T], mut is_less: F) return; } - // Limit the number of imbalanced partitions to `floor(log2(len)) + 2`. - let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize + 1; + // Limit the number of imbalanced partitions to `floor(log2(len)) + 1`. + let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize; recurse(v, &mut is_less, None, limit); } From 02d6e0058717bec78bc1ef8db2bf8674804590b7 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sun, 19 Mar 2017 21:40:02 +0100 Subject: [PATCH 164/662] Use partial insertion sort --- src/libcore/slice/sort.rs | 173 ++++++++++++++++++++++++++------------ 1 file changed, 119 insertions(+), 54 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 2ff059b464ab4..a015c8fc120e0 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -38,64 +38,125 @@ impl Drop for CopyOnDrop { } } -/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case. -fn insertion_sort(v: &mut [T], is_less: &mut F) +/// Shifts the first element to the right until it encounters a greater or equal element. +fn shift_head(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool { let len = v.len(); + unsafe { + // If the first two elements are out-of-order... + if len >= 2 && is_less(v.get_unchecked(1), v.get_unchecked(0)) { + // Read the first element into a stack-allocated variable. If a following comparison + // operation panics, `hole` will get dropped and automatically write the element back + // into the slice. + let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) }; + let mut hole = CopyOnDrop { + src: &mut tmp.value, + dest: v.get_unchecked_mut(1), + }; + ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); - for i in 1..len { - unsafe { - if is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) { - // There are three ways to implement insertion here: - // - // 1. Swap adjacent elements until the first one gets to its final destination. - // However, this way we copy data around more than is necessary. If elements are - // big structures (costly to copy), this method will be slow. - // - // 2. Iterate until the right place for the first element is found. Then shift the - // elements succeeding it to make room for it and finally place it into the - // remaining hole. This is a good method. - // - // 3. Copy the first element into a temporary variable. Iterate until the right - // place for it is found. As we go along, copy every traversed element into the - // slot preceding it. Finally, copy data from the temporary variable into the - // remaining hole. This method is very good. Benchmarks demonstrated slightly - // better performance than with the 2nd method. - // - // All methods were benchmarked, and the 3rd showed best results. So we chose that - // one. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(i)) }; - - // Intermediate state of the insertion process is always tracked by `hole`, which - // serves two purposes: - // 1. Protects integrity of `v` from panics in `is_less`. - // 2. Fills the remaining hole in `v` in the end. - // - // Panic safety: - // - // If `is_less` panics at any point during the process, `hole` will get dropped and - // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object - // it initially held exactly once. - let mut hole = CopyOnDrop { - src: &mut tmp.value, - dest: v.get_unchecked_mut(i - 1), - }; - ptr::copy_nonoverlapping(v.get_unchecked(i - 1), v.get_unchecked_mut(i), 1); - - for h in (0..i-1).rev() { - if !is_less(&tmp.value, v.get_unchecked(h)) { - break; - } - ptr::copy_nonoverlapping(v.get_unchecked(h), v.get_unchecked_mut(h + 1), 1); - hole.dest = v.get_unchecked_mut(h); + for i in 2..len { + if !is_less(&v[i], &tmp.value) { + break; } - // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. + + // Move `i`-th element one place to the left, thus shifting the hole to the right. + ptr::copy_nonoverlapping(v.get_unchecked(i), v.get_unchecked_mut(i - 1), 1); + hole.dest = v.get_unchecked_mut(i); } + // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. } } } +/// Shifts the last element to the left until it encounters a smaller or equal element. +fn shift_tail(v: &mut [T], is_less: &mut F) + where F: FnMut(&T, &T) -> bool +{ + let len = v.len(); + unsafe { + // If the last two elements are out-of-order... + if len >= 2 && is_less(v.get_unchecked(len - 1), v.get_unchecked(len - 2)) { + // Read the last element into a stack-allocated variable. If a following comparison + // operation panics, `hole` will get dropped and automatically write the element back + // into the slice. + let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) }; + let mut hole = CopyOnDrop { + src: &mut tmp.value, + dest: v.get_unchecked_mut(len - 2), + }; + ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1); + + for i in (0..len-2).rev() { + if !is_less(&tmp.value, v.get_unchecked(i)) { + break; + } + + // Move `i`-th element one place to the right, thus shifting the hole to the left. + ptr::copy_nonoverlapping(v.get_unchecked(i), v.get_unchecked_mut(i + 1), 1); + hole.dest = v.get_unchecked_mut(i); + } + // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`. + } + } +} + +/// Partially sorts a slice by shifting several out-of-order elements around. +/// +/// Returns true if the slice is sorted at the end. This function is `O(n)` worst-case. +#[cold] +fn partial_insertion_sort(v: &mut [T], is_less: &mut F) -> bool + where F: FnMut(&T, &T) -> bool +{ + // Maximum number of adjacent out-of-order pairs that will get shifted. + const MAX_STEPS: usize = 5; + // If the slice is shorter than this, don't shift any elements. + const SHORTEST_SHIFTING: usize = 50; + + let len = v.len(); + let mut i = 1; + + for _ in 0..MAX_STEPS { + unsafe { + // Find the next pair of adjacent out-of-order elements. + while i < len && !is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) { + i += 1; + } + } + + // Are we done? + if i == len { + return true; + } + + // Don't shift elements on short arrays, that has a performance cost. + if len < SHORTEST_SHIFTING { + return false; + } + + // Swap the found pair of elements. This puts them in correct order. + v.swap(i - 1, i); + + // Shift the smaller element to the left. + shift_tail(&mut v[..i], is_less); + // Shift the greater element to the right. + shift_head(&mut v[i..], is_less); + } + + // Didn't manage to sort the slice in the limited number of steps. + false +} + +/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case. +fn insertion_sort(v: &mut [T], is_less: &mut F) + where F: FnMut(&T, &T) -> bool +{ + for i in 2..v.len()+1 { + shift_tail(&mut v[..i], is_less); + } +} + /// Sorts `v` using heapsort, which guarantees `O(n log n)` worst-case. #[cold] fn heapsort(v: &mut [T], is_less: &mut F) @@ -180,6 +241,9 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize let mut end_r = ptr::null_mut(); let mut offsets_r: [u8; BLOCK] = unsafe { mem::uninitialized() }; + // FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather + // than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient. + // Returns the number of elements between pointers `l` (inclusive) and `r` (exclusive). fn width(l: *mut T, r: *mut T) -> usize { assert!(mem::size_of::() > 0); @@ -470,10 +534,10 @@ fn break_patterns(v: &mut [T]) { fn choose_pivot(v: &mut [T], is_less: &mut F) -> (usize, bool) where F: FnMut(&T, &T) -> bool { - // Minimal length to choose the median-of-medians method. + // Minimum length to choose the median-of-medians method. // Shorter slices use the simple median-of-three method. - const SHORTEST_MEDIAN_OF_MEDIANS: usize = 80; - // Maximal number of swaps that can be performed in this function. + const SHORTEST_MEDIAN_OF_MEDIANS: usize = 50; + // Maximum number of swaps that can be performed in this function. const MAX_SWAPS: usize = 4 * 3; let len = v.len(); @@ -522,7 +586,7 @@ fn choose_pivot(v: &mut [T], is_less: &mut F) -> (usize, bool) if swaps < MAX_SWAPS { (b, swaps == 0) } else { - // The maximal number of swaps was performed. Chances are the slice is descending or mostly + // The maximum number of swaps was performed. Chances are the slice is descending or mostly // descending, so reversing will probably help sort it faster. v.reverse(); (len - 1 - b, true) @@ -575,8 +639,9 @@ fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T // If the last partitioning was decently balanced and didn't shuffle elements, and if pivot // selection predicts the slice is likely already sorted... if was_balanced && was_partitioned && likely_sorted { - // Check whether the slice really is sorted. If so, we're done. - if v.windows(2).all(|w| !is_less(&w[1], &w[0])) { + // Try identifying several out-of-order elements and shifting them to correct + // positions. If the slice ends up being completely sorted, we're done. + if partial_insertion_sort(v, is_less) { return; } } From a18b2aa641da7c000fea9e9ac62d2da89fa034ad Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 20 Mar 2017 16:50:07 +0100 Subject: [PATCH 165/662] Remove stabilized features --- src/libcoretest/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index e8dbbd55df259..4f3b775ceb2e0 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -21,10 +21,7 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(libc)] -#![feature(move_cell)] #![feature(nonzero)] -#![feature(ordering_chaining)] -#![feature(ptr_unaligned)] #![feature(rand)] #![feature(raw)] #![feature(sip_hash_13)] From a718051f63308638ecf40a7570dbd18f4fc99703 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Tue, 21 Mar 2017 02:38:03 +0100 Subject: [PATCH 166/662] Unit test heapsort --- src/libcore/slice/mod.rs | 9 ++++++++ src/libcore/slice/sort.rs | 4 ++-- src/libcoretest/lib.rs | 1 + src/libcoretest/slice.rs | 44 +++++++++++++++++++++++++++------------ 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 53cbdd84c3a8d..6f8b199f886b7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2253,6 +2253,15 @@ pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { mem::transmute(Repr { data: p, len: len }) } +// This function is public only because there is no other way to unit test heapsort. +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "0")] +#[doc(hidden)] +pub fn heapsort(v: &mut [T], mut is_less: F) + where F: FnMut(&T, &T) -> bool +{ + sort::heapsort(v, &mut is_less); +} + // // Comparison traits // diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index a015c8fc120e0..fdfba33f8a9d9 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -57,7 +57,7 @@ fn shift_head(v: &mut [T], is_less: &mut F) ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); for i in 2..len { - if !is_less(&v[i], &tmp.value) { + if !is_less(v.get_unchecked(i), &tmp.value) { break; } @@ -159,7 +159,7 @@ fn insertion_sort(v: &mut [T], is_less: &mut F) /// Sorts `v` using heapsort, which guarantees `O(n log n)` worst-case. #[cold] -fn heapsort(v: &mut [T], is_less: &mut F) +pub fn heapsort(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool { // This binary heap respects the invariant `parent >= child`. diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 4f3b775ceb2e0..d92c378160d2e 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -26,6 +26,7 @@ #![feature(raw)] #![feature(sip_hash_13)] #![feature(slice_patterns)] +#![feature(sort_internals)] #![feature(sort_unstable)] #![feature(step_by)] #![feature(test)] diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index b51bae4db2251..89bd3be08519c 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::slice::heapsort; use core::result::Result::{Ok, Err}; use rand::{Rng, XorShiftRng}; @@ -226,26 +227,43 @@ fn get_unchecked_mut_range() { #[test] fn sort_unstable() { let mut v = [0; 600]; - let mut v1 = [0; 600]; + let mut tmp = [0; 600]; let mut rng = XorShiftRng::new_unseeded(); for len in (2..25).chain(500..510) { - for &modulus in &[10, 1000] { + let v = &mut v[0..len]; + let tmp = &mut tmp[0..len]; + + for &modulus in &[5, 10, 100, 1000] { for _ in 0..100 { for i in 0..len { - let num = rng.gen::() % modulus; - v[i] = num; - v1[i] = num; + v[i] = rng.gen::() % modulus; } - v.sort_unstable(); - assert!(v.windows(2).all(|w| w[0] <= w[1])); - - v1.sort_unstable_by(|a, b| a.cmp(b)); - assert!(v1.windows(2).all(|w| w[0] <= w[1])); - - v1.sort_unstable_by(|a, b| b.cmp(a)); - assert!(v1.windows(2).all(|w| w[0] >= w[1])); + // Sort in default order. + tmp.copy_from_slice(v); + tmp.sort_unstable(); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in ascending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| a.cmp(b)); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in descending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| b.cmp(a)); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + + // Test heapsort using `<` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a < b); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Test heapsort using `>` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a > b); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); } } } From b5e889791a5ec8cb06224cf07273be8c84192698 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 17 Mar 2017 00:47:32 +0300 Subject: [PATCH 167/662] Refactor parsing of trait object types --- src/libsyntax/ast.rs | 12 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 404 ++++++++---------- src/libsyntax/parse/token.rs | 44 +- src/test/compile-fail/E0178.rs | 3 - src/test/compile-fail/issue-34334.rs | 2 +- .../restricted/tuple-struct-fields/test.rs | 4 +- .../restricted/tuple-struct-fields/test2.rs | 4 +- .../restricted/tuple-struct-fields/test3.rs | 4 +- .../trait-object-macro-matcher.rs | 19 + ...ect-reference-without-parens-suggestion.rs | 3 +- src/test/parse-fail/bounds-obj-parens.rs | 2 +- src/test/parse-fail/issue-17904.rs | 2 +- .../parse-fail/removed-syntax-ptr-lifetime.rs | 2 +- .../parse-fail/removed-syntax-uniq-mut-ty.rs | 2 +- .../parse-fail/trailing-plus-in-bounds.rs | 6 +- .../parse-fail/trait-object-macro-matcher.rs | 20 + .../trait-object-polytrait-priority.rs | 19 + src/test/run-pass/issue-28279.rs | 3 +- 21 files changed, 294 insertions(+), 267 deletions(-) create mode 100644 src/test/compile-fail/trait-object-macro-matcher.rs create mode 100644 src/test/parse-fail/trait-object-macro-matcher.rs create mode 100644 src/test/parse-fail/trait-object-polytrait-priority.rs diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 84fb69a7f1094..4347046b6b808 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -17,7 +17,7 @@ pub use self::PathParameters::*; pub use symbol::Symbol as Name; pub use util::ThinVec; -use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::SyntaxContext; @@ -1716,6 +1716,16 @@ pub struct PolyTraitRef { pub span: Span, } +impl PolyTraitRef { + pub fn new(lifetimes: Vec, path: Path, lo: BytePos, hi: BytePos) -> Self { + PolyTraitRef { + bound_lifetimes: lifetimes, + trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID }, + span: mk_sp(lo, hi), + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Visibility { Public, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c1816582bc6ca..6abeb4b0b2805 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -657,7 +657,7 @@ impl<'a> Parser<'a> { } ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?), ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)), - ExpansionKind::Ty => Expansion::Ty(self.parse_ty_no_plus()?), + ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?), ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?), }) } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 10b7249743b8c..d7a85baa3fff5 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -414,7 +414,7 @@ pub fn parse_arm_panic(parser: &mut Parser) -> Arm { } pub fn parse_ty_panic(parser: &mut Parser) -> P { - panictry!(parser.parse_ty_no_plus()) + panictry!(parser.parse_ty()) } pub fn parse_stmt_panic(parser: &mut Parser) -> Option { diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 6385d206a0cb9..ed17f0f956cf3 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -512,7 +512,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "pat" => token::NtPat(panictry!(p.parse_pat())), "expr" => token::NtExpr(panictry!(p.parse_expr())), - "ty" => token::NtTy(panictry!(p.parse_ty_no_plus())), + "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => match p.token { token::Ident(sn) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0a97accead6a2..df4ccc94c0421 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -41,7 +41,7 @@ use ast::{BinOpKind, UnOp}; use ast::RangeEnd; use {ast, attr}; use codemap::{self, CodeMap, Spanned, spanned, respan}; -use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; +use syntax_pos::{self, Span, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; use parse::{self, classify, token}; use parse::common::SeqSep; @@ -1116,57 +1116,13 @@ impl<'a> Parser<'a> { self.check_keyword(keywords::Extern) } - pub fn get_lifetime(&mut self) -> ast::Ident { + fn get_label(&mut self) -> ast::Ident { match self.token { token::Lifetime(ref ident) => *ident, _ => self.bug("not a lifetime"), } } - pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> { - /* - Parses whatever can come after a `for` keyword in a type. - The `for` hasn't been consumed. - - - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T - - for <'lt> path::foo(a, b) + Trait + 'a - */ - - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - // examine next token to decide to do - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs) - } else { - let hi = self.span.hi; - let trait_ref = self.parse_trait_ref()?; - let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: trait_ref, - span: mk_sp(lo, hi)}; - let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds()? - } else { - Vec::new() - }; - let all_bounds = - Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() - .chain(other_bounds) - .collect(); - Ok(ast::TyKind::TraitObject(all_bounds)) - } - } - - pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> { - // Parses whatever can come after a `impl` keyword in a type. - // The `impl` has already been consumed. - Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?)) - } - - pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { - Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?)) - } - /// parse a TyKind::BareFn type: pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult<'a, TyKind> { @@ -1347,84 +1303,9 @@ impl<'a> Parser<'a> { } } - /// Parse a type. + // Parse a type pub fn parse_ty(&mut self) -> PResult<'a, P> { - let lo = self.span.lo; - let lhs = self.parse_ty_no_plus()?; - - if !self.eat(&token::BinOp(token::Plus)) { - return Ok(lhs); - } - - let mut bounds = self.parse_ty_param_bounds()?; - - // In type grammar, `+` is treated like a binary operator, - // and hence both L and R side are required. - if bounds.is_empty() { - let prev_span = self.prev_span; - self.span_err(prev_span, - "at least one type parameter bound \ - must be specified"); - } - - let mut lhs = lhs.unwrap(); - if let TyKind::Paren(ty) = lhs.node { - // We have to accept the first bound in parens for backward compatibility. - // Example: `(Bound) + Bound + Bound` - lhs = ty.unwrap(); - } - if let TyKind::Path(None, path) = lhs.node { - let poly_trait_ref = PolyTraitRef { - bound_lifetimes: Vec::new(), - trait_ref: TraitRef { path: path, ref_id: lhs.id }, - span: lhs.span, - }; - let poly_trait_ref = TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None); - bounds.insert(0, poly_trait_ref); - } else { - let mut err = struct_span_err!(self.sess.span_diagnostic, lhs.span, E0178, - "expected a path on the left-hand side \ - of `+`, not `{}`", - pprust::ty_to_string(&lhs)); - err.span_label(lhs.span, &format!("expected a path")); - let hi = bounds.iter().map(|x| match *x { - TraitTyParamBound(ref tr, _) => tr.span.hi, - RegionTyParamBound(ref r) => r.span.hi, - }).max_by_key(|x| x.to_usize()); - let full_span = hi.map(|hi| Span { - lo: lhs.span.lo, - hi: hi, - expn_id: lhs.span.expn_id, - }); - match (&lhs.node, full_span) { - (&TyKind::Rptr(ref lifetime, ref mut_ty), Some(full_span)) => { - let ty_str = pprust::to_string(|s| { - use print::pp::word; - use print::pprust::PrintState; - - word(&mut s.s, "&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", - ty_str); - } - - _ => { - help!(&mut err, - "perhaps you forgot parentheses? (per RFC 438)"); - } - } - err.emit(); - } - - let sp = mk_sp(lo, self.prev_span.hi); - let sum = TyKind::TraitObject(bounds); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})) + self.parse_ty_common(true) } /// Parse a type in restricted contexts where `+` is not permitted. @@ -1432,15 +1313,17 @@ impl<'a> Parser<'a> { /// `+` is prohibited to maintain operator priority (P(+) < P(&)). /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. - pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { + fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { + self.parse_ty_common(false) + } + + fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { maybe_whole!(self, NtTy, |x| x); let lo = self.span.lo; - - let t = if self.eat(&token::OpenDelim(token::Paren)) { - // (t) is a parenthesized ty - // (t,) is the type of a tuple with only one field, - // of type t + let node = if self.eat(&token::OpenDelim(token::Paren)) { + // `(TYPE)` is a parenthesized type. + // `(TYPE,)` is a tuple with a single field of type TYPE. let mut ts = vec![]; let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { @@ -1452,81 +1335,162 @@ impl<'a> Parser<'a> { break; } } - self.expect(&token::CloseDelim(token::Paren))?; + if ts.len() == 1 && !last_comma { - TyKind::Paren(ts.into_iter().nth(0).unwrap()) + let ty = ts.into_iter().nth(0).unwrap().unwrap(); + match ty.node { + // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). + TyKind::Path(None, ref path) + if allow_plus && self.token == token::BinOp(token::Plus) => { + self.bump(); // `+` + let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo, self.prev_span.hi); + let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } + _ => TyKind::Paren(P(ty)) + } } else { TyKind::Tup(ts) } } else if self.eat(&token::Not) { + // Never type `!` TyKind::Never } else if self.eat(&token::BinOp(token::Star)) { - // STAR POINTER (bare pointer?) + // Raw pointer TyKind::Ptr(self.parse_ptr()?) } else if self.eat(&token::OpenDelim(token::Bracket)) { - // VECTOR + // Array or slice let t = self.parse_ty()?; - - // Parse the `; e` in `[ i32; e ]` - // where `e` is a const expression + // Parse optional `; EXPR` in `[TYPE; EXPR]` let t = match self.maybe_parse_fixed_length_of_vec()? { None => TyKind::Slice(t), - Some(suffix) => TyKind::Array(t, suffix) + Some(suffix) => TyKind::Array(t, suffix), }; self.expect(&token::CloseDelim(token::Bracket))?; t - } else if self.check(&token::BinOp(token::And)) || - self.check(&token::AndAnd) { - // BORROWED POINTER + } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { + // Reference self.expect_and()?; self.parse_borrowed_pointee()? - } else if self.check_keyword(keywords::For) { - // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317). - self.parse_for_in_type()? - } else if self.eat_keyword(keywords::Impl) { - // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511). - self.parse_impl_trait_type()? - } else if self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn(Vec::new())? } else if self.eat_keyword_noexpect(keywords::Typeof) { - // TYPEOF + // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; let e = self.parse_expr()?; self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) + } else if self.eat(&token::Underscore) { + // A type to be inferred `_` + TyKind::Infer } else if self.eat_lt() { + // Qualified path let (qself, path) = self.parse_qualified_path(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { + // Simple path let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { - // MACRO INVOCATION + // Macro invocation in type position let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.span.hi; - TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts })) + TyKind::Mac(spanned(lo, self.span.hi, Mac_ { path: path, tts: tts })) } else { - // NAMED TYPE - TyKind::Path(None, path) + // Just a type path or bound list (trait object type) starting with a trait. + // `Type` + // `Trait1 + Trait2 + 'a` + if allow_plus && self.eat(&token::BinOp(token::Plus)) { + let poly_trait = PolyTraitRef::new(Vec::new(), path, lo, self.prev_span.hi); + let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } else { + TyKind::Path(None, path) + } } - } else if self.eat(&token::Underscore) { - // TYPE TO BE INFERRED - TyKind::Infer + } else if self.token_is_bare_fn_keyword() { + // Function pointer type + self.parse_ty_bare_fn(Vec::new())? + } else if self.check_keyword(keywords::For) { + // Function pointer type or bound list (trait object type) starting with a poly-trait. + // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` + // `for<'lt> Trait1<'lt> + Trait2 + 'a` + let lo = self.span.lo; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + if self.token_is_bare_fn_keyword() { + self.parse_ty_bare_fn(lifetime_defs)? + } else { + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); + let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; + if allow_plus && self.eat(&token::BinOp(token::Plus)) { + bounds.append(&mut self.parse_ty_param_bounds()?) + } + TyKind::TraitObject(bounds) + } + } else if self.eat_keyword(keywords::Impl) { + // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). + TyKind::ImplTrait(self.parse_ty_param_bounds()?) + } else if self.check(&token::Question) { + // Bound list (trait object type) + // Bound lists starting with `'lt` are not currently supported (#40043) + TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?) } else { let msg = format!("expected type, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); }; - let sp = mk_sp(lo, self.prev_span.hi); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) + let span = mk_sp(lo, self.prev_span.hi); + let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; + + // Try to recover from use of `+` with incorrect priority. + self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + + Ok(P(ty)) } - pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.eat_lifetime(); - let mutbl = self.parse_mutability()?; + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || self.token != token::BinOp(token::Plus) { + return Ok(()) + } + + self.bump(); // `+` + let bounds = self.parse_ty_param_bounds()?; + let sum_span = mk_sp(ty.span.lo, self.prev_span.hi); + + let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178, + "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty)); + err.span_label(ty.span, &format!("expected a path")); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use print::pp::word; + use print::pprust::PrintState; + + word(&mut s.s, "&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + help!(&mut err, "perhaps you forgot parentheses?"); + } + _ => {} + } + err.emit(); + Ok(()) + } + + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { + let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); } @@ -1927,30 +1891,28 @@ impl<'a> Parser<'a> { } } - /// Parse single lifetime 'a or nothing. - pub fn eat_lifetime(&mut self) -> Option { + fn check_lifetime(&mut self) -> bool { + self.expected_tokens.push(TokenType::Lifetime); + self.token.is_lifetime() + } + + /// Parse single lifetime 'a or panic. + fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { self.bump(); - Some(Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.prev_span, - name: ident.name - }) - } - _ => { - self.expected_tokens.push(TokenType::Lifetime); - None + Lifetime { name: ident.name, span: self.prev_span, id: ast::DUMMY_NODE_ID } } + _ => self.span_bug(self.span, "not a lifetime") } } /// Parse mutability (`mut` or nothing). - pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> { + fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(keywords::Mut) { - Ok(Mutability::Mutable) + Mutability::Mutable } else { - Ok(Mutability::Immutable) + Mutability::Immutable } } @@ -2207,7 +2169,7 @@ impl<'a> Parser<'a> { return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { - let label = Spanned { node: self.get_lifetime(), + let label = Spanned { node: self.get_label(), span: self.span }; let lo = self.span.lo; self.bump(); @@ -2230,7 +2192,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Continue) { let ex = if self.token.is_lifetime() { let ex = ExprKind::Continue(Some(Spanned{ - node: self.get_lifetime(), + node: self.get_label(), span: self.span })); self.bump(); @@ -2267,7 +2229,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Break) { let lt = if self.token.is_lifetime() { let spanned_lt = Spanned { - node: self.get_lifetime(), + node: self.get_label(), span: self.span }; self.bump(); @@ -2700,7 +2662,7 @@ impl<'a> Parser<'a> { } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; - let m = self.parse_mutability()?; + let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; hi = span.hi; @@ -3422,7 +3384,7 @@ impl<'a> Parser<'a> { token::BinOp(token::And) | token::AndAnd => { // Parse &pat / &mut pat self.expect_and()?; - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); if let token::Lifetime(ident) = self.token { return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); } @@ -3449,7 +3411,7 @@ impl<'a> Parser<'a> { pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?; } else if self.eat_keyword(keywords::Ref) { // Parse ref ident @ pat / ref mut ident @ pat - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; } else if self.eat_keyword(keywords::Box) { // Parse box pat @@ -4069,30 +4031,32 @@ impl<'a> Parser<'a> { // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) - fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> - { + fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { if let Some(question_span) = question { self.span_err(question_span, "`?` may only modify trait bounds, not lifetime bounds"); } - bounds.push(RegionTyParamBound(lifetime)); - } else {if self.check_keyword(keywords::For) || self.check_path() { - let poly_trait_ref = self.parse_poly_trait_ref()?; + bounds.push(RegionTyParamBound(self.expect_lifetime())); + } else if self.check_keyword(keywords::For) || self.check_path() { + let lo = self.span.lo; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); let modifier = if question.is_some() { TraitBoundModifier::Maybe } else { TraitBoundModifier::None }; - bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); + bounds.push(TraitTyParamBound(poly_trait, modifier)); } else { break - }} + } - if !self.eat(&token::BinOp(token::Plus)) { + if !allow_plus || !self.eat(&token::BinOp(token::Plus)) { break } } @@ -4100,12 +4064,16 @@ impl<'a> Parser<'a> { return Ok(bounds); } + fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { + self.parse_ty_param_bounds_common(true) + } + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec { let mut lifetimes = Vec::new(); - while let Some(lifetime) = self.eat_lifetime() { - lifetimes.push(lifetime); + while self.check_lifetime() { + lifetimes.push(self.expect_lifetime()); if !self.eat(&token::BinOp(token::Plus)) { break @@ -4150,7 +4118,8 @@ impl<'a> Parser<'a> { let mut seen_ty_param = false; loop { let attrs = self.parse_outer_attributes()?; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { + let lifetime = self.expect_lifetime(); // Parse lifetime parameter. let bounds = if self.eat(&token::Colon) { self.parse_lt_param_bounds() @@ -4166,7 +4135,7 @@ impl<'a> Parser<'a> { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() { + } else if self.check_ident() { // Parse type parameter. ty_params.push(self.parse_ty_param(attrs)?); seen_ty_param = true; @@ -4178,7 +4147,7 @@ impl<'a> Parser<'a> { &format!("trailing attribute after {} parameters", param_kind)); } break - }} + } if !self.eat(&token::Comma) { break @@ -4224,14 +4193,14 @@ impl<'a> Parser<'a> { let mut seen_type = false; let mut seen_binding = false; loop { - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { // Parse lifetime argument. - lifetimes.push(lifetime); + lifetimes.push(self.expect_lifetime()); if seen_type || seen_binding { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { + } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. let lo = self.span.lo; let ident = self.parse_ident()?; @@ -4254,7 +4223,7 @@ impl<'a> Parser<'a> { seen_type = true; } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4299,7 +4268,8 @@ impl<'a> Parser<'a> { loop { let lo = self.span.lo; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { + let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. self.expect(&token::Colon)?; let bounds = self.parse_lt_param_bounds(); @@ -4310,7 +4280,7 @@ impl<'a> Parser<'a> { bounds: bounds, } )); - } else {if self.check_type() { + } else if self.check_type() { // Parse optional `for<'a, 'b>`. // This `for` is parsed greedily and applies to the whole predicate, // the bounded type can have its own `for` applying only to it. @@ -4348,7 +4318,7 @@ impl<'a> Parser<'a> { } } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4453,13 +4423,13 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| t.is_lifetime()) && isolated_self(self, 2) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && isolated_self(self, 3) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { @@ -4852,14 +4822,6 @@ impl<'a> Parser<'a> { } } - /// Parse a::B - fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { - Ok(TraitRef { - path: self.parse_path(PathStyle::Type)?, - ref_id: ast::DUMMY_NODE_ID, - }) - } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(keywords::For) { self.expect_lt()?; @@ -4875,18 +4837,6 @@ impl<'a> Parser<'a> { } } - /// Parse for<'l> a::B - fn parse_poly_trait_ref(&mut self) -> PResult<'a, PolyTraitRef> { - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - Ok(PolyTraitRef { - bound_lifetimes: lifetime_defs, - trait_ref: self.parse_trait_ref()?, - span: mk_sp(lo, self.prev_span.hi), - }) - } - /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 75852629ce131..519d5bd98e47f 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -103,6 +103,21 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { ].contains(&ident.name) } +fn ident_can_begin_type(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::For.name(), + keywords::Impl.name(), + keywords::Fn.name(), + keywords::Unsafe.name(), + keywords::Extern.name(), + keywords::Typeof.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -182,23 +197,21 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { match *self { - OpenDelim(..) => true, - Ident(ident) => ident_can_begin_expr(ident), - Literal(..) => true, - Not => true, - BinOp(Minus) => true, - BinOp(Star) => true, - BinOp(And) => true, - BinOp(Or) => true, // in lambda syntax - OrOr => true, // in lambda syntax - AndAnd => true, // double borrow + Ident(ident) => ident_can_begin_expr(ident), // value name or keyword + OpenDelim(..) => true, // tuple, array or block + Literal(..) => true, // literal + Not => true, // operator not + BinOp(Minus) => true, // unary minus + BinOp(Star) => true, // dereference + BinOp(Or) | OrOr => true, // closure + BinOp(And) => true, // reference + AndAnd => true, // double reference DotDot | DotDotDot => true, // range notation Lt | BinOp(Shl) => true, // associated path - ModSep => true, - Pound => true, // for expression attributes + ModSep => true, // global path + Pound => true, // expression attributes Interpolated(ref nt) => match **nt { NtExpr(..) => true, - NtIdent(..) => true, NtBlock(..) => true, NtPath(..) => true, _ => false, @@ -210,19 +223,20 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match *self { + Ident(ident) => ident_can_begin_type(ident), // type name or keyword OpenDelim(Paren) => true, // tuple OpenDelim(Bracket) => true, // array - Ident(..) => true, // type name or keyword Underscore => true, // placeholder Not => true, // never BinOp(Star) => true, // raw pointer BinOp(And) => true, // reference AndAnd => true, // double reference + Question => true, // maybe bound in trait object + Lifetime(..) => true, // lifetime bound in trait object Lt | BinOp(Shl) => true, // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { NtTy(..) => true, - NtIdent(..) => true, NtPath(..) => true, _ => false, }, diff --git a/src/test/compile-fail/E0178.rs b/src/test/compile-fail/E0178.rs index ffc5940c95c98..6527465e0b7f7 100644 --- a/src/test/compile-fail/E0178.rs +++ b/src/test/compile-fail/E0178.rs @@ -17,15 +17,12 @@ struct Bar<'a> { x: &'a Foo + 'a, //~^ ERROR E0178 //~| NOTE expected a path - //~| ERROR at least one non-builtin trait is required for an object type y: &'a mut Foo + 'a, //~^ ERROR E0178 //~| NOTE expected a path - //~| ERROR at least one non-builtin trait is required for an object type z: fn() -> Foo + 'a, //~^ ERROR E0178 //~| NOTE expected a path - //~| ERROR at least one non-builtin trait is required for an object type } fn main() { diff --git a/src/test/compile-fail/issue-34334.rs b/src/test/compile-fail/issue-34334.rs index aff908e581530..95b5fabc81e4f 100644 --- a/src/test/compile-fail/issue-34334.rs +++ b/src/test/compile-fail/issue-34334.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main () { - let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `+`, `,`, or `>`, found `=` + let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); //~^ ERROR cannot find value `sr` in this scope } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index bb212b3114d11..208f1a0e2ee25 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -11,6 +11,6 @@ mod foo { type T = (); struct S1(pub(foo) (), pub(T), pub(crate) (), pub(((), T))); - struct S2(pub((foo)) ()); //~ ERROR expected one of `+` or `,`, found `(` - //~| ERROR expected one of `+`, `;`, or `where`, found `(` + struct S2(pub((foo)) ()); //~ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 2c6e71d7c55e6..57769646e3b8f 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -12,8 +12,8 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); struct S2(pub (foo) ()); - struct S3(pub $t ()); //~ ERROR expected one of `+` or `,`, found `(` - //~| ERROR expected one of `+`, `;`, or `where`, found `(` + struct S3(pub $t ()); //~ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index e15eeae8159a3..db3358f7d50ae 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -12,8 +12,8 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); struct S2(pub (foo) ()); - struct S3(pub($t) ()); //~ ERROR expected one of `+` or `,`, found `(` - //~| ERROR expected one of `+`, `;`, or `where`, found `(` + struct S3(pub($t) ()); //~ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/trait-object-macro-matcher.rs b/src/test/compile-fail/trait-object-macro-matcher.rs new file mode 100644 index 0000000000000..de80b04b86568 --- /dev/null +++ b/src/test/compile-fail/trait-object-macro-matcher.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +// `ty` matcher accepts trait object types + +macro_rules! m { + ($t: ty) => ( let _: $t; ) +} + +fn main() { + m!(Copy + Send + 'static); //~ ERROR the trait `std::marker::Copy` cannot be made into an object +} diff --git a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs index c009644c5619f..f9f887b78b0d8 100644 --- a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs +++ b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs @@ -13,10 +13,9 @@ fn main() { //~^ ERROR expected a path //~| HELP try adding parentheses //~| SUGGESTION let _: &(Copy + 'static); - //~| ERROR at least one non-builtin trait is required for an object type + //~| ERROR the trait `std::marker::Copy` cannot be made into an object let _: &'static Copy + 'static; //~^ ERROR expected a path //~| HELP try adding parentheses //~| SUGGESTION let _: &'static (Copy + 'static); - //~| ERROR at least one non-builtin trait is required for an object type } diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/parse-fail/bounds-obj-parens.rs index cbdffb4a2554e..ad59d4a52d74c 100644 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ b/src/test/parse-fail/bounds-obj-parens.rs @@ -10,6 +10,6 @@ // compile-flags: -Z parse-only -type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK +type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) FAIL //~ ERROR diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs index ae28ac76acb98..a54d89f48c300 100644 --- a/src/test/parse-fail/issue-17904.rs +++ b/src/test/parse-fail/issue-17904.rs @@ -13,6 +13,6 @@ struct Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. struct Baz(U) where U: Eq; // This rightfully signals no error as well. -struct Foo where T: Copy, (T); //~ ERROR expected one of `+`, `:`, `==`, or `=`, found `;` +struct Foo where T: Copy, (T); //~ ERROR expected one of `:`, `==`, or `=`, found `;` fn main() {} diff --git a/src/test/parse-fail/removed-syntax-ptr-lifetime.rs b/src/test/parse-fail/removed-syntax-ptr-lifetime.rs index ebef0e56e3e2b..b91ab8730b3dc 100644 --- a/src/test/parse-fail/removed-syntax-ptr-lifetime.rs +++ b/src/test/parse-fail/removed-syntax-ptr-lifetime.rs @@ -10,4 +10,4 @@ // compile-flags: -Z parse-only -type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, or `<`, found `/` +type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, or `<`, found `/` diff --git a/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs b/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs index 9bd8dc9b11b21..8a47376179dfd 100644 --- a/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs +++ b/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs @@ -10,4 +10,4 @@ // compile-flags: -Z parse-only -type mut_box = Box; //~ ERROR expected type, found keyword `mut` +type mut_box = Box; //~ ERROR expected one of `>`, lifetime, or type, found `mut` diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 44bb1f930c7bd..4a2e6d5bdcd9c 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -13,7 +13,7 @@ use std::fmt::Debug; fn main() { - let x: Box = box 3 as Box; - //~^ ERROR at least one type parameter bound must be specified - //~^^ ERROR at least one type parameter bound must be specified + let x: Box = box 3 as Box; // Trailing `+` is OK } + +FAIL //~ ERROR diff --git a/src/test/parse-fail/trait-object-macro-matcher.rs b/src/test/parse-fail/trait-object-macro-matcher.rs new file mode 100644 index 0000000000000..3a5bce509f10e --- /dev/null +++ b/src/test/parse-fail/trait-object-macro-matcher.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A single lifetime is not parsed as a type. +// `ty` matcher in particular doesn't accept a single lifetime + +macro_rules! m { + ($t: ty) => ( let _: $t; ) +} + +fn main() { + m!('static); //~ ERROR expected type, found `'static` +} diff --git a/src/test/parse-fail/trait-object-polytrait-priority.rs b/src/test/parse-fail/trait-object-polytrait-priority.rs new file mode 100644 index 0000000000000..f0abc678c2130 --- /dev/null +++ b/src/test/parse-fail/trait-object-polytrait-priority.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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<'a> {} + +fn main() { + let _: &for<'a> Trait<'a> + 'static; + //~^ ERROR expected a path on the left-hand side of `+`, not `& for<'a>Trait<'a>` + //~| NOTE expected a path + //~| HELP try adding parentheses + //~| SUGGESTION &( for<'a>Trait<'a> + 'static) +} diff --git a/src/test/run-pass/issue-28279.rs b/src/test/run-pass/issue-28279.rs index ae40ce44d178d..3165084b9e90d 100644 --- a/src/test/run-pass/issue-28279.rs +++ b/src/test/run-pass/issue-28279.rs @@ -18,7 +18,7 @@ fn test1() -> Rc Fn(&'a usize) + 'static> { } } -fn test2() -> *mut for<'a> Fn(&'a usize) + 'static { +fn test2() -> *mut (for<'a> Fn(&'a usize) + 'static) { if let Some(_) = Some(1) { loop{} } else { @@ -27,4 +27,3 @@ fn test2() -> *mut for<'a> Fn(&'a usize) + 'static { } fn main() {} - From 49db656b069c425d5895e4b2b6f6684d80ba24b8 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Mon, 20 Mar 2017 20:01:18 -0500 Subject: [PATCH 168/662] str: Make docs consistently punctuated --- src/libcore/str/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index cf3e8a684dfab..9985cc2b27ad1 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -332,7 +332,7 @@ impl fmt::Display for Utf8Error { Section: Iterators */ -/// Iterator for the char (representing *Unicode Scalar Values*) of a string +/// Iterator for the char (representing *Unicode Scalar Values*) of a string. /// /// Created with the method [`chars`]. /// From ed5702fc581a9d4d72e53e8d7a2ce4475fa8a064 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Mar 2017 22:49:22 +0100 Subject: [PATCH 169/662] Fix invalid linking in iter docs --- src/libcore/iter/iterator.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index fb98e43aa614b..618edf48abd04 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -518,13 +518,13 @@ pub trait Iterator { /// Creates an iterator that both filters and maps. /// - /// The closure must return an [`Option`]. `filter_map()` creates an + /// The closure must return an [`Option`]. `filter_map` creates an /// iterator which calls this closure on each element. If the closure /// returns [`Some(element)`][`Some`], then that element is returned. If the /// closure returns [`None`], it will try again, and call the closure on the /// next element, seeing if it will return [`Some`]. /// - /// Why `filter_map()` and not just [`filter()`].[`map`]? The key is in this + /// Why `filter_map` and not just [`filter`].[`map`]? The key is in this /// part: /// /// [`filter`]: #method.filter @@ -534,7 +534,7 @@ pub trait Iterator { /// /// In other words, it removes the [`Option`] layer automatically. If your /// mapping is already returning an [`Option`] and you want to skip over - /// [`None`]s, then `filter_map()` is much, much nicer to use. + /// [`None`]s, then `filter_map` is much, much nicer to use. /// /// # Examples /// From f53172287a4ebb57e8372ce2647628887a268696 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Mar 2017 22:41:19 +0100 Subject: [PATCH 170/662] Add whitespace around "=" in assoc items --- src/librustdoc/html/format.rs | 4 ++-- src/librustdoc/html/render.rs | 2 +- src/test/rustdoc/doc-assoc-item.rs | 28 ++++++++++++++++++++++++++++ src/test/rustdoc/issue-20646.rs | 4 ++-- 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/test/rustdoc/doc-assoc-item.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a255ba0ad4edf..9f2d02c14dde0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1096,9 +1096,9 @@ impl fmt::Display for clean::ImportSource { impl fmt::Display for clean::TypeBinding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if f.alternate() { - write!(f, "{}={:#}", self.name, self.ty) + write!(f, "{} = {:#}", self.name, self.ty) } else { - write!(f, "{}={}", self.name, self.ty) + write!(f, "{} = {}", self.name, self.ty) } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 7b60d497932de..10fde67a45674 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2808,7 +2808,7 @@ fn render_assoc_items(w: &mut fmt::Formatter, } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { write!(w, "

Methods from \ - {}<Target={}>

", trait_, type_)?; + {}<Target = {}>", trait_, type_)?; RenderMode::ForDeref { mut_: deref_mut_ } } }; diff --git a/src/test/rustdoc/doc-assoc-item.rs b/src/test/rustdoc/doc-assoc-item.rs new file mode 100644 index 0000000000000..36f44295953f0 --- /dev/null +++ b/src/test/rustdoc/doc-assoc-item.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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. + +pub struct Foo { + x: T, +} + +pub trait Bar { + type Fuu; + + fn foo(foo: Self::Fuu); +} + +// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl> Foo' +impl> Foo { + pub fn new(t: T) -> Foo { + Foo { + x: t, + } + } +} diff --git a/src/test/rustdoc/issue-20646.rs b/src/test/rustdoc/issue-20646.rs index 87c40d1157974..49fac20035fc0 100644 --- a/src/test/rustdoc/issue-20646.rs +++ b/src/test/rustdoc/issue-20646.rs @@ -23,7 +23,7 @@ pub trait Trait { } // @has issue_20646/fn.fun.html \ -// '//*[@class="rust fn"]' 'where T: Trait' +// '//*[@class="rust fn"]' 'where T: Trait' pub fn fun(_: T) where T: Trait {} pub mod reexport { @@ -31,6 +31,6 @@ pub mod reexport { // '//*[@id="associatedtype.Output"]' \ // 'type Output' // @has issue_20646/reexport/fn.fun.html \ - // '//*[@class="rust fn"]' 'where T: Trait' + // '//*[@class="rust fn"]' 'where T: Trait' pub use issue_20646::{Trait, fun}; } From 678e882ce2fdafdfa886cc23a288709140cfd125 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 14 Mar 2017 05:16:54 +0000 Subject: [PATCH 171/662] Check for conflicts between macros 1.0 exports (`#[macro_export]`, `#[macro_reexport]`) and macros 2.0 exports (`pub use` macro re-exports and `pub macro` (once implemented) at the crate root. --- src/librustc/hir/def.rs | 2 ++ src/librustc_metadata/decoder.rs | 19 ++++++----------- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/macros.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 21 ++++++++++++++----- .../duplicate-check-macro-exports.rs | 19 +++++++++++++++++ 6 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 src/test/compile-fail/duplicate-check-macro-exports.rs diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index aedb8fef2885c..7bab4a8d725dc 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -12,6 +12,7 @@ use hir::def_id::DefId; use util::nodemap::NodeMap; use syntax::ast; use syntax::ext::base::MacroKind; +use syntax_pos::Span; use hir; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -116,6 +117,7 @@ pub type ExportMap = NodeMap>; pub struct Export { pub name: ast::Name, // The name of the target. pub def: Def, // The definition of the target. + pub span: Span, // The span of the target definition. } impl CtorKind { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b4b9966cbe47b..c2ad598b0c503 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -683,7 +683,7 @@ impl<'a, 'tcx> CrateMetadata { }, ext.kind() ); - callback(def::Export { name: name, def: def }); + callback(def::Export { name: name, def: def, span: DUMMY_SP }); } } return @@ -720,6 +720,7 @@ impl<'a, 'tcx> CrateMetadata { callback(def::Export { def: def, name: self.item_name(child_index), + span: self.entry(child_index).span.decode(self), }); } } @@ -732,12 +733,10 @@ impl<'a, 'tcx> CrateMetadata { } let def_key = self.def_key(child_index); + let span = child.span.decode(self); if let (Some(def), Some(name)) = (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { - callback(def::Export { - def: def, - name: name, - }); + callback(def::Export { def: def, name: name, span: span }); // For non-reexport structs and variants add their constructors to children. // Reexport lists automatically contain constructors when necessary. match def { @@ -745,10 +744,7 @@ impl<'a, 'tcx> CrateMetadata { if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) { let ctor_kind = self.get_ctor_kind(child_index); let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind); - callback(def::Export { - def: ctor_def, - name: name, - }); + callback(def::Export { def: ctor_def, name: name, span: span }); } } Def::Variant(def_id) => { @@ -756,10 +752,7 @@ impl<'a, 'tcx> CrateMetadata { // value namespace, they are reserved for possible future use. let ctor_kind = self.get_ctor_kind(child_index); let ctor_def = Def::VariantCtor(def_id, ctor_kind); - callback(def::Export { - def: ctor_def, - name: name, - }); + callback(def::Export { def: ctor_def, name: name, span: span }); } _ => {} } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index be905a9d0f94a..c33d5b9b6e16b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -605,7 +605,7 @@ impl<'a> Resolver<'a> { let ident = Ident::with_empty_ctxt(name); let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None); if let Ok(binding) = result { - self.macro_exports.push(Export { name: name, def: binding.def() }); + self.macro_exports.push(Export { name: name, def: binding.def(), span: span }); } else { span_err!(self.session, span, E0470, "reexported macro not found"); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index df3be8fa0f810..f72c2eadb04a8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -653,7 +653,7 @@ impl<'a> Resolver<'a> { if attr::contains_name(&item.attrs, "macro_export") { let def = Def::Macro(def_id, MacroKind::Bang); - self.macro_exports.push(Export { name: ident.name, def: def }); + self.macro_exports.push(Export { name: ident.name, def: def, span: item.span }); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index dbc8bca548b76..2f4ac12cd7363 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -21,7 +21,7 @@ use rustc::ty; use rustc::lint::builtin::PRIVATE_IN_PUBLIC; use rustc::hir::def_id::DefId; use rustc::hir::def::*; -use rustc::util::nodemap::FxHashSet; +use rustc::util::nodemap::FxHashMap; use syntax::ast::{Ident, NodeId}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; @@ -763,10 +763,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { *module.globs.borrow_mut() = Vec::new(); let mut reexports = Vec::new(); + let mut exported_macro_names = FxHashMap(); if module as *const _ == self.graph_root as *const _ { - let mut exported_macro_names = FxHashSet(); - for export in mem::replace(&mut self.macro_exports, Vec::new()).into_iter().rev() { - if exported_macro_names.insert(export.name) { + let macro_exports = mem::replace(&mut self.macro_exports, Vec::new()); + for export in macro_exports.into_iter().rev() { + if exported_macro_names.insert(export.name, export.span).is_none() { reexports.push(export); } } @@ -786,7 +787,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if !def.def_id().is_local() { self.session.cstore.export_macros(def.def_id().krate); } - reexports.push(Export { name: ident.name, def: def }); + if let Def::Macro(..) = def { + if let Some(&span) = exported_macro_names.get(&ident.name) { + let msg = + format!("a macro named `{}` has already been exported", ident); + self.session.struct_span_err(span, &msg) + .span_label(span, &format!("`{}` already exported", ident)) + .span_note(binding.span, "previous macro export here") + .emit(); + } + } + reexports.push(Export { name: ident.name, def: def, span: binding.span }); } } diff --git a/src/test/compile-fail/duplicate-check-macro-exports.rs b/src/test/compile-fail/duplicate-check-macro-exports.rs new file mode 100644 index 0000000000000..53d7e54ee5b7b --- /dev/null +++ b/src/test/compile-fail/duplicate-check-macro-exports.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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(use_extern_macros)] + +pub use std::panic; //~ NOTE previous macro export here + +#[macro_export] +macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported +//~| NOTE `panic` already exported + +fn main() {} From fe2b7a49524c889715fb3346d4d309ecbd6ba651 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Mar 2017 19:49:36 -0700 Subject: [PATCH 172/662] rustbuild: Don't hardcode 'nightly' for Cargo It now follows rustc release trains --- src/bootstrap/dist.rs | 19 +++++++++++-------- src/bootstrap/lib.rs | 5 +++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 289c1e1c3a99c..ec992b47a6e4b 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -37,8 +37,12 @@ use channel; use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; fn pkgname(build: &Build, component: &str) -> String { - assert!(component.starts_with("rust")); // does not work with cargo - format!("{}-{}", component, build.rust_package_vers()) + if component == "cargo" { + format!("{}-{}", component, build.cargo_package_vers()) + } else { + assert!(component.starts_with("rust")); + format!("{}-{}", component, build.rust_package_vers()) + } } fn distdir(build: &Build) -> PathBuf { @@ -533,7 +537,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { let src = build.src.join("cargo"); let etc = src.join("src/etc"); let release_num = build.cargo_release_num(); - let name = format!("cargo-{}", build.package_vers(&release_num)); + let name = pkgname(build, "cargo"); let version = build.cargo_info.version(build, &release_num); let tmp = tmpdir(build); @@ -591,12 +595,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { println!("Dist extended stage{} ({})", stage, target); let dist = distdir(build); - let cargo_vers = build.cargo_release_num(); let rustc_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rustc"), target)); - let cargo_installer = dist.join(format!("cargo-{}-{}.tar.gz", - build.package_vers(&cargo_vers), + let cargo_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "cargo"), target)); let docs_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-docs"), @@ -674,7 +677,7 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)), &pkg.join("rustc")); - cp_r(&work.join(&format!("cargo-nightly-{}", target)), + cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)), &pkg.join("cargo")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)), &pkg.join("rust-docs")); @@ -726,7 +729,7 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)) .join("rustc"), &exe.join("rustc")); - cp_r(&work.join(&format!("cargo-nightly-{}", target)) + cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)) .join("cargo"), &exe.join("cargo")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 26f3c06306197..84254d7d6ae51 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1015,6 +1015,11 @@ impl Build { self.package_vers(channel::CFG_RELEASE_NUM) } + /// Returns the value of `package_vers` above for Cargo + fn cargo_package_vers(&self) -> String { + self.package_vers(&self.cargo_release_num()) + } + /// Returns the `version` string associated with this compiler for Rust /// itself. /// From 71020e38367e490cb172b7040e8a783fc5605327 Mon Sep 17 00:00:00 2001 From: omtcyfz Date: Tue, 21 Mar 2017 19:26:19 +0300 Subject: [PATCH 173/662] Nit: LLVM & Clang latest version is 4.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc9362ca2f0b8..fca7d1cc5bd3c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Read ["Installing Rust"] from [The Book]. 1. Make sure you have installed the dependencies: - * `g++` 4.7 or later or `clang++` 3.x + * `g++` 4.7 or later or `clang++` 3.x or later * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later * `cmake` 3.4.3 or later From 7551e715dc456906a3dac617f2ec20ce929693d9 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Tue, 14 Mar 2017 14:19:59 -0400 Subject: [PATCH 174/662] add test for nested macro def (#31946) Adds a test for issue #31946 which was fixed a while ago. --- .../macro-nested_definition_issue-31946.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/run-pass/macro-nested_definition_issue-31946.rs diff --git a/src/test/run-pass/macro-nested_definition_issue-31946.rs b/src/test/run-pass/macro-nested_definition_issue-31946.rs new file mode 100644 index 0000000000000..84ff2dc4d0d61 --- /dev/null +++ b/src/test/run-pass/macro-nested_definition_issue-31946.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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() { + println!("{}", { + macro_rules! foo { + ($name:expr) => { concat!("hello ", $name) } + } + foo!("rust") + }); +} From a212002db1d9c7ea4d0c21058a96631a52ba7b81 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 21 Mar 2017 01:26:27 -0700 Subject: [PATCH 175/662] Remove unused adt-def insertion by constructor DefIndex --- src/librustc_metadata/decoder.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b4b9966cbe47b..ba6d552e134dc 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -558,7 +558,6 @@ impl<'a, 'tcx> CrateMetadata { EntryKind::Union(_, _) => ty::AdtKind::Union, _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; - let mut ctor_index = None; let variants = if let ty::AdtKind::Enum = kind { item.children .decode(self) @@ -570,8 +569,7 @@ impl<'a, 'tcx> CrateMetadata { }) .collect() } else { - let (variant, struct_ctor) = self.get_variant(&item, item_id, tcx); - ctor_index = struct_ctor; + let (variant, _struct_ctor) = self.get_variant(&item, item_id, tcx); vec![variant] }; let (kind, repr) = match item.kind { @@ -581,13 +579,7 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; - let adt = tcx.alloc_adt_def(did, kind, variants, repr); - if let Some(ctor_index) = ctor_index { - // Make adt definition available through constructor id as well. - tcx.maps.adt_def.borrow_mut().insert(self.local_def_id(ctor_index), adt); - } - - adt + tcx.alloc_adt_def(did, kind, variants, repr) } pub fn get_predicates(&self, From 873248d87d1b376c0411d474c665cc6eeefbb16c Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 21 Mar 2017 02:20:50 -0700 Subject: [PATCH 176/662] Remove unused adt_def access by constructor in typeck/collect --- src/librustc_typeck/collect.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2417745571910..1ed42b842c6fa 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -689,12 +689,6 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let item = match tcx.hir.get(node_id) { NodeItem(item) => item, - - // Make adt definition available through constructor id as well. - NodeStructCtor(_) => { - return tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id)); - } - _ => bug!() }; From a906d9912b32dd8c4d56b7dd61f48fd1ec0ceb63 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Wed, 15 Mar 2017 01:27:43 -0700 Subject: [PATCH 177/662] Correctly get source for metadata crate type; replace `unwrap()` with `expect()` --- src/librustc_metadata/creader.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 5af4db6041115..fcdb968dc0615 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -236,7 +236,8 @@ impl<'a> CrateLoader<'a> { // path (this is a top-level dependency) as we don't want to // implicitly load anything inside the dependency lookup path. let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref()) - .unwrap().1; + .or(source.rmeta.as_ref()) + .expect("No sources for crate").1; if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) { ret = Some(cnum); } From 8a6ef505750152cf9034dfe26858b241221a3400 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Thu, 16 Mar 2017 14:41:08 -0700 Subject: [PATCH 178/662] Regression test for rust-lang/rust#40535 --- src/test/run-make/issue-40535/Makefile | 11 +++++++++++ src/test/run-make/issue-40535/bar.rs | 13 +++++++++++++ src/test/run-make/issue-40535/baz.rs | 11 +++++++++++ src/test/run-make/issue-40535/foo.rs | 14 ++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 src/test/run-make/issue-40535/Makefile create mode 100644 src/test/run-make/issue-40535/bar.rs create mode 100644 src/test/run-make/issue-40535/baz.rs create mode 100644 src/test/run-make/issue-40535/foo.rs diff --git a/src/test/run-make/issue-40535/Makefile b/src/test/run-make/issue-40535/Makefile new file mode 100644 index 0000000000000..7d513a86a7fa5 --- /dev/null +++ b/src/test/run-make/issue-40535/Makefile @@ -0,0 +1,11 @@ +# The ICE occurred in the following situation: +# * `foo` declares `extern crate bar, baz`, depends only on `bar` (forgetting `baz` in `Cargo.toml`) +# * `bar` declares and depends on `extern crate baz` +# * All crates built in metadata-only mode (`cargo check`) +all: + # cc https://github.com/rust-lang/rust/issues/40623 + $(RUSTC) baz.rs --emit=metadata --out-dir=$(TMPDIR) + $(RUSTC) bar.rs --emit=metadata --extern baz=$(TMPDIR)/libbaz.rmeta --out-dir=$(TMPDIR) + $(RUSTC) foo.rs --emit=metadata --extern bar=$(TMPDIR)/libbar.rmeta --out-dir=$(TMPDIR) 2>&1 | \ + grep -vq "unexpectedly panicked" + # ^ Succeeds if it doesn't find the ICE message diff --git a/src/test/run-make/issue-40535/bar.rs b/src/test/run-make/issue-40535/bar.rs new file mode 100644 index 0000000000000..4c22f181975b8 --- /dev/null +++ b/src/test/run-make/issue-40535/bar.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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. + +#![crate_type = "lib"] + +extern crate baz; diff --git a/src/test/run-make/issue-40535/baz.rs b/src/test/run-make/issue-40535/baz.rs new file mode 100644 index 0000000000000..737a918a0398d --- /dev/null +++ b/src/test/run-make/issue-40535/baz.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +#![crate_type = "lib"] diff --git a/src/test/run-make/issue-40535/foo.rs b/src/test/run-make/issue-40535/foo.rs new file mode 100644 index 0000000000000..53a8c8636b148 --- /dev/null +++ b/src/test/run-make/issue-40535/foo.rs @@ -0,0 +1,14 @@ +// Copyright 2017 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. + +#![crate_type = "lib"] + +extern crate bar; +extern crate baz; From ef90d32f07e187d3e1824d980ad01caac5313101 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Mar 2017 08:09:59 -0700 Subject: [PATCH 179/662] rustc: Always emit the `uwtable` attribute on Windows This commit alters the translation layer to unconditionally emit the `uwtable` LLVM attribute on Windows regardless of the `no_landing_pads` setting. Previously I believe we omitted this attribute as an optimization when the `-Cpanic=abort` flag was passed, but this unfortunately caused problems for Gecko. It [was discovered] that there was trouble unwinding through Rust functions due to foreign exceptions such as illegal instructions or otherwise in-practice methods used to abort a process. In testing it looked like the major difference between a working binary and a non-working binary is indeed this `uwtable` attribute, but this PR has unfortunately not been thoroughly tested in terms of compiling Gecko with `-C panic=abort` *and* this PR to see whether it works, so this is still somewhat working on just suspicion. [was discovered]: https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 --- src/librustc_trans/base.rs | 19 +++++++++++- src/test/codegen/panic-abort-windows.rs | 41 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/panic-abort-windows.rs diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 6593b8e68d425..80b563729f5ce 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -583,7 +583,24 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); - if !ccx.sess().no_landing_pads() { + // The `uwtable` attribute according to LLVM is: + // + // This attribute indicates that the ABI being targeted requires that an + // unwind table entry be produced for this function even if we can show + // that no exceptions passes by it. This is normally the case for the + // ELF x86-64 abi, but it can be disabled for some compilation units. + // + // Typically when we're compiling with `-C panic=abort` (which implies this + // `no_landing_pads` check) we don't need `uwtable` because we can't + // generate any exceptions! On Windows, however, exceptions include other + // events such as illegal instructions, segfaults, etc. This means that on + // Windows we end up still needing the `uwtable` attribute even if the `-C + // panic=abort` flag is passed. + // + // You can also find more info on why Windows is whitelisted here in: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 + if !ccx.sess().no_landing_pads() || + ccx.sess().target.target.options.is_like_windows { attributes::emit_uwtable(lldecl, true); } diff --git a/src/test/codegen/panic-abort-windows.rs b/src/test/codegen/panic-abort-windows.rs new file mode 100644 index 0000000000000..2ab15277084ca --- /dev/null +++ b/src/test/codegen/panic-abort-windows.rs @@ -0,0 +1,41 @@ +// 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 + +// This test is for *-windows-msvc only. +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// compile-flags: -C no-prepopulate-passes -C panic=abort -O + +#![crate_type = "lib"] + +// CHECK: Function Attrs: uwtable +// CHECK-NEXT: define void @normal_uwtable() +#[no_mangle] +pub fn normal_uwtable() { +} + +// CHECK: Function Attrs: nounwind uwtable +// CHECK-NEXT: define void @extern_uwtable() +#[no_mangle] +pub extern fn extern_uwtable() { +} From cbb3af1e9c02bcb7c84a05bbcdb250e3e45c453c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 12:04:00 +0100 Subject: [PATCH 180/662] Make the filenames of .stamp files generated by compiletest shorter. Otherwise we run into filename length limitations on some file systems (especially ecryptfs). --- src/tools/compiletest/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 5a97f7e3ee9b5..657739c65b1f5 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -486,11 +486,9 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn } fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf { - let stamp_name = format!("{}-H-{}-T-{}-S-{}.stamp", + let stamp_name = format!("{}-{}.stamp", testpaths.file.file_name().unwrap() .to_str().unwrap(), - config.host, - config.target, config.stage_id); config.build_base.canonicalize() .unwrap_or(config.build_base.clone()) From b5c35c5f7ae255887af085fbd75c06809a3039c1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Mar 2017 09:31:28 -0700 Subject: [PATCH 181/662] travis: Add timestamps to all build messages When debugging why builds are taking so long it's often useful to get the timestamp of all log messages as we're not always timing every tiny step of the build. I wrote a [utility] for prepending a relative timestamp from the start of a process which is now downloaded to the builders and is what we wrap the entire build invocation in. [utility]: https://github.com/alexcrichton/stamp-rs Closes #40577 --- .travis.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b4f558099da51..1dd9114d5348a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,9 @@ matrix: osx_image: xcode8.2 install: &osx_install_sccache > travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-apple-darwin && - chmod +x /usr/local/bin/sccache + chmod +x /usr/local/bin/sccache && + travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && + chmod +x /usr/local/bin/stamp - env: > RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=i686-apple-darwin @@ -118,6 +120,11 @@ env: # AWS_SECRET_ACCESS_KEY=... - secure: "Pixhh0hXDqGCdOyLtGFjli3J2AtDWIpyb2btIrLe956nCBDRutRoMm6rv5DI9sFZN07Mms7VzNNvhc9wCW1y63JAm414d2Co7Ob8kWMZlz9l9t7ACHuktUiis8yr+S4Quq1Vqd6pqi7pf2J++UxC8R/uLeqVrubzr6+X7AbmEFE=" +# Note that this is overridden on OSX builders +install: > + travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-unknown-linux-musl && + chmod +x /usr/local/bin/stamp + before_script: - > echo "#### Disk usage before running script:"; @@ -129,11 +136,11 @@ script: if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then echo skipping, not a full build; elif [ "$TRAVIS_OS_NAME" = "osx" ]; then - travis_retry sh -c 'git submodule deinit -f . && git submodule update --init' && - src/ci/run.sh; + travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && + stamp src/ci/run.sh; else - travis_retry sh -c 'git submodule deinit -f . && git submodule update --init' && - src/ci/docker/run.sh $IMAGE; + travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && + stamp src/ci/docker/run.sh $IMAGE; fi after_success: From 2727866831190406ad13613d55c5846677b7d777 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Mar 2017 09:33:34 -0700 Subject: [PATCH 182/662] travis: Don't enable quiet tests This makes travis problems more difficult to debug, so let's just enable more verbose logging. --- .travis.yml | 9 ++++----- src/ci/run.sh | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1dd9114d5348a..b16957344ae1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -79,9 +79,7 @@ matrix: MACOSX_STD_DEPLOYMENT_TARGET=10.7 os: osx osx_image: xcode8.2 - install: > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-apple-darwin && - chmod +x /usr/local/bin/sccache + install: *osx_install_sccache - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" @@ -122,8 +120,9 @@ env: # Note that this is overridden on OSX builders install: > - travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-unknown-linux-musl && - chmod +x /usr/local/bin/stamp + travis_retry curl -o $HOME/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-unknown-linux-musl && + chmod +x $HOME/stamp && + export PATH=$PATH:$HOME before_script: - > diff --git a/src/ci/run.sh b/src/ci/run.sh index d8b317a46c31e..6c6a49ada15d9 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -24,7 +24,6 @@ ci_dir=`cd $(dirname $0) && pwd` source "$ci_dir/shared.sh" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache" -RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static" From bd862d29d337ff4a082bef9d4adcad4b6a86b7a5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 20 Mar 2017 05:03:10 +0000 Subject: [PATCH 183/662] Fix bug in legacy `#[derive]` processing logic. --- src/librustc_resolve/macros.rs | 8 ++++---- .../auxiliary/custom_derive_plugin.rs | 6 ++++++ src/test/run-pass-fulldeps/issue-40663.rs | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass-fulldeps/issue-40663.rs diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index df3be8fa0f810..f83413095934d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -230,12 +230,12 @@ impl<'a> base::Resolver for Resolver<'a> { attrs.remove(i); } else { let mut tokens = Vec::new(); - for (i, path) in traits.iter().enumerate() { - if i > 0 { + for (j, path) in traits.iter().enumerate() { + if j > 0 { tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into()); } - for (j, segment) in path.segments.iter().enumerate() { - if j > 0 { + for (k, segment) in path.segments.iter().enumerate() { + if k > 0 { tokens.push(TokenTree::Token(path.span, Token::ModSep).into()); } let tok = Token::Ident(segment.identifier); diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index e46e4fb3766d3..16856d3041749 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -34,8 +34,14 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_custom_derive( Symbol::intern("derive_TotalSum"), MultiDecorator(box expand)); + + reg.register_custom_derive( + Symbol::intern("derive_Nothing"), + MultiDecorator(box noop)); } +fn noop(_: &mut ExtCtxt, _: Span, _: &ast::MetaItem, _: &Annotatable, _: &mut FnMut(Annotatable)) {} + fn expand(cx: &mut ExtCtxt, span: Span, mitem: &ast::MetaItem, diff --git a/src/test/run-pass-fulldeps/issue-40663.rs b/src/test/run-pass-fulldeps/issue-40663.rs new file mode 100644 index 0000000000000..d030eab64e564 --- /dev/null +++ b/src/test/run-pass-fulldeps/issue-40663.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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:custom_derive_plugin.rs + +#![feature(plugin, custom_derive)] +#![plugin(custom_derive_plugin)] + +#[derive(Nothing, Nothing, Nothing)] +struct S; + +fn main() {} From a8800bb675397e6aa06ffdac46092d5d03e0cf69 Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 21 Mar 2017 22:18:52 +0100 Subject: [PATCH 184/662] Fix doc error for ExactSizeIterator The code example in the trait documentation of ExactSizeIterator has an incorrect implementation of the len method that does not return the number of times the example iterator 'Counter' will iterate. This may confuse readers of the docs as the example code will compile but doesn't uphold the trait's contract. This is easily fixed by modifying the implementation of len and changing the assert statement to actually assert the correct behaviour. I also slightly modified a code comment to better reflect what the method returns. --- src/libcore/iter/traits.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 3415b0eea9bd0..34f14ef53f893 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -536,9 +536,9 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { /// # } /// # } /// impl ExactSizeIterator for Counter { -/// // We already have the number of iterations, so we can use it directly. +/// // We can easily calculate the remaining number of iterations. /// fn len(&self) -> usize { -/// self.count +/// 5 - self.count /// } /// } /// @@ -546,7 +546,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { /// /// let counter = Counter::new(); /// -/// assert_eq!(0, counter.len()); +/// assert_eq!(5, counter.len()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait ExactSizeIterator: Iterator { From 6acbbc66f7ff4dcf5db92c9c73c84c2b18d63b05 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 17 Mar 2017 23:21:21 +0100 Subject: [PATCH 185/662] Add docs for sort_unstable to unstable book --- src/doc/unstable-book/src/sort-unstable.md | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/doc/unstable-book/src/sort-unstable.md b/src/doc/unstable-book/src/sort-unstable.md index aec39de2c9a73..9effcfc774c77 100644 --- a/src/doc/unstable-book/src/sort-unstable.md +++ b/src/doc/unstable-book/src/sort-unstable.md @@ -6,4 +6,35 @@ The tracking issue for this feature is: [#40585] ------------------------ +The default `sort` method on slices is stable. In other words, it guarantees +that the original order of equal elements is preserved after sorting. The +method has several undesirable characteristics: +1. It allocates a sizable chunk of memory. +2. If you don't need stability, it is not as performant as it could be. + +An alternative is the new `sort_unstable` feature, which includes these +methods for sorting slices: + +1. `sort_unstable` +2. `sort_unstable_by` +3. `sort_unstable_by_key` + +Unstable sorting is generally faster and makes no allocations. The majority +of real-world sorting needs doesn't require stability, so these methods can +very often come in handy. + +Another important difference is that `sort` lives in `libstd` and +`sort_unstable` lives in `libcore`. The reason is that the former makes +allocations and the latter doesn't. + +A simple example: + +```rust +#![feature(sort_unstable)] + +let mut v = [-5, 4, 1, -3, 2]; + +v.sort_unstable(); +assert!(v == [-5, -3, 1, 2, 4]); +``` From d7d4e670ed53883672d8c4458226d91dcc731569 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 22 Mar 2017 00:01:37 +0100 Subject: [PATCH 186/662] Added core::cmp::Reverse for sort_by_key reverse sorting --- src/libcore/cmp.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index cb39796eecd7d..d87615ad9a2c2 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -322,6 +322,40 @@ impl Ordering { } } +/// A helper struct for reverse ordering. +/// +/// This struct is a helper to be used with functions like `Vec::sort_by_key` and +/// can be used to reverse order a part of a key. +/// +/// Example usage: +/// +/// ``` +/// use std::cmp::Reverse; +/// +/// let mut v = vec![1, 2, 3, 4, 5, 6]; +/// v.sort_by_key(|&num| (num >= 3, Reverse(num))); +/// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); +/// ``` +#[derive(PartialEq, Eq, Debug)] +#[stable(feature = "rust1", since = "1.8.0")] +pub struct Reverse(pub T); + +#[stable(feature = "rust1", since = "1.8.0")] +impl PartialOrd for Reverse { + #[inline] + fn partial_cmp(&self, other: &Reverse) -> Option { + other.0.partial_cmp(&self.0) + } +} + +#[stable(feature = "rust1", since = "1.8.0")] +impl Ord for Reverse { + #[inline] + fn cmp(&self, other: &Reverse) -> Ordering { + other.0.cmp(&self.0) + } +} + /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// /// An order is a total order if it is (for all `a`, `b` and `c`): From 9218f9772a6e7b8f55a1dbb6a347ee72d0c6eac9 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 16 Feb 2017 16:59:09 -0500 Subject: [PATCH 187/662] Teach rustc --emit=mir --- src/librustc/session/config.rs | 6 ++++++ src/librustc_driver/driver.rs | 7 +++++++ src/librustc_mir/transform/dump_mir.rs | 14 ++++++++++++++ src/librustc_trans/back/write.rs | 2 ++ 4 files changed, 29 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index d7a765fb82215..a0603c5795247 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -82,6 +82,7 @@ pub enum OutputType { Bitcode, Assembly, LlvmAssembly, + Mir, Metadata, Object, Exe, @@ -96,6 +97,7 @@ impl OutputType { OutputType::Bitcode | OutputType::Assembly | OutputType::LlvmAssembly | + OutputType::Mir | OutputType::Object | OutputType::Metadata => false, } @@ -106,6 +108,7 @@ impl OutputType { OutputType::Bitcode => "llvm-bc", OutputType::Assembly => "asm", OutputType::LlvmAssembly => "llvm-ir", + OutputType::Mir => "mir", OutputType::Object => "obj", OutputType::Metadata => "metadata", OutputType::Exe => "link", @@ -118,6 +121,7 @@ impl OutputType { OutputType::Bitcode => "bc", OutputType::Assembly => "s", OutputType::LlvmAssembly => "ll", + OutputType::Mir => "mir", OutputType::Object => "o", OutputType::Metadata => "rmeta", OutputType::DepInfo => "d", @@ -172,6 +176,7 @@ impl OutputTypes { OutputType::Bitcode | OutputType::Assembly | OutputType::LlvmAssembly | + OutputType::Mir | OutputType::Object | OutputType::Exe => true, OutputType::Metadata | @@ -1370,6 +1375,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let output_type = match parts.next().unwrap() { "asm" => OutputType::Assembly, "llvm-ir" => OutputType::LlvmAssembly, + "mir" => OutputType::Mir, "llvm-bc" => OutputType::Bitcode, "obj" => OutputType::Object, "metadata" => OutputType::Metadata, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2126a5a7c71bd..c1ea2b9ce41a9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -209,6 +209,13 @@ pub fn compile_input(sess: &Session, tcx.print_debug_stats(); } + if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { + if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) { + sess.err(&format!("could not emit MIR: {}", e)); + sess.abort_if_errors(); + } + } + Ok((outputs, trans)) })?? }; diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index f22a71636a98e..5b3113f962b2e 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -11,7 +11,10 @@ //! This pass just dumps MIR at a specified point. use std::fmt; +use std::fs::File; +use std::io; +use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; use rustc::mir::*; use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource}; @@ -70,3 +73,14 @@ impl<'tcx> MirPassHook<'tcx> for DumpMir { } impl<'b> Pass for DumpMir {} + +pub fn emit_mir<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + outputs: &OutputFilenames) + -> io::Result<()> +{ + let path = outputs.path(OutputType::Mir); + let mut f = File::create(&path)?; + mir_util::write_mir_pretty(tcx, tcx.maps.mir.borrow().keys().into_iter(), &mut f)?; + Ok(()) +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 40a69721495b8..377ff34cb7e0d 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -741,6 +741,7 @@ pub fn run_passes(sess: &Session, modules_config.emit_obj = true; metadata_config.emit_obj = true; }, + OutputType::Mir => {} OutputType::DepInfo => {} } } @@ -880,6 +881,7 @@ pub fn run_passes(sess: &Session, user_wants_objects = true; copy_if_one_unit(OutputType::Object, true); } + OutputType::Mir | OutputType::Metadata | OutputType::Exe | OutputType::DepInfo => {} From 4ddedf7246128c7f0dce4a836a0f375f2b12c7c3 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 3 Mar 2017 22:42:49 -0500 Subject: [PATCH 188/662] Add warning about volatility of MIR output --- src/librustc_mir/util/pretty.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 35734dcce2beb..ef2bf6e543420 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -91,6 +91,9 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, -> io::Result<()> where I: Iterator, 'tcx: 'a { + writeln!(w, "// WARNING: This output format is intended for human consumers only")?; + writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; + let mut first = true; for def_id in iter.filter(DefId::is_local) { let mir = &tcx.item_mir(def_id); From 8e352f7d866f46e09746d7f8557818984a1f3854 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 21 Mar 2017 20:15:55 -0500 Subject: [PATCH 189/662] E0090: Add explanation for error message See #32777 --- src/librustc_typeck/diagnostics.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 644e323a8dbf2..2d24b1fb4f20a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1223,6 +1223,18 @@ fn main() { ``` "##, +E0090: r##" +The wrong number of lifetimes were supplied. For example: + +```compile_fail,E0090 +fn foo<'a: 'b, 'b: 'a>() {} + +fn main() { + foo::<'static>(); // error, expected 2 lifetime parameters +} +``` +"##, + E0091: r##" You gave an unnecessary type parameter in a type alias. Erroneous code example: @@ -4120,7 +4132,6 @@ register_diagnostics! { // E0068, // E0085, // E0086, - E0090, E0103, // @GuillaumeGomez: I was unable to get this error, try your best! E0104, // E0123, From 6ae22346b83406bce360b80d648920eac9874bae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Mar 2017 07:35:35 -0700 Subject: [PATCH 190/662] appveyor: Use Ninja to build LLVM on MinGW I have a suspicion that MinGW's make is the cause of #40546 rather than anything else, but that's purely a suspicion without any facts to back it up. In any case we'll eventually be moving the MSVC build over to Ninja in order to leverage sccache regardless, so this commit simply jumpstarts that process by downloading Ninja for use by MinGW anyway. I'm not sure if this closes #40546 for real, but this is my current best shot at closing it out, so... Closes #40546 --- appveyor.yml | 17 ++++++++++++----- src/bootstrap/config.rs | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 499f7d602e368..0e7ebf12a2a91 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,14 +43,14 @@ environment: # *not* use debug assertions and llvm assertions. This is because they take # too long on appveyor and this is tested by rustbuild below. - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z MINGW_DIR: mingw64 @@ -68,7 +68,7 @@ environment: SCRIPT: python x.py dist DEPLOY: 1 - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z @@ -76,7 +76,7 @@ environment: DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z MINGW_DIR: mingw64 @@ -116,9 +116,16 @@ install: # Download and install sccache - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-pc-windows-msvc - - mv 2017-03-16-sccache-x86_64-pc-windows-msvc sccache + - mv 2017-03-16-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% + # Download and install ninja + # + # Note that this is originally from the github releases patch of Ninja + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-15-ninja-win.zip + - 7z x 2017-03-15-ninja-win.zip + # - set PATH=%PATH%;%CD% -- this already happens above for sccache + # Install InnoSetup to get `iscc` used to produce installers - appveyor-retry choco install -y InnoSetup - set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH% diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index b1d1d79b9eaa3..52ebf401aefd6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,7 +23,7 @@ use std::process; use num_cpus; use rustc_serialize::Decodable; use toml::{Parser, Decoder, Value}; -use util::push_exe_path; +use util::{exe, push_exe_path}; /// Global configuration for the entire build and/or bootstrap. /// @@ -584,10 +584,10 @@ impl Config { self.python = Some(path); } "CFG_ENABLE_CCACHE" if value == "1" => { - self.ccache = Some("ccache".to_string()); + self.ccache = Some(exe("ccache", &self.build)); } "CFG_ENABLE_SCCACHE" if value == "1" => { - self.ccache = Some("sccache".to_string()); + self.ccache = Some(exe("sccache", &self.build)); } "CFG_CONFIGURE_ARGS" if value.len() > 0 => { self.configure_args = value.split_whitespace() From e2b5a8cf57f83d6e658f36f0cdafdd59896649b8 Mon Sep 17 00:00:00 2001 From: Cldfire Date: Tue, 21 Mar 2017 23:40:41 -0400 Subject: [PATCH 191/662] Remove duplicate style classes --- src/librustdoc/html/static/styles/main.css | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index 40561597e93e0..74ec3691b3860 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -45,14 +45,6 @@ pre { background-color: #fff; } -.sidebar { - background-color: #F1F1F1; -} - -.sidebar .current { - background-color: #fff; -} - .sidebar .location { border-color: #000; background-color: #fff; From 8ea0f18d9a3bdf001be8d668818b8291dd2b37df Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Wed, 22 Mar 2017 00:07:12 -0500 Subject: [PATCH 192/662] E0090: Expand error message explanation --- src/librustc_typeck/diagnostics.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 2d24b1fb4f20a..0136faef28d8c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1224,7 +1224,7 @@ fn main() { "##, E0090: r##" -The wrong number of lifetimes were supplied. For example: +You gave too few lifetime parameters. Example: ```compile_fail,E0090 fn foo<'a: 'b, 'b: 'a>() {} @@ -1233,6 +1233,16 @@ fn main() { foo::<'static>(); // error, expected 2 lifetime parameters } ``` + +Please check you give the right number of lifetime parameters. Example: + +``` +fn foo<'a: 'b, 'b: 'a>() {} + +fn main() { + foo::<'static, 'static>(); +} +``` "##, E0091: r##" From dabff151426d0cf6f8a779c15be459f7bd457a4c Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 22 Mar 2017 09:04:42 +0100 Subject: [PATCH 193/662] Fix the test for cmp::Reverse --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d87615ad9a2c2..d787a0833c7ab 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -333,7 +333,7 @@ impl Ordering { /// use std::cmp::Reverse; /// /// let mut v = vec![1, 2, 3, 4, 5, 6]; -/// v.sort_by_key(|&num| (num >= 3, Reverse(num))); +/// v.sort_by_key(|&num| (num > 3, Reverse(num))); /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` #[derive(PartialEq, Eq, Debug)] From 439bf132d93b35221c3891f85606e22b2071b7c2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 15:24:30 +0100 Subject: [PATCH 194/662] Support more kinds of Regions in TypeIdHasher. --- src/librustc/ty/util.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1d816d342c4fd..03db15263b62f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -509,18 +509,19 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> } fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + self.hash_discriminant_u8(r); match *r { - ty::ReErased => { - self.hash::(0); - } + ty::ReErased | + ty::ReStatic | + ty::ReEmpty => {} ty::ReLateBound(db, ty::BrAnon(i)) => { - assert!(db.depth > 0); - self.hash::(db.depth); + self.hash(db.depth); self.hash(i); } - ty::ReStatic | - ty::ReEmpty | - ty::ReEarlyBound(..) | + ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { + self.hash(index); + self.hash(name.as_str()); + } ty::ReLateBound(..) | ty::ReFree(..) | ty::ReScope(..) | From bb243057427ab02f8d7b27b27c3311f6a0ac0726 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 15:22:24 +0100 Subject: [PATCH 195/662] Add some missing method impls to MIR region eraser. --- src/librustc_mir/transform/erase_regions.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index cebd9dd9668e3..07822a5a097ae 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -13,7 +13,7 @@ //! care erasing regions all over the place. use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt}; +use rustc::ty::{Ty, TyCtxt, ReErased, ClosureSubsts}; use rustc::mir::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, MirSource, Pass}; @@ -39,6 +39,23 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) { *substs = self.tcx.erase_regions(&{*substs}); } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + match *rvalue { + Rvalue::Ref(ref mut r, _, _) => { + *r = self.tcx.mk_region(ReErased); + } + _ => { + /* only the above variant contains regions */ + } + } + self.super_rvalue(rvalue, location); + } + + fn visit_closure_substs(&mut self, + substs: &mut ClosureSubsts<'tcx>) { + *substs = self.tcx.erase_regions(substs); + } } pub struct EraseRegions; From 8c00e63f3f104ff6bb9f9d5ded251b6a59ca6f4b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 16:35:06 +0100 Subject: [PATCH 196/662] Move Fingerprint to rustc::ich::Fingerprint. --- src/{librustc_incremental => librustc}/ich/fingerprint.rs | 0 src/{librustc_incremental => librustc}/ich/mod.rs | 3 ++- src/librustc/lib.rs | 1 + src/librustc_driver/driver.rs | 2 +- src/librustc_incremental/calculate_svh/mod.rs | 2 +- src/librustc_incremental/lib.rs | 1 - src/librustc_incremental/persist/data.rs | 2 +- src/librustc_incremental/persist/dirty_clean.rs | 2 +- src/librustc_incremental/persist/hash.rs | 2 +- src/librustc_incremental/persist/load.rs | 2 +- src/librustc_incremental/persist/preds/mod.rs | 2 +- src/librustc_incremental/persist/save.rs | 2 +- 12 files changed, 11 insertions(+), 10 deletions(-) rename src/{librustc_incremental => librustc}/ich/fingerprint.rs (100%) rename src/{librustc_incremental => librustc}/ich/mod.rs (87%) diff --git a/src/librustc_incremental/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs similarity index 100% rename from src/librustc_incremental/ich/fingerprint.rs rename to src/librustc/ich/fingerprint.rs diff --git a/src/librustc_incremental/ich/mod.rs b/src/librustc/ich/mod.rs similarity index 87% rename from src/librustc_incremental/ich/mod.rs rename to src/librustc/ich/mod.rs index 8edd04322d7f6..b634fb3491463 100644 --- a/src/librustc_incremental/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -11,3 +11,4 @@ pub use self::fingerprint::Fingerprint; mod fingerprint; + diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a007c9d2c43a9..c1c945d4e6063 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -72,6 +72,7 @@ pub mod diagnostics; pub mod cfg; pub mod dep_graph; pub mod hir; +pub mod ich; pub mod infer; pub mod lint; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2126a5a7c71bd..ecf5664438176 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -10,6 +10,7 @@ use rustc::hir::{self, map as hir_map}; use rustc::hir::lowering::lower_crate; +use rustc::ich::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; use rustc_mir as mir; use rustc::session::{Session, CompileResult, compile_result_from_err_count}; @@ -25,7 +26,6 @@ use rustc::util::nodemap::NodeSet; use rustc::util::fs::rename_or_copy_remove; use rustc_borrowck as borrowck; use rustc_incremental::{self, IncrementalHashesMap}; -use rustc_incremental::ich::Fingerprint; use rustc_resolve::{MakeGlobMap, Resolver}; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index b9e6426dc01d8..99279d686ab4e 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,9 +35,9 @@ use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; +use rustc::ich::Fingerprint; use rustc::ty::TyCtxt; use rustc_data_structures::stable_hasher::StableHasher; -use ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; use rustc::session::config::DebugInfoLevel::NoDebugInfo; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 0a8719c125329..40e9cb97d66d9 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -46,7 +46,6 @@ const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; mod assert_dep_graph; mod calculate_svh; mod persist; -pub mod ich; pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::compute_incremental_hashes_map; diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 673f1ae10843c..d900907395656 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -12,9 +12,9 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; +use rustc::ich::Fingerprint; use std::sync::Arc; use rustc_data_structures::fx::FxHashMap; -use ich::Fingerprint; use super::directory::DefPathIndex; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 929249df0b173..cd5c8900092e9 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -47,11 +47,11 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit; +use rustc::ich::Fingerprint; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax_pos::Span; use rustc::ty::TyCtxt; -use ich::Fingerprint; use {ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA}; diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 799cb6c5e3d8c..9d8ff57e03bcc 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -11,6 +11,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::{CrateNum, DefId}; use rustc::hir::svh::Svh; +use rustc::ich::Fingerprint; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::flock; @@ -18,7 +19,6 @@ use rustc_serialize::Decodable; use rustc_serialize::opaque::Decoder; use IncrementalHashesMap; -use ich::Fingerprint; use super::data::*; use super::fs::*; use super::file_format; diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 2789250649674..ed2e2e72ee79f 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -13,6 +13,7 @@ use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; +use rustc::ich::Fingerprint; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; @@ -22,7 +23,6 @@ use std::path::{Path}; use std::sync::Arc; use IncrementalHashesMap; -use ich::Fingerprint; use super::data::*; use super::directory::*; use super::dirty_clean; diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index f6a37c7a12265..fe8cf72996e15 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -10,11 +10,11 @@ use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::hir::def_id::DefId; +use rustc::ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::{Graph, NodeIndex}; use super::hash::*; -use ich::Fingerprint; mod compress; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index dfa6bf6bbb5e7..2e5186493370b 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -11,6 +11,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; +use rustc::ich::Fingerprint; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; @@ -23,7 +24,6 @@ use std::fs::{self, File}; use std::path::PathBuf; use IncrementalHashesMap; -use ich::Fingerprint; use super::data::*; use super::directory::*; use super::hash::*; From 1445ed272e9bc498a00365eb3bb353b944994c24 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 16:45:48 +0100 Subject: [PATCH 197/662] Move DefPathHashes to rustc::ich --- .../calculate_svh => librustc/ich}/def_path_hash.rs | 6 +++--- src/librustc/ich/mod.rs | 3 ++- src/librustc_incremental/calculate_svh/mod.rs | 4 +--- src/librustc_incremental/calculate_svh/svh_visitor.rs | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) rename src/{librustc_incremental/calculate_svh => librustc/ich}/def_path_hash.rs (92%) diff --git a/src/librustc_incremental/calculate_svh/def_path_hash.rs b/src/librustc/ich/def_path_hash.rs similarity index 92% rename from src/librustc_incremental/calculate_svh/def_path_hash.rs rename to src/librustc/ich/def_path_hash.rs index 8aa134ba3bfd0..03051dc003420 100644 --- a/src/librustc_incremental/calculate_svh/def_path_hash.rs +++ b/src/librustc/ich/def_path_hash.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir::def_id::DefId; -use rustc::ty::TyCtxt; -use rustc::util::nodemap::DefIdMap; +use hir::def_id::DefId; +use ty::TyCtxt; +use util::nodemap::DefIdMap; pub struct DefPathHashes<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index b634fb3491463..935117d4ca419 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -9,6 +9,7 @@ // except according to those terms. pub use self::fingerprint::Fingerprint; +pub use self::def_path_hash::DefPathHashes; mod fingerprint; - +mod def_path_hash; diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 99279d686ab4e..a9676fb8ccf69 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,18 +35,16 @@ use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::ich::Fingerprint; +use rustc::ich::{Fingerprint, DefPathHashes}; use rustc::ty::TyCtxt; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; use rustc::session::config::DebugInfoLevel::NoDebugInfo; -use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; use self::caching_codemap_view::CachingCodemapView; -mod def_path_hash; mod svh_visitor; mod caching_codemap_view; diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index fac49b29598aa..e97e2016098b5 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -26,10 +26,10 @@ use rustc::hir::*; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self as visit, Visitor}; +use rustc::ich::DefPathHashes; use rustc::ty::TyCtxt; use std::hash::{Hash, Hasher}; -use super::def_path_hash::DefPathHashes; use super::caching_codemap_view::CachingCodemapView; use super::IchHasher; From 9af97e7ff29941f5ced10b7f70f1a679f8fc7d1e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 17:00:31 +0100 Subject: [PATCH 198/662] Move CachingCodemapView to rustc::ich. --- .../calculate_svh => librustc/ich}/caching_codemap_view.rs | 2 +- src/librustc/ich/mod.rs | 2 ++ src/librustc_incremental/calculate_svh/mod.rs | 4 +--- src/librustc_incremental/calculate_svh/svh_visitor.rs | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) rename src/{librustc_incremental/calculate_svh => librustc/ich}/caching_codemap_view.rs (99%) diff --git a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs similarity index 99% rename from src/librustc_incremental/calculate_svh/caching_codemap_view.rs rename to src/librustc/ich/caching_codemap_view.rs index ad9c48420e217..a71251eedf5d0 100644 --- a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::ty::TyCtxt; +use ty::TyCtxt; use std::rc::Rc; use syntax::codemap::CodeMap; use syntax_pos::{BytePos, FileMap}; diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 935117d4ca419..b8cf52ec672b5 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -10,6 +10,8 @@ pub use self::fingerprint::Fingerprint; pub use self::def_path_hash::DefPathHashes; +pub use self::caching_codemap_view::CachingCodemapView; mod fingerprint; mod def_path_hash; +mod caching_codemap_view; diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index a9676fb8ccf69..c9496a4deb8eb 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,7 +35,7 @@ use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::ich::{Fingerprint, DefPathHashes}; +use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView}; use rustc::ty::TyCtxt; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::fx::FxHashMap; @@ -43,10 +43,8 @@ use rustc::util::common::record_time; use rustc::session::config::DebugInfoLevel::NoDebugInfo; use self::svh_visitor::StrictVersionHashVisitor; -use self::caching_codemap_view::CachingCodemapView; mod svh_visitor; -mod caching_codemap_view; pub type IchHasher = StableHasher; diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index e97e2016098b5..3b6e2748e97cd 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -26,11 +26,10 @@ use rustc::hir::*; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self as visit, Visitor}; -use rustc::ich::DefPathHashes; +use rustc::ich::{DefPathHashes, CachingCodemapView}; use rustc::ty::TyCtxt; use std::hash::{Hash, Hasher}; -use super::caching_codemap_view::CachingCodemapView; use super::IchHasher; const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ From 03b8091d103873386688f171fc48fbe0a8618810 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Mar 2017 18:09:59 +0100 Subject: [PATCH 199/662] Move some constants to rustc::ich. --- src/librustc/ich/mod.rs | 17 +++++++++++++++++ src/librustc_incremental/assert_dep_graph.rs | 2 +- .../calculate_svh/svh_visitor.rs | 12 +----------- src/librustc_incremental/lib.rs | 7 ------- src/librustc_incremental/persist/dirty_clean.rs | 5 ++--- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index b8cf52ec672b5..209953f3c686b 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -15,3 +15,20 @@ pub use self::caching_codemap_view::CachingCodemapView; mod fingerprint; mod def_path_hash; mod caching_codemap_view; + +pub const ATTR_DIRTY: &'static str = "rustc_dirty"; +pub const ATTR_CLEAN: &'static str = "rustc_clean"; +pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; +pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean"; +pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; +pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; + +pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ + "cfg", + ATTR_IF_THIS_CHANGED, + ATTR_THEN_THIS_WOULD_NEED, + ATTR_DIRTY, + ATTR_CLEAN, + ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA +]; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 287ee7dd13e4e..897ca0f295761 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -52,13 +52,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ich::{ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED}; use graphviz::IntoCow; use std::env; use std::fs::File; use std::io::Write; use syntax::ast; use syntax_pos::Span; -use {ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED}; pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 3b6e2748e97cd..210803c3f329c 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -26,22 +26,12 @@ use rustc::hir::*; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self as visit, Visitor}; -use rustc::ich::{DefPathHashes, CachingCodemapView}; +use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES}; use rustc::ty::TyCtxt; use std::hash::{Hash, Hasher}; use super::IchHasher; -const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ - "cfg", - ::ATTR_IF_THIS_CHANGED, - ::ATTR_THEN_THIS_WOULD_NEED, - ::ATTR_DIRTY, - ::ATTR_CLEAN, - ::ATTR_DIRTY_METADATA, - ::ATTR_CLEAN_METADATA -]; - pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, pub st: &'a mut IchHasher, diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 40e9cb97d66d9..3b61cc1464a91 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -36,13 +36,6 @@ extern crate serialize as rustc_serialize; extern crate syntax; extern crate syntax_pos; -const ATTR_DIRTY: &'static str = "rustc_dirty"; -const ATTR_CLEAN: &'static str = "rustc_clean"; -const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; -const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean"; -const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; -const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; - mod assert_dep_graph; mod calculate_svh; mod persist; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index cd5c8900092e9..d931f64d579e1 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -47,14 +47,13 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit; -use rustc::ich::Fingerprint; +use rustc::ich::{Fingerprint, ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA}; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax_pos::Span; use rustc::ty::TyCtxt; -use {ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA}; - const LABEL: &'static str = "label"; const CFG: &'static str = "cfg"; From 45deab4a2c5d0674cac0fd260da4b8c0d46f7aa2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 21 Mar 2017 10:42:51 +0100 Subject: [PATCH 200/662] Address review comments. --- src/librustc/ty/util.rs | 4 +++- src/librustc_mir/transform/erase_regions.rs | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 03db15263b62f..1c1e0d91cb4d6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -513,7 +513,9 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> match *r { ty::ReErased | ty::ReStatic | - ty::ReEmpty => {} + ty::ReEmpty => { + // No variant fields to hash for these ... + } ty::ReLateBound(db, ty::BrAnon(i)) => { self.hash(db.depth); self.hash(i); diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 07822a5a097ae..0f869e7ed02ff 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -45,8 +45,17 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { Rvalue::Ref(ref mut r, _, _) => { *r = self.tcx.mk_region(ReErased); } - _ => { - /* only the above variant contains regions */ + Rvalue::Use(..) | + Rvalue::Repeat(..) | + Rvalue::Len(..) | + Rvalue::Cast(..) | + Rvalue::BinaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::UnaryOp(..) | + Rvalue::Discriminant(..) | + Rvalue::Box(..) | + Rvalue::Aggregate(..) => { + // These variants don't contain regions. } } self.super_rvalue(rvalue, location); From 9e772b0092b7eff566d8d7a450ddc783ba69f119 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 22 Mar 2017 11:51:03 +0300 Subject: [PATCH 201/662] Update the book submodule and fix tidy --- src/doc/book | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book b/src/doc/book index e6d6caab41471..9bd223ca406b1 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit e6d6caab41471f7115a621029bd428a812c5260e +Subproject commit 9bd223ca406b1170a24942d6474f9e8a56f4a420 From dae66e000a974dd3bea7ae10b8827a5ece2b941e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 17 Mar 2017 22:36:21 -0700 Subject: [PATCH 202/662] Specialize Vec::from_iter for vec::IntoIter It's fairly common to expose an API which takes an `IntoIterator` and immediately collects that into a vector. It's also common to buffer a bunch of items into a vector and then pass that into one of these APIs. If the iterator hasn't been advanced, we can make this `from_iter` simply reassemble the original `Vec` with no actual iteration or reallocation. --- src/libcollections/vec.rs | 29 +++++++++++++++++++++++++---- src/libcollectionstest/vec.rs | 16 ++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 7b408af13aa2f..56b60a3e00341 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1563,7 +1563,7 @@ impl ops::DerefMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()) } } @@ -1631,7 +1631,7 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - self.spec_extend(iter.into_iter()) + >::spec_extend(self, iter.into_iter()) } } @@ -1662,7 +1662,7 @@ impl SpecExtend for Vec vector } }; - vector.spec_extend(iterator); + as SpecExtend>::spec_extend(&mut vector, iterator); vector } @@ -1674,7 +1674,7 @@ impl SpecExtend for Vec impl SpecExtend for Vec where I: TrustedLen, { - fn from_iter(iterator: I) -> Self { + default fn from_iter(iterator: I) -> Self { let mut vector = Vec::new(); vector.spec_extend(iterator); vector @@ -1706,6 +1706,27 @@ impl SpecExtend for Vec } } +impl SpecExtend> for Vec { + fn from_iter(iterator: IntoIter) -> Self { + // A common case is passing a vector into a function which immediately + // re-collects into a vector. We can short circuit this if the IntoIter + // has not been advanced at all. + if *iterator.buf == iterator.ptr as *mut T { + unsafe { + let vec = Vec::from_raw_parts(*iterator.buf as *mut T, + iterator.len(), + iterator.cap); + mem::forget(iterator); + vec + } + } else { + let mut vector = Vec::new(); + vector.spec_extend(iterator); + vector + } + } +} + impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 06d70800d3925..63df0eb730509 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -680,3 +680,19 @@ fn test_placement_panic() { let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); })); assert_eq!(vec.len(), 3); } + +#[test] +fn from_into_inner() { + let vec = vec![1, 2, 3]; + let ptr = vec.as_ptr(); + let vec = vec.into_iter().collect::>(); + assert_eq!(vec, [1, 2, 3]); + assert_eq!(vec.as_ptr(), ptr); + + let ptr = &vec[1] as *const _; + let mut it = vec.into_iter(); + it.next().unwrap(); + let vec = it.collect::>(); + assert_eq!(vec, [2, 3]); + assert!(ptr != vec.as_ptr()); +} From 1ae1a19ba6156479969f493c8e05871539e69b52 Mon Sep 17 00:00:00 2001 From: Adam Ransom Date: Tue, 21 Mar 2017 21:35:57 +0900 Subject: [PATCH 203/662] Refactor checking if a `Lifetime` is static Simply move the test for `keywords::StaticLifetime` into the `Lifetime` impl, to match how elision is checked. --- src/librustc/hir/mod.rs | 4 ++++ src/librustc/middle/resolve_lifetime.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index edcfcffaa03a4..8239fd7d13c11 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -100,6 +100,10 @@ impl Lifetime { pub fn is_elided(&self) -> bool { self.name == keywords::Invalid.name() } + + pub fn is_static(&self) -> bool { + self.name == keywords::StaticLifetime.name() + } } /// A lifetime definition, eg `'a: 'b+'c+'d` diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 37749816eb153..10ee760a6a615 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -434,7 +434,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.resolve_elided_lifetimes(slice::ref_slice(lifetime_ref)); return; } - if lifetime_ref.name == keywords::StaticLifetime.name() { + if lifetime_ref.is_static() { self.insert_lifetime(lifetime_ref, Region::Static); return; } @@ -1434,7 +1434,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let lifetime_i = &lifetimes[i]; for lifetime in lifetimes { - if lifetime.lifetime.name == keywords::StaticLifetime.name() { + if lifetime.lifetime.is_static() { let lifetime = lifetime.lifetime; let mut err = struct_span_err!(self.sess, lifetime.span, E0262, "invalid lifetime parameter name: `{}`", lifetime.name); From d005d917783b8f753b4ee2f79f03e2212e519d01 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 22 Mar 2017 14:16:41 +0100 Subject: [PATCH 204/662] Improved bounds for cmp::Reverse --- src/libcore/cmp.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d787a0833c7ab..751932a6105ae 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -337,19 +337,19 @@ impl Ordering { /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` #[derive(PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.8.0")] -pub struct Reverse(pub T); +#[stable(feature = "rust1", since = "1.18.0")] +pub struct Reverse(pub T); -#[stable(feature = "rust1", since = "1.8.0")] -impl PartialOrd for Reverse { +#[stable(feature = "rust1", since = "1.18.0")] +impl PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) } } -#[stable(feature = "rust1", since = "1.8.0")] -impl Ord for Reverse { +#[stable(feature = "rust1", since = "1.18.0")] +impl Ord for Reverse { #[inline] fn cmp(&self, other: &Reverse) -> Ordering { other.0.cmp(&self.0) From 9e0589a52b73e254460f90beb010f380b09ff0ba Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 14 Mar 2017 15:49:28 +0100 Subject: [PATCH 205/662] Add resize() method to IndexVec. --- src/librustc_data_structures/indexed_vec.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 3f478d7c165d1..62c430dda327f 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -189,6 +189,13 @@ impl IndexVec { } } +impl IndexVec { + #[inline] + pub fn resize(&mut self, new_len: usize, value: T) { + self.raw.resize(new_len, value) + } +} + impl Index for IndexVec { type Output = T; From 559127b4517229115397404f20167bc7b702d3d6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 14 Mar 2017 15:50:04 +0100 Subject: [PATCH 206/662] Implement indexed_vec::Idx for ast::NodeId --- src/libsyntax/ast.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4347046b6b808..3dd4bdbd14ddb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -23,6 +23,7 @@ use abi::Abi; use ext::hygiene::SyntaxContext; use print::pprust; use ptr::P; +use rustc_data_structures::indexed_vec; use symbol::{Symbol, keywords}; use tokenstream::{ThinTokenStream, TokenStream}; @@ -275,6 +276,16 @@ impl serialize::UseSpecializedDecodable for NodeId { } } +impl indexed_vec::Idx for NodeId { + fn new(idx: usize) -> Self { + NodeId::new(idx) + } + + fn index(self) -> usize { + self.as_usize() + } +} + /// Node id used to represent the root of the crate. pub const CRATE_NODE_ID: NodeId = NodeId(0); From 89ddd717caf7084c9fe292ceaa46828c65573097 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 12:24:42 -0400 Subject: [PATCH 207/662] Revert "Auto merge of #39485 - canndrew:inference-fix-39297, r=nikomatsakis" This reverts commit dc0bb3f2839c13ab42feacd423f728fbfd2f2f7a, reversing changes made to e879aa43ef63962f8e4d797292194a9f40a22a13. This is a temporary step intended to fix regressions. A more comprehensive fix for type inference and dead-code is in the works. --- src/librustc_typeck/check/mod.rs | 11 +++++++++++ .../issue-10176.rs} | 8 ++++---- src/test/compile-fail/issue-5500.rs | 17 +++++++++++++++++ src/test/run-pass/issue-15763.rs | 7 +++---- src/test/run-pass/project-defer-unification.rs | 4 +--- 5 files changed, 36 insertions(+), 11 deletions(-) rename src/test/{run-pass/inference-changes-39485.rs => compile-fail/issue-10176.rs} (82%) create mode 100644 src/test/compile-fail/issue-5500.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c857388106d5a..9c62fd486d45a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4099,6 +4099,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if self.diverges.get().always() { + if let ExpectHasType(ety) = expected { + // Avoid forcing a type (only `!` for now) in unreachable code. + // FIXME(aburka) do we need this special case? and should it be is_uninhabited? + if !ety.is_never() { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); + } + } + } + ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); } else if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { diff --git a/src/test/run-pass/inference-changes-39485.rs b/src/test/compile-fail/issue-10176.rs similarity index 82% rename from src/test/run-pass/inference-changes-39485.rs rename to src/test/compile-fail/issue-10176.rs index 193c66b2a2afd..434b795ff31f5 100644 --- a/src/test/run-pass/inference-changes-39485.rs +++ b/src/test/compile-fail/issue-10176.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn g() { - &panic!() -} - fn f() -> isize { (return 1, return 2) +//~^ ERROR mismatched types +//~| expected type `isize` +//~| found type `(_, _)` +//~| expected isize, found tuple } fn main() {} diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs new file mode 100644 index 0000000000000..1cbb7588e17df --- /dev/null +++ b/src/test/compile-fail/issue-5500.rs @@ -0,0 +1,17 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + &panic!() + //~^ ERROR mismatched types + //~| expected type `()` + //~| found type `&_` + //~| expected (), found reference +} diff --git a/src/test/run-pass/issue-15763.rs b/src/test/run-pass/issue-15763.rs index f77888c29554d..0baaaac267685 100644 --- a/src/test/run-pass/issue-15763.rs +++ b/src/test/run-pass/issue-15763.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_features)] -#![allow(unreachable_code)] +#![allow(unknown_features)] #![feature(box_syntax)] #[derive(PartialEq, Debug)] @@ -29,14 +28,14 @@ struct Foo { } fn foo() -> Result { - return Ok::(Foo { + return Ok(Foo { x: Bar { x: 22 }, a: return Err(32) }); } fn baz() -> Result { - Ok::(Foo { + Ok(Foo { x: Bar { x: 22 }, a: return Err(32) }) diff --git a/src/test/run-pass/project-defer-unification.rs b/src/test/run-pass/project-defer-unification.rs index 8e008c639b30e..9a6ea2272fea7 100644 --- a/src/test/run-pass/project-defer-unification.rs +++ b/src/test/run-pass/project-defer-unification.rs @@ -11,8 +11,6 @@ // A regression test extracted from image-0.3.11. The point of // failure was in `index_colors` below. -#![allow(unused)] - use std::ops::{Deref, DerefMut}; #[derive(Copy, Clone)] @@ -94,7 +92,7 @@ pub fn index_colors(image: &ImageBuffer>) -> ImageBuffer, Vec> where Pix: Pixel + 'static, { - let mut indices: ImageBuffer, Vec> = loop { }; + let mut indices: ImageBuffer<_,Vec<_>> = loop { }; for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) { // failured occurred here ^^ because we were requiring that we // could project Pixel or Subpixel from `T_indices` (type of From 0f1eb8a70f0f877eba4b55151949df8861377c65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 12:28:34 -0400 Subject: [PATCH 208/662] add regression test for #39984 Fixes #39984 --- src/test/run-pass/issue-39984.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/run-pass/issue-39984.rs diff --git a/src/test/run-pass/issue-39984.rs b/src/test/run-pass/issue-39984.rs new file mode 100644 index 0000000000000..a0019e7215c98 --- /dev/null +++ b/src/test/run-pass/issue-39984.rs @@ -0,0 +1,21 @@ +// 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. + +// Regression test for issue #39984. +// +// The key here is that the error type of the `Ok` call ought to be +// constrained to `String`, even though it is dead-code. + +fn main() {} + +fn t() -> Result<(), String> { + return Err("".into()); + Ok(()) +} From bc259ee844f608599293c83d96de353005681cca Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 14 Mar 2017 15:50:40 +0100 Subject: [PATCH 209/662] Introduce HirId, a replacement for NodeId after lowering to HIR. HirId has a more stable representation than NodeId, meaning that modifications to one item don't influence (part of) the IDs within other items. The other part is a DefIndex for which there already is a way of stable hashing and persistence. This commit introduces the HirId type and generates a HirId for every NodeId during HIR lowering, but the resulting values are not yet used anywhere, except in consistency checks. --- src/librustc/hir/lowering.rs | 1773 ++++++++++------- src/librustc/hir/map/definitions.rs | 30 + src/librustc/hir/map/hir_id_validator.rs | 184 ++ src/librustc/hir/map/mod.rs | 9 +- src/librustc/hir/mod.rs | 61 +- src/libsyntax/ext/placeholders.rs | 14 +- ...n-bounds-on-objects-and-type-parameters.rs | 2 +- 7 files changed, 1286 insertions(+), 787 deletions(-) create mode 100644 src/librustc/hir/map/hir_id_validator.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 81591a5650f07..22ca0e421be85 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -43,12 +43,14 @@ use hir; use hir::map::{Definitions, DefKey}; use hir::map::definitions::DefPathData; -use hir::def_id::{DefIndex, DefId}; +use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX}; use hir::def::{Def, PathResolution}; +use rustc_data_structures::indexed_vec::IndexVec; use session::Session; use util::nodemap::{DefIdMap, NodeMap}; use std::collections::BTreeMap; +use std::fmt::Debug; use std::iter; use std::mem; @@ -63,6 +65,8 @@ use syntax::util::small_vector::SmallVector; use syntax::visit::{self, Visitor}; use syntax_pos::Span; +const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; + pub struct LoweringContext<'a> { crate_root: Option<&'static str>, // Use to assign ids to hir nodes that do not directly correspond to an ast node @@ -89,6 +93,10 @@ pub struct LoweringContext<'a> { is_in_loop_condition: bool, type_def_lifetime_params: DefIdMap, + + current_hir_id_owner: Vec<(DefIndex, u32)>, + item_local_id_counters: NodeMap, + node_id_to_hir_id: IndexVec, } pub trait Resolver { @@ -128,6 +136,9 @@ pub fn lower_crate(sess: &Session, loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), + current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], + item_local_id_counters: NodeMap(), + node_id_to_hir_id: IndexVec::new(), }.lower_crate(krate) } @@ -152,6 +163,8 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { + self.lctx.allocate_hir_id_counter(item.id, item); + match item.node { ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | @@ -166,6 +179,16 @@ impl<'a> LoweringContext<'a> { } visit::walk_item(self, item); } + + fn visit_trait_item(&mut self, item: &'lcx TraitItem) { + self.lctx.allocate_hir_id_counter(item.id, item); + visit::walk_trait_item(self, item); + } + + fn visit_impl_item(&mut self, item: &'lcx ImplItem) { + self.lctx.allocate_hir_id_counter(item.id, item); + visit::walk_impl_item(self, item); + } } struct ItemLowerer<'lcx, 'interner: 'lcx> { @@ -174,27 +197,43 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { - if let Some(hir_item) = self.lctx.lower_item(item) { - self.lctx.items.insert(item.id, hir_item); + let mut item_lowered = true; + self.lctx.with_hir_id_owner(item.id, |lctx| { + if let Some(hir_item) = lctx.lower_item(item) { + lctx.items.insert(item.id, hir_item); + } else { + item_lowered = false; + } + }); + + if item_lowered { visit::walk_item(self, item); } } fn visit_trait_item(&mut self, item: &'lcx TraitItem) { - let id = hir::TraitItemId { node_id: item.id }; - let hir_item = self.lctx.lower_trait_item(item); - self.lctx.trait_items.insert(id, hir_item); + self.lctx.with_hir_id_owner(item.id, |lctx| { + let id = hir::TraitItemId { node_id: item.id }; + let hir_item = lctx.lower_trait_item(item); + lctx.trait_items.insert(id, hir_item); + }); + visit::walk_trait_item(self, item); } fn visit_impl_item(&mut self, item: &'lcx ImplItem) { - let id = hir::ImplItemId { node_id: item.id }; - let hir_item = self.lctx.lower_impl_item(item); - self.lctx.impl_items.insert(id, hir_item); + self.lctx.with_hir_id_owner(item.id, |lctx| { + let id = hir::ImplItemId { node_id: item.id }; + let hir_item = lctx.lower_impl_item(item); + lctx.impl_items.insert(id, hir_item); + }); visit::walk_impl_item(self, item); } } + self.lower_node_id(CRATE_NODE_ID); + debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == hir::CRATE_HIR_ID); + visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); @@ -202,6 +241,10 @@ impl<'a> LoweringContext<'a> { let attrs = self.lower_attrs(&c.attrs); let body_ids = body_ids(&self.bodies); + self.resolver + .definitions() + .init_node_id_to_hir_id_mapping(self.node_id_to_hir_id); + hir::Crate { module: module, attrs: attrs, @@ -217,6 +260,103 @@ impl<'a> LoweringContext<'a> { } } + fn allocate_hir_id_counter(&mut self, + owner: NodeId, + debug: &T) { + if self.item_local_id_counters.insert(owner, 0).is_some() { + bug!("Tried to allocate item_local_id_counter for {:?} twice", debug); + } + // Always allocate the first HirId for the owner itself + self.lower_node_id_with_owner(owner, owner); + } + + fn lower_node_id_generic(&mut self, + ast_node_id: NodeId, + alloc_hir_id: F) + -> NodeId + where F: FnOnce(&mut Self) -> hir::HirId + { + if ast_node_id == DUMMY_NODE_ID { + return ast_node_id; + } + + let min_size = ast_node_id.as_usize() + 1; + + if min_size > self.node_id_to_hir_id.len() { + self.node_id_to_hir_id.resize(min_size, hir::DUMMY_HIR_ID); + } + + if self.node_id_to_hir_id[ast_node_id] == hir::DUMMY_HIR_ID { + // Generate a new HirId + self.node_id_to_hir_id[ast_node_id] = alloc_hir_id(self); + } + + ast_node_id + } + + fn with_hir_id_owner(&mut self, owner: NodeId, f: F) + where F: FnOnce(&mut Self) + { + let counter = self.item_local_id_counters + .insert(owner, HIR_ID_COUNTER_LOCKED) + .unwrap(); + let def_index = self.resolver.definitions().opt_def_index(owner).unwrap(); + self.current_hir_id_owner.push((def_index, counter)); + f(self); + let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap(); + + debug_assert!(def_index == new_def_index); + debug_assert!(new_counter >= counter); + + let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap(); + debug_assert!(prev == HIR_ID_COUNTER_LOCKED); + } + + /// This method allocates a new HirId for the given NodeId and stores it in + /// the LoweringContext's NodeId => HirId map. + /// Take care not to call this method if the resulting HirId is then not + /// actually used in the HIR, as that would trigger an assertion in the + /// HirIdValidator later on, which makes sure that all NodeIds got mapped + /// properly. Calling the method twice with the same NodeId is fine though. + fn lower_node_id(&mut self, ast_node_id: NodeId) -> NodeId { + self.lower_node_id_generic(ast_node_id, |this| { + let &mut (def_index, ref mut local_id_counter) = this.current_hir_id_owner + .last_mut() + .unwrap(); + let local_id = *local_id_counter; + *local_id_counter += 1; + hir::HirId { + owner: def_index, + local_id: hir::ItemLocalId(local_id), + } + }) + } + + fn lower_node_id_with_owner(&mut self, + ast_node_id: NodeId, + owner: NodeId) + -> NodeId { + self.lower_node_id_generic(ast_node_id, |this| { + let local_id_counter = this.item_local_id_counters + .get_mut(&owner) + .unwrap(); + let local_id = *local_id_counter; + + // We want to be sure not to modify the counter in the map while it + // is also on the stack. Otherwise we'll get lost updates when writing + // back from the stack to the map. + debug_assert!(local_id != HIR_ID_COUNTER_LOCKED); + + *local_id_counter += 1; + let def_index = this.resolver.definitions().opt_def_index(owner).unwrap(); + + hir::HirId { + owner: def_index, + local_id: hir::ItemLocalId(local_id), + } + }) + } + fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) -> hir::BodyId { let body = hir::Body { @@ -230,8 +370,8 @@ impl<'a> LoweringContext<'a> { id } - fn next_id(&self) -> NodeId { - self.sess.next_node_id() + fn next_id(&mut self) -> NodeId { + self.lower_node_id(self.sess.next_node_id()) } fn expect_full_def(&mut self, id: NodeId) -> Def { @@ -362,7 +502,7 @@ impl<'a> LoweringContext<'a> { match destination { Some((id, label_ident)) => { let target = if let Def::Label(loop_id) = self.expect_full_def(id) { - hir::LoopIdResult::Ok(loop_id) + hir::LoopIdResult::Ok(self.lower_node_id(loop_id)) } else { hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel) }; @@ -371,11 +511,18 @@ impl<'a> LoweringContext<'a> { target_id: hir::ScopeTarget::Loop(target), } }, - None => hir::Destination { - ident: None, - target_id: hir::ScopeTarget::Loop( - self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id)) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into()) + None => { + let loop_id = self.loop_scopes + .last() + .map(|innermost_loop_id| *innermost_loop_id); + + hir::Destination { + ident: None, + target_id: hir::ScopeTarget::Loop( + loop_id.map(|id| Ok(self.lower_node_id(id))) + .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) + .into()) + } } } } @@ -395,7 +542,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding { hir::TypeBinding { - id: b.id, + id: self.lower_node_id(b.id), name: b.ident.name, ty: self.lower_ty(&b.ty), span: b.span, @@ -403,82 +550,87 @@ impl<'a> LoweringContext<'a> { } fn lower_ty(&mut self, t: &Ty) -> P { - P(hir::Ty { - id: t.id, - node: match t.node { - TyKind::Infer => hir::TyInfer, - TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), - TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), - TyKind::Rptr(ref region, ref mt) => { - let span = Span { hi: t.span.lo, ..t.span }; - let lifetime = match *region { - Some(ref lt) => self.lower_lifetime(lt), - None => self.elided_lifetime(span) - }; - hir::TyRptr(lifetime, self.lower_mt(mt)) - } - TyKind::BareFn(ref f) => { - hir::TyBareFn(P(hir::BareFnTy { - lifetimes: self.lower_lifetime_defs(&f.lifetimes), - unsafety: self.lower_unsafety(f.unsafety), - abi: f.abi, - decl: self.lower_fn_decl(&f.decl), - })) - } - TyKind::Never => hir::TyNever, - TyKind::Tup(ref tys) => { - hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()) - } - TyKind::Paren(ref ty) => { - return self.lower_ty(ty); - } - TyKind::Path(ref qself, ref path) => { - let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); - return self.ty_path(t.id, t.span, qpath); - } - TyKind::ImplicitSelf => { - hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { - def: self.expect_full_def(t.id), - segments: hir_vec![hir::PathSegment { - name: keywords::SelfType.name(), - parameters: hir::PathParameters::none() - }], - span: t.span, - }))) - } - TyKind::Array(ref ty, ref length) => { - let length = self.lower_expr(length); - hir::TyArray(self.lower_ty(ty), - self.record_body(length, None)) - } - TyKind::Typeof(ref expr) => { - let expr = self.lower_expr(expr); - hir::TyTypeof(self.record_body(expr, None)) - } - TyKind::TraitObject(ref bounds) => { - let mut lifetime_bound = None; - let bounds = bounds.iter().filter_map(|bound| { - match *bound { - TraitTyParamBound(ref ty, TraitBoundModifier::None) => { - Some(self.lower_poly_trait_ref(ty)) - } - TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, - RegionTyParamBound(ref lifetime) => { + let kind = match t.node { + TyKind::Infer => hir::TyInfer, + TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), + TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), + TyKind::Rptr(ref region, ref mt) => { + let span = Span { hi: t.span.lo, ..t.span }; + let lifetime = match *region { + Some(ref lt) => self.lower_lifetime(lt), + None => self.elided_lifetime(span) + }; + hir::TyRptr(lifetime, self.lower_mt(mt)) + } + TyKind::BareFn(ref f) => { + hir::TyBareFn(P(hir::BareFnTy { + lifetimes: self.lower_lifetime_defs(&f.lifetimes), + unsafety: self.lower_unsafety(f.unsafety), + abi: f.abi, + decl: self.lower_fn_decl(&f.decl), + })) + } + TyKind::Never => hir::TyNever, + TyKind::Tup(ref tys) => { + hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()) + } + TyKind::Paren(ref ty) => { + return self.lower_ty(ty); + } + TyKind::Path(ref qself, ref path) => { + let id = self.lower_node_id(t.id); + let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); + return self.ty_path(id, t.span, qpath); + } + TyKind::ImplicitSelf => { + hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { + def: self.expect_full_def(t.id), + segments: hir_vec![hir::PathSegment { + name: keywords::SelfType.name(), + parameters: hir::PathParameters::none() + }], + span: t.span, + }))) + } + TyKind::Array(ref ty, ref length) => { + let length = self.lower_expr(length); + hir::TyArray(self.lower_ty(ty), + self.record_body(length, None)) + } + TyKind::Typeof(ref expr) => { + let expr = self.lower_expr(expr); + hir::TyTypeof(self.record_body(expr, None)) + } + TyKind::TraitObject(ref bounds) => { + let mut lifetime_bound = None; + let bounds = bounds.iter().filter_map(|bound| { + match *bound { + TraitTyParamBound(ref ty, TraitBoundModifier::None) => { + Some(self.lower_poly_trait_ref(ty)) + } + TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, + RegionTyParamBound(ref lifetime) => { + if lifetime_bound.is_none() { lifetime_bound = Some(self.lower_lifetime(lifetime)); - None } + None } - }).collect(); - let lifetime_bound = lifetime_bound.unwrap_or_else(|| { - self.elided_lifetime(t.span) - }); - hir::TyTraitObject(bounds, lifetime_bound) - } - TyKind::ImplTrait(ref bounds) => { - hir::TyImplTrait(self.lower_bounds(bounds)) - } - TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), - }, + } + }).collect(); + let lifetime_bound = lifetime_bound.unwrap_or_else(|| { + self.elided_lifetime(t.span) + }); + hir::TyTraitObject(bounds, lifetime_bound) + } + TyKind::ImplTrait(ref bounds) => { + hir::TyImplTrait(self.lower_bounds(bounds)) + } + TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), + }; + + P(hir::Ty { + id: self.lower_node_id(t.id), + node: kind, span: t.span, }) } @@ -712,7 +864,7 @@ impl<'a> LoweringContext<'a> { fn lower_local(&mut self, l: &Local) -> P { P(hir::Local { - id: l.id, + id: self.lower_node_id(l.id), ty: l.ty.as_ref().map(|t| self.lower_ty(t)), pat: self.lower_pat(&l.pat), init: l.init.as_ref().map(|e| P(self.lower_expr(e))), @@ -730,7 +882,7 @@ impl<'a> LoweringContext<'a> { fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { hir::Arg { - id: arg.id, + id: self.lower_node_id(arg.id), pat: self.lower_pat(&arg.pat), } } @@ -786,7 +938,7 @@ impl<'a> LoweringContext<'a> { } hir::TyParam { - id: tp.id, + id: self.lower_node_id(tp.id), name: name, bounds: bounds, default: tp.default.as_ref().map(|x| self.lower_ty(x)), @@ -804,7 +956,7 @@ impl<'a> LoweringContext<'a> { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { hir::Lifetime { - id: l.id, + id: self.lower_node_id(l.id), name: l.name, span: l.span, } @@ -876,7 +1028,7 @@ impl<'a> LoweringContext<'a> { fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause { hir::WhereClause { - id: wc.id, + id: self.lower_node_id(wc.id), predicates: wc.predicates .iter() .map(|predicate| self.lower_where_predicate(predicate)) @@ -915,7 +1067,7 @@ impl<'a> LoweringContext<'a> { ref rhs_ty, span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - id: id, + id: self.lower_node_id(id), lhs_ty: self.lower_ty(lhs_ty), rhs_ty: self.lower_ty(rhs_ty), span: span, @@ -931,16 +1083,16 @@ impl<'a> LoweringContext<'a> { .enumerate() .map(|f| self.lower_struct_field(f)) .collect(), - id) + self.lower_node_id(id)) } VariantData::Tuple(ref fields, id) => { hir::VariantData::Tuple(fields.iter() .enumerate() .map(|f| self.lower_struct_field(f)) .collect(), - id) + self.lower_node_id(id)) } - VariantData::Unit(id) => hir::VariantData::Unit(id), + VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id)), } } @@ -951,7 +1103,7 @@ impl<'a> LoweringContext<'a> { }; hir::TraitRef { path: path, - ref_id: p.ref_id, + ref_id: self.lower_node_id(p.ref_id), } } @@ -966,9 +1118,9 @@ impl<'a> LoweringContext<'a> { fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField { hir::StructField { span: f.span, - id: f.id, + id: self.lower_node_id(f.id), name: f.ident.map(|ident| ident.name).unwrap_or(Symbol::intern(&index.to_string())), - vis: self.lower_visibility(&f.vis), + vis: self.lower_visibility(&f.vis, None), ty: self.lower_ty(&f.ty), attrs: self.lower_attrs(&f.attrs), } @@ -997,17 +1149,22 @@ impl<'a> LoweringContext<'a> { fn lower_block(&mut self, b: &Block, break_to: Option) -> P { let mut expr = None; - let mut stmts = b.stmts.iter().flat_map(|s| self.lower_stmt(s)).collect::>(); - if let Some(last) = stmts.pop() { - if let hir::StmtExpr(e, _) = last.node { - expr = Some(e); + let mut stmts = vec![]; + + for (index, stmt) in b.stmts.iter().enumerate() { + if index == b.stmts.len() - 1 { + if let StmtKind::Expr(ref e) = stmt.node { + expr = Some(P(self.lower_expr(e))); + } else { + stmts.extend(self.lower_stmt(stmt)); + } } else { - stmts.push(last); + stmts.extend(self.lower_stmt(stmt)); } } P(hir::Block { - id: b.id, + id: self.lower_node_id(b.id), stmts: stmts.into(), expr: expr, rules: self.lower_block_check_mode(&b.rules), @@ -1046,13 +1203,30 @@ impl<'a> LoweringContext<'a> { let mut path = self.lower_path_extra(import.id, path, suffix, ParamMode::Explicit, true); path.span = span; - self.items.insert(import.id, hir::Item { - id: import.id, - name: import.rename.unwrap_or(ident).name, - attrs: attrs.clone(), - node: hir::ItemUse(P(path), hir::UseKind::Single), - vis: vis.clone(), - span: span, + + self.allocate_hir_id_counter(import.id, import); + self.with_hir_id_owner(import.id, |this| { + let vis = match *vis { + hir::Visibility::Public => hir::Visibility::Public, + hir::Visibility::Crate => hir::Visibility::Crate, + hir::Visibility::Inherited => hir::Visibility::Inherited, + hir::Visibility::Restricted { ref path, id: _ } => { + hir::Visibility::Restricted { + path: path.clone(), + // We are allocating a new NodeId here + id: this.next_id(), + } + } + }; + + this.items.insert(import.id, hir::Item { + id: import.id, + name: import.rename.unwrap_or(ident).name, + attrs: attrs.clone(), + node: hir::ItemUse(P(path), hir::UseKind::Single), + vis: vis, + span: span, + }); }); } path @@ -1167,7 +1341,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { self.with_parent_def(i.id, |this| { hir::TraitItem { - id: i.id, + id: this.lower_node_id(i.id), name: i.ident.name, attrs: this.lower_attrs(&i.attrs), node: match i.node { @@ -1228,10 +1402,10 @@ impl<'a> LoweringContext<'a> { fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem { self.with_parent_def(i.id, |this| { hir::ImplItem { - id: i.id, + id: this.lower_node_id(i.id), name: i.ident.name, attrs: this.lower_attrs(&i.attrs), - vis: this.lower_visibility(&i.vis), + vis: this.lower_visibility(&i.vis, None), defaultness: this.lower_defaultness(i.defaultness, true /* [1] */), node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { @@ -1260,7 +1434,7 @@ impl<'a> LoweringContext<'a> { id: hir::ImplItemId { node_id: i.id }, name: i.ident.name, span: i.span, - vis: self.lower_visibility(&i.vis), + vis: self.lower_visibility(&i.vis, Some(i.id)), defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), kind: match i.node { ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, @@ -1299,7 +1473,6 @@ impl<'a> LoweringContext<'a> { pub fn lower_item(&mut self, i: &Item) -> Option { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); - let mut vis = self.lower_visibility(&i.vis); if let ItemKind::MacroDef(ref tts) = i.node { if i.attrs.iter().any(|attr| attr.path == "macro_export") { self.exported_macros.push(hir::MacroDef { @@ -1309,12 +1482,13 @@ impl<'a> LoweringContext<'a> { return None; } + let mut vis = self.lower_visibility(&i.vis, None); let node = self.with_parent_def(i.id, |this| { this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) }); Some(hir::Item { - id: i.id, + id: self.lower_node_id(i.id), name: name, attrs: attrs, node: node, @@ -1326,7 +1500,7 @@ impl<'a> LoweringContext<'a> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { self.with_parent_def(i.id, |this| { hir::ForeignItem { - id: i.id, + id: this.lower_node_id(i.id), name: i.ident.name, attrs: this.lower_attrs(&i.attrs), node: match i.node { @@ -1339,7 +1513,7 @@ impl<'a> LoweringContext<'a> { hir::ForeignItemStatic(this.lower_ty(t), m) } }, - vis: this.lower_visibility(&i.vis), + vis: this.lower_visibility(&i.vis, None), span: i.span, } }) @@ -1405,7 +1579,7 @@ impl<'a> LoweringContext<'a> { fn lower_pat(&mut self, p: &Pat) -> P { P(hir::Pat { - id: p.id, + id: self.lower_node_id(p.id), node: match p.node { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, pth1, ref sub) => { @@ -1491,707 +1665,746 @@ impl<'a> LoweringContext<'a> { } fn lower_expr(&mut self, e: &Expr) -> hir::Expr { - hir::Expr { - id: e.id, - node: match e.node { - // Issue #22181: - // Eventually a desugaring for `box EXPR` - // (similar to the desugaring above for `in PLACE BLOCK`) - // should go here, desugaring - // + let kind = match e.node { + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ExprKind::Box(ref inner) => { + hir::ExprBox(P(self.lower_expr(inner))) + } + + // Desugar ExprBox: `in (PLACE) EXPR` + ExprKind::InPlace(ref placer, ref value_expr) => { // to: // - // let mut place = BoxPlace::make_place(); + // let p = PLACE; + // let mut place = Placer::make_place(p); // let raw_place = Place::pointer(&mut place); - // let value = $value; - // unsafe { - // ::std::ptr::write(raw_place, value); - // Boxed::finalize(place) - // } - // - // But for now there are type-inference issues doing that. - ExprKind::Box(ref e) => { - hir::ExprBox(P(self.lower_expr(e))) - } - - // Desugar ExprBox: `in (PLACE) EXPR` - ExprKind::InPlace(ref placer, ref value_expr) => { - // to: - // - // let p = PLACE; - // let mut place = Placer::make_place(p); - // let raw_place = Place::pointer(&mut place); - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let placer_expr = P(self.lower_expr(placer)); - let value_expr = P(self.lower_expr(value_expr)); - - let placer_ident = self.str_to_ident("placer"); - let place_ident = self.str_to_ident("place"); - let p_ptr_ident = self.str_to_ident("p_ptr"); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let unstable_span = self.allow_internal_unstable("<-", e.span); - let make_call = |this: &mut LoweringContext, p, args| { - let path = P(this.expr_std_path(unstable_span, p, ThinVec::new())); - P(this.expr_call(e.span, path, args)) - }; + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let placer_expr = P(self.lower_expr(placer)); + let value_expr = P(self.lower_expr(value_expr)); + + let placer_ident = self.str_to_ident("placer"); + let place_ident = self.str_to_ident("place"); + let p_ptr_ident = self.str_to_ident("p_ptr"); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let unstable_span = self.allow_internal_unstable("<-", e.span); + let make_call = |this: &mut LoweringContext, p, args| { + let path = P(this.expr_std_path(unstable_span, p, ThinVec::new())); + P(this.expr_call(e.span, path, args)) + }; - let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, false, bind, expr) - }; + let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { + this.stmt_let(e.span, false, bind, expr) + }; - let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, true, bind, expr) - }; + let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { + this.stmt_let(e.span, true, bind, expr) + }; - // let placer = ; - let (s1, placer_binding) = { - mk_stmt_let(self, placer_ident, placer_expr) - }; + // let placer = ; + let (s1, placer_binding) = { + mk_stmt_let(self, placer_ident, placer_expr) + }; - // let mut place = Placer::make_place(placer); - let (s2, place_binding) = { - let placer = self.expr_ident(e.span, placer_ident, placer_binding); - let call = make_call(self, &make_place, hir_vec![placer]); - mk_stmt_let_mut(self, place_ident, call) - }; + // let mut place = Placer::make_place(placer); + let (s2, place_binding) = { + let placer = self.expr_ident(e.span, placer_ident, placer_binding); + let call = make_call(self, &make_place, hir_vec![placer]); + mk_stmt_let_mut(self, place_ident, call) + }; - // let p_ptr = Place::pointer(&mut place); - let (s3, p_ptr_binding) = { - let agent = P(self.expr_ident(e.span, place_ident, place_binding)); - let args = hir_vec![self.expr_mut_addr_of(e.span, agent)]; - let call = make_call(self, &place_pointer, args); - mk_stmt_let(self, p_ptr_ident, call) - }; + // let p_ptr = Place::pointer(&mut place); + let (s3, p_ptr_binding) = { + let agent = P(self.expr_ident(e.span, place_ident, place_binding)); + let args = hir_vec![self.expr_mut_addr_of(e.span, agent)]; + let call = make_call(self, &place_pointer, args); + mk_stmt_let(self, p_ptr_ident, call) + }; - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = { - self.signal_block_expr(hir_vec![], - value_expr, - e.span, - hir::PopUnsafeBlock(hir::CompilerGenerated), - ThinVec::new()) - }; + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = { + self.signal_block_expr(hir_vec![], + value_expr, + e.span, + hir::PopUnsafeBlock(hir::CompilerGenerated), + ThinVec::new()) + }; - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let expr = { - let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding); - let call_move_val_init = - hir::StmtSemi( - make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - self.next_id()); - let call_move_val_init = respan(e.span, call_move_val_init); - - let place = self.expr_ident(e.span, place_ident, place_binding); - let call = make_call(self, &inplace_finalize, hir_vec![place]); - P(self.signal_block_expr(hir_vec![call_move_val_init], - call, - e.span, - hir::PushUnsafeBlock(hir::CompilerGenerated), - ThinVec::new())) - }; + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let expr = { + let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding); + let call_move_val_init = + hir::StmtSemi( + make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), + self.next_id()); + let call_move_val_init = respan(e.span, call_move_val_init); + + let place = self.expr_ident(e.span, place_ident, place_binding); + let call = make_call(self, &inplace_finalize, hir_vec![place]); + P(self.signal_block_expr(hir_vec![call_move_val_init], + call, + e.span, + hir::PushUnsafeBlock(hir::CompilerGenerated), + ThinVec::new())) + }; - let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr)); - // add the attributes to the outer returned expr node - return self.expr_block(P(block), e.attrs.clone()); - } + let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr)); + hir::ExprBlock(P(block)) + } - ExprKind::Array(ref exprs) => { - hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) - } - ExprKind::Repeat(ref expr, ref count) => { - let expr = P(self.lower_expr(expr)); - let count = self.lower_expr(count); - hir::ExprRepeat(expr, self.record_body(count, None)) - } - ExprKind::Tup(ref elts) => { - hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) - } - ExprKind::Call(ref f, ref args) => { - let f = P(self.lower_expr(f)); - hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect()) - } - ExprKind::MethodCall(i, ref tps, ref args) => { - let tps = tps.iter().map(|x| self.lower_ty(x)).collect(); - let args = args.iter().map(|x| self.lower_expr(x)).collect(); - hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) - } - ExprKind::Binary(binop, ref lhs, ref rhs) => { - let binop = self.lower_binop(binop); - let lhs = P(self.lower_expr(lhs)); - let rhs = P(self.lower_expr(rhs)); - hir::ExprBinary(binop, lhs, rhs) - } - ExprKind::Unary(op, ref ohs) => { - let op = self.lower_unop(op); - let ohs = P(self.lower_expr(ohs)); - hir::ExprUnary(op, ohs) - } - ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), - ExprKind::Cast(ref expr, ref ty) => { - let expr = P(self.lower_expr(expr)); - hir::ExprCast(expr, self.lower_ty(ty)) - } - ExprKind::Type(ref expr, ref ty) => { - let expr = P(self.lower_expr(expr)); - hir::ExprType(expr, self.lower_ty(ty)) - } - ExprKind::AddrOf(m, ref ohs) => { - let m = self.lower_mutability(m); - let ohs = P(self.lower_expr(ohs)); - hir::ExprAddrOf(m, ohs) - } - // More complicated than you might expect because the else branch - // might be `if let`. - ExprKind::If(ref cond, ref blk, ref else_opt) => { - let else_opt = else_opt.as_ref().map(|els| { - match els.node { - ExprKind::IfLet(..) => { - // wrap the if-let expr in a block - let span = els.span; - let els = P(self.lower_expr(els)); - let id = self.next_id(); - let blk = P(hir::Block { - stmts: hir_vec![], - expr: Some(els), - id: id, - rules: hir::DefaultBlock, - span: span, - break_to_expr_id: None, - }); - P(self.expr_block(blk, ThinVec::new())) - } - _ => P(self.lower_expr(els)), + ExprKind::Array(ref exprs) => { + hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::Repeat(ref expr, ref count) => { + let expr = P(self.lower_expr(expr)); + let count = self.lower_expr(count); + hir::ExprRepeat(expr, self.record_body(count, None)) + } + ExprKind::Tup(ref elts) => { + hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::Call(ref f, ref args) => { + let f = P(self.lower_expr(f)); + hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::MethodCall(i, ref tps, ref args) => { + let tps = tps.iter().map(|x| self.lower_ty(x)).collect(); + let args = args.iter().map(|x| self.lower_expr(x)).collect(); + hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) + } + ExprKind::Binary(binop, ref lhs, ref rhs) => { + let binop = self.lower_binop(binop); + let lhs = P(self.lower_expr(lhs)); + let rhs = P(self.lower_expr(rhs)); + hir::ExprBinary(binop, lhs, rhs) + } + ExprKind::Unary(op, ref ohs) => { + let op = self.lower_unop(op); + let ohs = P(self.lower_expr(ohs)); + hir::ExprUnary(op, ohs) + } + ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), + ExprKind::Cast(ref expr, ref ty) => { + let expr = P(self.lower_expr(expr)); + hir::ExprCast(expr, self.lower_ty(ty)) + } + ExprKind::Type(ref expr, ref ty) => { + let expr = P(self.lower_expr(expr)); + hir::ExprType(expr, self.lower_ty(ty)) + } + ExprKind::AddrOf(m, ref ohs) => { + let m = self.lower_mutability(m); + let ohs = P(self.lower_expr(ohs)); + hir::ExprAddrOf(m, ohs) + } + // More complicated than you might expect because the else branch + // might be `if let`. + ExprKind::If(ref cond, ref blk, ref else_opt) => { + let else_opt = else_opt.as_ref().map(|els| { + match els.node { + ExprKind::IfLet(..) => { + // wrap the if-let expr in a block + let span = els.span; + let els = P(self.lower_expr(els)); + let id = self.next_id(); + let blk = P(hir::Block { + stmts: hir_vec![], + expr: Some(els), + id: id, + rules: hir::DefaultBlock, + span: span, + break_to_expr_id: None, + }); + P(self.expr_block(blk, ThinVec::new())) } - }); + _ => P(self.lower_expr(els)), + } + }); - hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) - } - ExprKind::While(ref cond, ref body, opt_ident) => { - self.with_loop_scope(e.id, |this| - hir::ExprWhile( - this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body, None), - this.lower_opt_sp_ident(opt_ident))) - } - ExprKind::Loop(ref body, opt_ident) => { - self.with_loop_scope(e.id, |this| - hir::ExprLoop(this.lower_block(body, None), - this.lower_opt_sp_ident(opt_ident), - hir::LoopSource::Loop)) - } - ExprKind::Catch(ref body) => { - self.with_catch_scope(e.id, |this| - hir::ExprBlock(this.lower_block(body, Some(e.id)))) - } - ExprKind::Match(ref expr, ref arms) => { - hir::ExprMatch(P(self.lower_expr(expr)), - arms.iter().map(|x| self.lower_arm(x)).collect(), - hir::MatchSource::Normal) - } - ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_scopes(|this| { - this.with_parent_def(e.id, |this| { - let expr = this.lower_expr(body); - hir::ExprClosure(this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl), - this.record_body(expr, Some(decl)), - fn_decl_span) - }) + hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) + } + ExprKind::While(ref cond, ref body, opt_ident) => { + self.with_loop_scope(e.id, |this| + hir::ExprWhile( + this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), + this.lower_block(body, None), + this.lower_opt_sp_ident(opt_ident))) + } + ExprKind::Loop(ref body, opt_ident) => { + self.with_loop_scope(e.id, |this| + hir::ExprLoop(this.lower_block(body, None), + this.lower_opt_sp_ident(opt_ident), + hir::LoopSource::Loop)) + } + ExprKind::Catch(ref body) => { + self.with_catch_scope(e.id, |this| + hir::ExprBlock(this.lower_block(body, Some(e.id)))) + } + ExprKind::Match(ref expr, ref arms) => { + hir::ExprMatch(P(self.lower_expr(expr)), + arms.iter().map(|x| self.lower_arm(x)).collect(), + hir::MatchSource::Normal) + } + ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { + self.with_new_scopes(|this| { + this.with_parent_def(e.id, |this| { + let expr = this.lower_expr(body); + hir::ExprClosure(this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl), + this.record_body(expr, Some(decl)), + fn_decl_span) }) - } - ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), - ExprKind::Assign(ref el, ref er) => { - hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) - } - ExprKind::AssignOp(op, ref el, ref er) => { - hir::ExprAssignOp(self.lower_binop(op), - P(self.lower_expr(el)), - P(self.lower_expr(er))) - } - ExprKind::Field(ref el, ident) => { - hir::ExprField(P(self.lower_expr(el)), respan(ident.span, ident.node.name)) - } - ExprKind::TupField(ref el, ident) => { - hir::ExprTupField(P(self.lower_expr(el)), ident) - } - ExprKind::Index(ref el, ref er) => { - hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) - } - ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(this: &mut LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) - .collect::>(); - let unstable_span = this.allow_internal_unstable("...", ast_expr.span); - - if fields.len() == 0 { - this.expr_std_path(unstable_span, struct_path, - ast_expr.attrs.clone()) - } else { - let fields = fields.into_iter().map(|&(s, e)| { - let expr = P(this.lower_expr(&e)); - let unstable_span = this.allow_internal_unstable("...", e.span); - this.field(Symbol::intern(s), expr, unstable_span) - }).collect(); - let attrs = ast_expr.attrs.clone(); - - this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) - } + }) + } + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), + ExprKind::Assign(ref el, ref er) => { + hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) + } + ExprKind::AssignOp(op, ref el, ref er) => { + hir::ExprAssignOp(self.lower_binop(op), + P(self.lower_expr(el)), + P(self.lower_expr(er))) + } + ExprKind::Field(ref el, ident) => { + hir::ExprField(P(self.lower_expr(el)), respan(ident.span, ident.node.name)) + } + ExprKind::TupField(ref el, ident) => { + hir::ExprTupField(P(self.lower_expr(el)), ident) + } + ExprKind::Index(ref el, ref er) => { + hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) + } + ExprKind::Range(ref e1, ref e2, lims) => { + fn make_struct(this: &mut LoweringContext, + ast_expr: &Expr, + path: &[&str], + fields: &[(&str, &P)]) -> hir::Expr { + let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) + .collect::>(); + let unstable_span = this.allow_internal_unstable("...", ast_expr.span); + + if fields.len() == 0 { + this.expr_std_path(unstable_span, struct_path, + ast_expr.attrs.clone()) + } else { + let fields = fields.into_iter().map(|&(s, e)| { + let expr = P(this.lower_expr(&e)); + let unstable_span = this.allow_internal_unstable("...", e.span); + this.field(Symbol::intern(s), expr, unstable_span) + }).collect(); + let attrs = ast_expr.attrs.clone(); + + this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) } + } - use syntax::ast::RangeLimits::*; + use syntax::ast::RangeLimits::*; - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(self, e, &["RangeFull"], &[]), + return match (e1, e2, lims) { + (&None, &None, HalfOpen) => + make_struct(self, e, &["RangeFull"], &[]), - (&Some(ref e1), &None, HalfOpen) => - make_struct(self, e, &["RangeFrom"], - &[("start", e1)]), + (&Some(ref e1), &None, HalfOpen) => + make_struct(self, e, &["RangeFrom"], + &[("start", e1)]), - (&None, &Some(ref e2), HalfOpen) => - make_struct(self, e, &["RangeTo"], - &[("end", e2)]), + (&None, &Some(ref e2), HalfOpen) => + make_struct(self, e, &["RangeTo"], + &[("end", e2)]), - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(self, e, &["Range"], - &[("start", e1), ("end", e2)]), + (&Some(ref e1), &Some(ref e2), HalfOpen) => + make_struct(self, e, &["Range"], + &[("start", e1), ("end", e2)]), - (&None, &Some(ref e2), Closed) => - make_struct(self, e, &["RangeToInclusive"], - &[("end", e2)]), + (&None, &Some(ref e2), Closed) => + make_struct(self, e, &["RangeToInclusive"], + &[("end", e2)]), - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(self, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), + (&Some(ref e1), &Some(ref e2), Closed) => + make_struct(self, e, &["RangeInclusive", "NonEmpty"], + &[("start", e1), ("end", e2)]), - _ => panic!(self.diagnostic() - .span_fatal(e.span, "inclusive range with no end")), - }; - } - ExprKind::Path(ref qself, ref path) => { - hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) - } - ExprKind::Break(opt_ident, ref opt_expr) => { - let label_result = if self.is_in_loop_condition && opt_ident.is_none() { + _ => panic!(self.diagnostic() + .span_fatal(e.span, "inclusive range with no end")), + }; + } + ExprKind::Path(ref qself, ref path) => { + hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) + } + ExprKind::Break(opt_ident, ref opt_expr) => { + let label_result = if self.is_in_loop_condition && opt_ident.is_none() { + hir::Destination { + ident: opt_ident, + target_id: hir::ScopeTarget::Loop( + Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()), + } + } else { + self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident))) + }; + hir::ExprBreak( + label_result, + opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) + } + ExprKind::Continue(opt_ident) => + hir::ExprAgain( + if self.is_in_loop_condition && opt_ident.is_none() { hir::Destination { ident: opt_ident, - target_id: hir::ScopeTarget::Loop( - Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()), + target_id: hir::ScopeTarget::Loop(Err( + hir::LoopIdError::UnlabeledCfInWhileCondition).into()), } } else { - self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident))) - }; - hir::ExprBreak( - label_result, - opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) - } - ExprKind::Continue(opt_ident) => - hir::ExprAgain( - if self.is_in_loop_condition && opt_ident.is_none() { - hir::Destination { - ident: opt_ident, - target_id: hir::ScopeTarget::Loop(Err( - hir::LoopIdError::UnlabeledCfInWhileCondition).into()), - } + self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident))) + }), + ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), + ExprKind::InlineAsm(ref asm) => { + let hir_asm = hir::InlineAsm { + inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), + outputs: asm.outputs.iter().map(|out| { + hir::InlineAsmOutput { + constraint: out.constraint.clone(), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }).collect(), + asm: asm.asm.clone(), + asm_str_style: asm.asm_str_style, + clobbers: asm.clobbers.clone().into(), + volatile: asm.volatile, + alignstack: asm.alignstack, + dialect: asm.dialect, + expn_id: asm.expn_id, + }; + let outputs = + asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); + let inputs = + asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect(); + hir::ExprInlineAsm(P(hir_asm), outputs, inputs) + } + ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { + hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional), + fields.iter().map(|x| self.lower_field(x)).collect(), + maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) + } + ExprKind::Paren(ref ex) => { + let mut ex = self.lower_expr(ex); + // include parens in span, but only if it is a super-span. + if e.span.contains(ex.span) { + ex.span = e.span; + } + // merge attributes into the inner expression. + let mut attrs = e.attrs.clone(); + attrs.extend::>(ex.attrs.into()); + ex.attrs = attrs; + return ex; + } + + // Desugar ExprIfLet + // From: `if let = []` + ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { + // to: + // + // match { + // => , + // [_ if => ,] + // _ => [ | ()] + // } + + let mut arms = vec![]; + + // ` => ` + { + let body = self.lower_block(body, None); + let body_expr = P(self.expr_block(body, ThinVec::new())); + let pat = self.lower_pat(pat); + arms.push(self.arm(hir_vec![pat], body_expr)); + } + + // `[_ if => ,]` + // `_ => [ | ()]` + { + let mut current: Option<&Expr> = else_opt.as_ref().map(|p| &**p); + let mut else_exprs: Vec> = vec![current]; + + // First, we traverse the AST and recursively collect all + // `else` branches into else_exprs, e.g.: + // + // if let Some(_) = x { + // ... + // } else if ... { // Expr1 + // ... + // } else if ... { // Expr2 + // ... + // } else { // Expr3 + // ... + // } + // + // ... results in else_exprs = [Some(&Expr1), + // Some(&Expr2), + // Some(&Expr3)] + // + // Because there also the case there is no `else`, these + // entries can also be `None`, as in: + // + // if let Some(_) = x { + // ... + // } else if ... { // Expr1 + // ... + // } else if ... { // Expr2 + // ... + // } + // + // ... results in else_exprs = [Some(&Expr1), + // Some(&Expr2), + // None] + // + // The last entry in this list is always translated into + // the final "unguard" wildcard arm of the `match`. In the + // case of a `None`, it becomes `_ => ()`. + loop { + if let Some(e) = current { + // There is an else branch at this level + if let ExprKind::If(_, _, ref else_opt) = e.node { + // The else branch is again an if-expr + current = else_opt.as_ref().map(|p| &**p); + else_exprs.push(current); + } else { + // The last item in the list is not an if-expr, + // stop here + break + } } else { - self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident))) - }), - ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))), - ExprKind::InlineAsm(ref asm) => { - let hir_asm = hir::InlineAsm { - inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), - outputs: asm.outputs.iter().map(|out| { - hir::InlineAsmOutput { - constraint: out.constraint.clone(), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }).collect(), - asm: asm.asm.clone(), - asm_str_style: asm.asm_str_style, - clobbers: asm.clobbers.clone().into(), - volatile: asm.volatile, - alignstack: asm.alignstack, - dialect: asm.dialect, - expn_id: asm.expn_id, - }; - let outputs = - asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); - let inputs = - asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect(); - hir::ExprInlineAsm(P(hir_asm), outputs, inputs) - } - ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional), - fields.iter().map(|x| self.lower_field(x)).collect(), - maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) - } - ExprKind::Paren(ref ex) => { - let mut ex = self.lower_expr(ex); - // include parens in span, but only if it is a super-span. - if e.span.contains(ex.span) { - ex.span = e.span; + // We have no more else branch + break + } } - // merge attributes into the inner expression. - let mut attrs = e.attrs.clone(); - attrs.extend::>(ex.attrs.into()); - ex.attrs = attrs; - return ex; - } - // Desugar ExprIfLet - // From: `if let = []` - ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { - // to: - // - // match { - // => , - // [_ if => ,] - // _ => [ | ()] - // } - - // ` => ` - let pat_arm = { - let body = self.lower_block(body, None); - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pat = self.lower_pat(pat); - self.arm(hir_vec![pat], body_expr) - }; + // Now translate the list of nested else-branches into the + // arms of the match statement. + for else_expr in else_exprs { + if let Some(else_expr) = else_expr { + let (guard, body) = if let ExprKind::If(ref cond, + ref then, + _) = else_expr.node { + let then = self.lower_block(then, None); + (Some(cond), + self.expr_block(then, ThinVec::new())) + } else { + (None, + self.lower_expr(else_expr)) + }; - // `[_ if => ,]` - let mut else_opt = else_opt.as_ref().map(|e| P(self.lower_expr(e))); - let else_if_arms = { - let mut arms = vec![]; - loop { - let else_opt_continue = else_opt.and_then(|els| { - els.and_then(|els| { - match els.node { - // else if - hir::ExprIf(cond, then, else_opt) => { - let pat_under = self.pat_wild(e.span); - arms.push(hir::Arm { - attrs: hir_vec![], - pats: hir_vec![pat_under], - guard: Some(cond), - body: P(self.expr_block(then, ThinVec::new())), - }); - else_opt.map(|else_opt| (else_opt, true)) - } - _ => Some((P(els), false)), - } - }) + arms.push(hir::Arm { + attrs: hir_vec![], + pats: hir_vec![self.pat_wild(e.span)], + guard: guard.map(|e| P(self.lower_expr(e))), + body: P(body), }); - match else_opt_continue { - Some((e, true)) => { - else_opt = Some(e); - } - Some((e, false)) => { - else_opt = Some(e); - break; - } - None => { - else_opt = None; - break; - } - } + } else { + // There was no else-branch, push a noop + let pat_under = self.pat_wild(e.span); + let unit = self.expr_tuple(e.span, hir_vec![]); + arms.push(self.arm(hir_vec![pat_under], unit)); } - arms - }; + } + } - let contains_else_clause = else_opt.is_some(); + let contains_else_clause = else_opt.is_some(); - // `_ => [ | ()]` - let else_arm = { - let pat_under = self.pat_wild(e.span); - let else_expr = - else_opt.unwrap_or_else(|| self.expr_tuple(e.span, hir_vec![])); - self.arm(hir_vec![pat_under], else_expr) - }; + let sub_expr = P(self.lower_expr(sub_expr)); - let mut arms = Vec::with_capacity(else_if_arms.len() + 2); - arms.push(pat_arm); - arms.extend(else_if_arms); - arms.push(else_arm); - - let sub_expr = P(self.lower_expr(sub_expr)); - // add attributes to the outer returned expr node - return self.expr(e.span, - hir::ExprMatch(sub_expr, - arms.into(), - hir::MatchSource::IfLetDesugar { - contains_else_clause: contains_else_clause, - }), - e.attrs.clone()); - } + hir::ExprMatch( + sub_expr, + arms.into(), + hir::MatchSource::IfLetDesugar { + contains_else_clause: contains_else_clause, + }) + } - // Desugar ExprWhileLet - // From: `[opt_ident]: while let = ` - ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { - // to: - // - // [opt_ident]: loop { - // match { - // => , - // _ => break - // } - // } - - // Note that the block AND the condition are evaluated in the loop scope. - // This is done to allow `break` from inside the condition of the loop. - let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( - this.lower_block(body, None), - this.expr_break(e.span, ThinVec::new()), - this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), - )); - - // ` => ` - let pat_arm = { - let body_expr = P(self.expr_block(body, ThinVec::new())); - let pat = self.lower_pat(pat); - self.arm(hir_vec![pat], body_expr) - }; + // Desugar ExprWhileLet + // From: `[opt_ident]: while let = ` + ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { + // to: + // + // [opt_ident]: loop { + // match { + // => , + // _ => break + // } + // } + + // Note that the block AND the condition are evaluated in the loop scope. + // This is done to allow `break` from inside the condition of the loop. + let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( + this.lower_block(body, None), + this.expr_break(e.span, ThinVec::new()), + this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), + )); + + // ` => ` + let pat_arm = { + let body_expr = P(self.expr_block(body, ThinVec::new())); + let pat = self.lower_pat(pat); + self.arm(hir_vec![pat], body_expr) + }; - // `_ => break` - let break_arm = { - let pat_under = self.pat_wild(e.span); - self.arm(hir_vec![pat_under], break_expr) - }; + // `_ => break` + let break_arm = { + let pat_under = self.pat_wild(e.span); + self.arm(hir_vec![pat_under], break_expr) + }; - // `match { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let match_expr = self.expr(e.span, - hir::ExprMatch(sub_expr, - arms, - hir::MatchSource::WhileLetDesugar), - ThinVec::new()); - - // `[opt_ident]: loop { ... }` - let loop_block = P(self.block_expr(P(match_expr))); - let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), - hir::LoopSource::WhileLet); - // add attributes to the outer returned expr node - let attrs = e.attrs.clone(); - return hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs }; - } + // `match { ... }` + let arms = hir_vec![pat_arm, break_arm]; + let match_expr = self.expr(e.span, + hir::ExprMatch(sub_expr, + arms, + hir::MatchSource::WhileLetDesugar), + ThinVec::new()); + + // `[opt_ident]: loop { ... }` + let loop_block = P(self.block_expr(P(match_expr))); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), + hir::LoopSource::WhileLet); + // add attributes to the outer returned expr node + loop_expr + } - // Desugar ExprForLoop - // From: `[opt_ident]: for in ` - ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { - // to: - // - // { - // let result = match ::std::iter::IntoIterator::into_iter() { - // mut iter => { - // [opt_ident]: loop { - // match ::std::iter::Iterator::next(&mut iter) { - // ::std::option::Option::Some() => , - // ::std::option::Option::None => break - // } - // } - // } - // }; - // result - // } - - // expand - let head = self.lower_expr(head); - - let iter = self.str_to_ident("iter"); - - // `::std::option::Option::Some() => ` - let pat_arm = { - let body_block = self.with_loop_scope(e.id, - |this| this.lower_block(body, None)); - let body_expr = P(self.expr_block(body_block, ThinVec::new())); - let pat = self.lower_pat(pat); - let some_pat = self.pat_some(e.span, pat); - - self.arm(hir_vec![some_pat], body_expr) - }; + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` + ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { + // to: + // + // { + // let result = match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // }; + // result + // } + + // expand + let head = self.lower_expr(head); + + let iter = self.str_to_ident("iter"); + + // `::std::option::Option::Some() => ` + let pat_arm = { + let body_block = self.with_loop_scope(e.id, + |this| this.lower_block(body, None)); + let body_expr = P(self.expr_block(body_block, ThinVec::new())); + let pat = self.lower_pat(pat); + let some_pat = self.pat_some(e.span, pat); + + self.arm(hir_vec![some_pat], body_expr) + }; - // `::std::option::Option::None => break` - let break_arm = { - let break_expr = self.with_loop_scope(e.id, |this| - this.expr_break(e.span, ThinVec::new())); - let pat = self.pat_none(e.span); - self.arm(hir_vec![pat], break_expr) - }; + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = self.with_loop_scope(e.id, |this| + this.expr_break(e.span, ThinVec::new())); + let pat = self.pat_none(e.span); + self.arm(hir_vec![pat], break_expr) + }; - // `mut iter` - let iter_pat = self.pat_ident_binding_mode(e.span, iter, - hir::BindByValue(hir::MutMutable)); + // `mut iter` + let iter_pat = self.pat_ident_binding_mode(e.span, iter, + hir::BindByValue(hir::MutMutable)); + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let iter = P(self.expr_ident(e.span, iter, iter_pat.id)); + let ref_mut_iter = self.expr_mut_addr_of(e.span, iter); + let next_path = &["iter", "Iterator", "next"]; + let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new())); + let next_expr = P(self.expr_call(e.span, next_path, + hir_vec![ref_mut_iter])); + let arms = hir_vec![pat_arm, break_arm]; - // `match ::std::iter::Iterator::next(&mut iter) { ... }` - let match_expr = { - let iter = P(self.expr_ident(e.span, iter, iter_pat.id)); - let ref_mut_iter = self.expr_mut_addr_of(e.span, iter); - let next_path = &["iter", "Iterator", "next"]; - let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new())); - let next_expr = P(self.expr_call(e.span, next_path, - hir_vec![ref_mut_iter])); - let arms = hir_vec![pat_arm, break_arm]; + P(self.expr(e.span, + hir::ExprMatch(next_expr, arms, + hir::MatchSource::ForLoopDesugar), + ThinVec::new())) + }; - P(self.expr(e.span, - hir::ExprMatch(next_expr, arms, - hir::MatchSource::ForLoopDesugar), - ThinVec::new())) - }; + // `[opt_ident]: loop { ... }` + let loop_block = P(self.block_expr(match_expr)); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), + hir::LoopSource::ForLoop); + let loop_expr = P(hir::Expr { + id: self.lower_node_id(e.id), + node: loop_expr, + span: e.span, + attrs: ThinVec::new(), + }); - // `[opt_ident]: loop { ... }` - let loop_block = P(self.block_expr(match_expr)); - let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), - hir::LoopSource::ForLoop); - let loop_expr = P(hir::Expr { - id: e.id, - node: loop_expr, - span: e.span, - attrs: ThinVec::new(), - }); - - // `mut iter => { ... }` - let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); - - // `match ::std::iter::IntoIterator::into_iter() { ... }` - let into_iter_expr = { - let into_iter_path = &["iter", "IntoIterator", "into_iter"]; - let into_iter = P(self.expr_std_path(e.span, into_iter_path, - ThinVec::new())); - P(self.expr_call(e.span, into_iter, hir_vec![head])) - }; + // `mut iter => { ... }` + let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); - let match_expr = P(self.expr_match(e.span, - into_iter_expr, - hir_vec![iter_arm], - hir::MatchSource::ForLoopDesugar)); - - // `{ let _result = ...; _result }` - // underscore prevents an unused_variables lint if the head diverges - let result_ident = self.str_to_ident("_result"); - let (let_stmt, let_stmt_binding) = - self.stmt_let(e.span, false, result_ident, match_expr); - - let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); - let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); - // add the attributes to the outer returned expr node - return self.expr_block(block, e.attrs.clone()); - } + // `match ::std::iter::IntoIterator::into_iter() { ... }` + let into_iter_expr = { + let into_iter_path = &["iter", "IntoIterator", "into_iter"]; + let into_iter = P(self.expr_std_path(e.span, into_iter_path, + ThinVec::new())); + P(self.expr_call(e.span, into_iter, hir_vec![head])) + }; - // Desugar ExprKind::Try - // From: `?` - ExprKind::Try(ref sub_expr) => { - // to: - // - // match Carrier::translate() { - // Ok(val) => #[allow(unreachable_code)] val, - // Err(err) => #[allow(unreachable_code)] - // // If there is an enclosing `catch {...}` - // break 'catch_target Carrier::from_error(From::from(err)), - // // Otherwise - // return Carrier::from_error(From::from(err)), - // } + let match_expr = P(self.expr_match(e.span, + into_iter_expr, + hir_vec![iter_arm], + hir::MatchSource::ForLoopDesugar)); + + // `{ let _result = ...; _result }` + // underscore prevents an unused_variables lint if the head diverges + let result_ident = self.str_to_ident("_result"); + let (let_stmt, let_stmt_binding) = + self.stmt_let(e.span, false, result_ident, match_expr); + + let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); + let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); + // add the attributes to the outer returned expr node + return self.expr_block(block, e.attrs.clone()); + } - let unstable_span = self.allow_internal_unstable("?", e.span); + // Desugar ExprKind::Try + // From: `?` + ExprKind::Try(ref sub_expr) => { + // to: + // + // match Carrier::translate() { + // Ok(val) => #[allow(unreachable_code)] val, + // Err(err) => #[allow(unreachable_code)] + // // If there is an enclosing `catch {...}` + // break 'catch_target Carrier::from_error(From::from(err)), + // // Otherwise + // return Carrier::from_error(From::from(err)), + // } - // Carrier::translate() - let discr = { - // expand - let sub_expr = self.lower_expr(sub_expr); + let unstable_span = self.allow_internal_unstable("?", e.span); - let path = &["ops", "Carrier", "translate"]; - let path = P(self.expr_std_path(unstable_span, path, ThinVec::new())); - P(self.expr_call(e.span, path, hir_vec![sub_expr])) + // Carrier::translate() + let discr = { + // expand + let sub_expr = self.lower_expr(sub_expr); + + let path = &["ops", "Carrier", "translate"]; + let path = P(self.expr_std_path(unstable_span, path, ThinVec::new())); + P(self.expr_call(e.span, path, hir_vec![sub_expr])) + }; + + // #[allow(unreachable_code)] + let attr = { + // allow(unreachable_code) + let allow = { + let allow_ident = self.str_to_ident("allow"); + let uc_ident = self.str_to_ident("unreachable_code"); + let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident); + let uc_nested = NestedMetaItemKind::MetaItem(uc_meta_item); + let uc_spanned = respan(e.span, uc_nested); + attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned]) }; + attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow) + }; + let attrs = vec![attr]; + + // Ok(val) => #[allow(unreachable_code)] val, + let ok_arm = { + let val_ident = self.str_to_ident("val"); + let val_pat = self.pat_ident(e.span, val_ident); + let val_expr = P(self.expr_ident_with_attrs(e.span, + val_ident, + val_pat.id, + ThinVec::from(attrs.clone()))); + let ok_pat = self.pat_ok(e.span, val_pat); + + self.arm(hir_vec![ok_pat], val_expr) + }; - // #[allow(unreachable_code)] - let attr = { - // allow(unreachable_code) - let allow = { - let allow_ident = self.str_to_ident("allow"); - let uc_ident = self.str_to_ident("unreachable_code"); - let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident); - let uc_nested = NestedMetaItemKind::MetaItem(uc_meta_item); - let uc_spanned = respan(e.span, uc_nested); - attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned]) - }; - attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow) + // Err(err) => #[allow(unreachable_code)] + // return Carrier::from_error(From::from(err)), + let err_arm = { + let err_ident = self.str_to_ident("err"); + let err_local = self.pat_ident(e.span, err_ident); + let from_expr = { + let path = &["convert", "From", "from"]; + let from = P(self.expr_std_path(e.span, path, ThinVec::new())); + let err_expr = self.expr_ident(e.span, err_ident, err_local.id); + + self.expr_call(e.span, from, hir_vec![err_expr]) }; - let attrs = vec![attr]; - - // Ok(val) => #[allow(unreachable_code)] val, - let ok_arm = { - let val_ident = self.str_to_ident("val"); - let val_pat = self.pat_ident(e.span, val_ident); - let val_expr = P(self.expr_ident_with_attrs(e.span, - val_ident, - val_pat.id, - ThinVec::from(attrs.clone()))); - let ok_pat = self.pat_ok(e.span, val_pat); - - self.arm(hir_vec![ok_pat], val_expr) + let from_err_expr = { + let path = &["ops", "Carrier", "from_error"]; + let from_err = P(self.expr_std_path(unstable_span, path, + ThinVec::new())); + P(self.expr_call(e.span, from_err, hir_vec![from_expr])) }; - // Err(err) => #[allow(unreachable_code)] - // return Carrier::from_error(From::from(err)), - let err_arm = { - let err_ident = self.str_to_ident("err"); - let err_local = self.pat_ident(e.span, err_ident); - let from_expr = { - let path = &["convert", "From", "from"]; - let from = P(self.expr_std_path(e.span, path, ThinVec::new())); - let err_expr = self.expr_ident(e.span, err_ident, err_local.id); - - self.expr_call(e.span, from, hir_vec![err_expr]) - }; - let from_err_expr = { - let path = &["ops", "Carrier", "from_error"]; - let from_err = P(self.expr_std_path(unstable_span, path, - ThinVec::new())); - P(self.expr_call(e.span, from_err, hir_vec![from_expr])) - }; + let thin_attrs = ThinVec::from(attrs); + let catch_scope = self.catch_scopes.last().map(|x| *x); + let ret_expr = if let Some(catch_node) = catch_scope { + P(self.expr( + e.span, + hir::ExprBreak( + hir::Destination { + ident: None, + target_id: hir::ScopeTarget::Block(catch_node), + }, + Some(from_err_expr) + ), + thin_attrs)) + } else { + P(self.expr(e.span, + hir::Expr_::ExprRet(Some(from_err_expr)), + thin_attrs)) + }; - let thin_attrs = ThinVec::from(attrs); - let catch_scope = self.catch_scopes.last().map(|x| *x); - let ret_expr = if let Some(catch_node) = catch_scope { - P(self.expr( - e.span, - hir::ExprBreak( - hir::Destination { - ident: None, - target_id: hir::ScopeTarget::Block(catch_node), - }, - Some(from_err_expr) - ), - thin_attrs)) - } else { - P(self.expr(e.span, - hir::Expr_::ExprRet(Some(from_err_expr)), - thin_attrs)) - }; - let err_pat = self.pat_err(e.span, err_local); - self.arm(hir_vec![err_pat], ret_expr) - }; + let err_pat = self.pat_err(e.span, err_local); + self.arm(hir_vec![err_pat], ret_expr) + }; - return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm], - hir::MatchSource::TryDesugar); - } + hir::ExprMatch(discr, + hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar) + } - ExprKind::Mac(_) => panic!("Shouldn't exist here"), - }, + ExprKind::Mac(_) => panic!("Shouldn't exist here"), + }; + + hir::Expr { + id: self.lower_node_id(e.id), + node: kind, span: e.span, attrs: e.attrs.clone(), } @@ -2203,7 +2416,7 @@ impl<'a> LoweringContext<'a> { node: hir::StmtDecl(P(Spanned { node: hir::DeclLocal(self.lower_local(l)), span: s.span, - }), s.id), + }), self.lower_node_id(s.id)), span: s.span, }, StmtKind::Item(ref it) => { @@ -2213,19 +2426,23 @@ impl<'a> LoweringContext<'a> { node: hir::StmtDecl(P(Spanned { node: hir::DeclItem(item_id), span: s.span, - }), id.take().unwrap_or_else(|| self.next_id())), + }), id.take() + .map(|id| self.lower_node_id(id)) + .unwrap_or_else(|| self.next_id())), span: s.span, }).collect(); } StmtKind::Expr(ref e) => { Spanned { - node: hir::StmtExpr(P(self.lower_expr(e)), s.id), + node: hir::StmtExpr(P(self.lower_expr(e)), + self.lower_node_id(s.id)), span: s.span, } } StmtKind::Semi(ref e) => { Spanned { - node: hir::StmtSemi(P(self.lower_expr(e)), s.id), + node: hir::StmtSemi(P(self.lower_expr(e)), + self.lower_node_id(s.id)), span: s.span, } } @@ -2240,14 +2457,26 @@ impl<'a> LoweringContext<'a> { } } - fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility { + /// If an `explicit_owner` is given, this method allocates the `HirId` in + /// the address space of that item instead of the item currently being + /// lowered. This can happen during `lower_impl_item_ref()` where we need to + /// lower a `Visibility` value although we haven't lowered the owning + /// `ImplItem` in question yet. + fn lower_visibility(&mut self, + v: &Visibility, + explicit_owner: Option) + -> hir::Visibility { match *v { Visibility::Public => hir::Public, Visibility::Crate(_) => hir::Visibility::Crate, Visibility::Restricted { ref path, id } => { hir::Visibility::Restricted { path: P(self.lower_path(id, path, ParamMode::Explicit, true)), - id: id + id: if let Some(owner) = explicit_owner { + self.lower_node_id_with_owner(id, owner) + } else { + self.lower_node_id(id) + } } } Visibility::Inherited => hir::Inherited, diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index bf52a036cc8b6..0f7e54953b052 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -14,8 +14,10 @@ //! There are also some rather random cases (like const initializer //! expressions) that are mostly just leftovers. +use hir; use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::fmt::Write; @@ -121,6 +123,7 @@ pub struct Definitions { table: DefPathTable, node_to_def_index: NodeMap, def_index_to_node: Vec, + pub(super) node_to_hir_id: IndexVec, } /// A unique identifier that we can use to lookup a definition @@ -206,6 +209,23 @@ impl DefPath { s } + /// Returns a string representation of the DefPath without + /// the crate-prefix. This method is useful if you don't have + /// a TyCtxt available. + pub fn to_string_no_crate(&self) -> String { + let mut s = String::with_capacity(self.data.len() * 16); + + for component in &self.data { + write!(s, + "::{}[{}]", + component.data.as_interned_str(), + component.disambiguator) + .unwrap(); + } + + s + } + pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 { debug!("deterministic_hash({:?})", self); let mut state = StableHasher::new(); @@ -275,6 +295,7 @@ impl Definitions { }, node_to_def_index: NodeMap(), def_index_to_node: vec![], + node_to_hir_id: IndexVec::new(), } } @@ -367,6 +388,15 @@ impl Definitions { index } + + /// Initialize the ast::NodeId to HirId mapping once it has been generated during + /// AST to HIR lowering. + pub fn init_node_id_to_hir_id_mapping(&mut self, + mapping: IndexVec) { + assert!(self.node_to_hir_id.is_empty(), + "Trying initialize NodeId -> HirId mapping twice"); + self.node_to_hir_id = mapping; + } } impl DefPathData { diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs new file mode 100644 index 0000000000000..b3cc0c542ef9d --- /dev/null +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -0,0 +1,184 @@ +// Copyright 2017 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 hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use hir::{self, intravisit, HirId, ItemLocalId}; +use syntax::ast::NodeId; +use hir::itemlikevisit::ItemLikeVisitor; +use rustc_data_structures::fx::FxHashMap; + +pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) { + let mut outer_visitor = OuterVisitor { + hir_map: hir_map, + errors: vec![], + }; + + hir_map.dep_graph.with_ignore(|| { + hir_map.krate().visit_all_item_likes(&mut outer_visitor); + if !outer_visitor.errors.is_empty() { + let message = outer_visitor + .errors + .iter() + .fold(String::new(), |s1, s2| s1 + "\n" + s2); + bug!("{}", message); + } + }); +} + +struct HirIdValidator<'a, 'hir: 'a> { + hir_map: &'a hir::map::Map<'hir>, + owner_def_index: Option, + hir_ids_seen: FxHashMap, + errors: Vec, +} + +struct OuterVisitor<'a, 'hir: 'a> { + hir_map: &'a hir::map::Map<'hir>, + errors: Vec, +} + +impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> { + fn new_inner_visitor(&self, + hir_map: &'a hir::map::Map<'hir>) + -> HirIdValidator<'a, 'hir> { + HirIdValidator { + hir_map: hir_map, + owner_def_index: None, + hir_ids_seen: FxHashMap(), + errors: Vec::new(), + } + } +} + +impl<'a, 'hir: 'a> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { + fn visit_item(&mut self, i: &'hir hir::Item) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.id, |this| intravisit::walk_item(this, i)); + self.errors.extend(inner_visitor.errors.drain(..)); + } + + fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.id, |this| intravisit::walk_trait_item(this, i)); + self.errors.extend(inner_visitor.errors.drain(..)); + } + + fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) { + let mut inner_visitor = self.new_inner_visitor(self.hir_map); + inner_visitor.check(i.id, |this| intravisit::walk_impl_item(this, i)); + self.errors.extend(inner_visitor.errors.drain(..)); + } +} + +impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> { + + fn check)>(&mut self, + node_id: NodeId, + walk: F) { + assert!(self.owner_def_index.is_none()); + let owner_def_index = self.hir_map.local_def_id(node_id).index; + self.owner_def_index = Some(owner_def_index); + walk(self); + + if owner_def_index == CRATE_DEF_INDEX { + return + } + + // There's always at least one entry for the owning item itself + let max = self.hir_ids_seen + .keys() + .map(|local_id| local_id.as_usize()) + .max() + .unwrap(); + + if max != self.hir_ids_seen.len() - 1 { + // Collect the missing ItemLocalIds + let missing: Vec<_> = (0 .. max + 1) + .filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId(i as u32))) + .collect(); + + // Try to map those to something more useful + let mut missing_items = vec![]; + + for local_id in missing { + let hir_id = HirId { + owner: owner_def_index, + local_id: ItemLocalId(local_id as u32), + }; + + // We are already in ICE mode here, so doing a linear search + // should be fine. + let (node_id, _) = self.hir_map + .definitions() + .node_to_hir_id + .iter() + .enumerate() + .find(|&(_, &entry)| hir_id == entry) + .unwrap(); + let node_id = NodeId::new(node_id); + missing_items.push(format!("[local_id: {}, node:{}]", + local_id, + self.hir_map.node_to_string(node_id))); + } + + self.errors.push(format!( + "ItemLocalIds not assigned densely in {}. \ + Max ItemLocalId = {}, missing IDs = {:?}", + self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(), + max, + missing_items)); + } + } +} + +impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { + + fn nested_visit_map<'this>(&'this mut self) + -> intravisit::NestedVisitorMap<'this, 'hir> { + intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) + } + + fn visit_id(&mut self, node_id: NodeId) { + let owner = self.owner_def_index.unwrap(); + let stable_id = self.hir_map.definitions().node_to_hir_id[node_id]; + + if stable_id == hir::DUMMY_HIR_ID { + self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}", + node_id, + self.hir_map.node_to_string(node_id))); + } + + if owner != stable_id.owner { + self.errors.push(format!( + "HirIdValidator: The recorded owner of {} is {} instead of {}", + self.hir_map.node_to_string(node_id), + self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(), + self.hir_map.def_path(DefId::local(owner)).to_string_no_crate())); + } + + if let Some(prev) = self.hir_ids_seen.insert(stable_id.local_id, node_id) { + if prev != node_id { + self.errors.push(format!( + "HirIdValidator: Same HirId {}/{} assigned for nodes {} and {}", + self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(), + stable_id.local_id.as_usize(), + self.hir_map.node_to_string(prev), + self.hir_map.node_to_string(node_id))); + } + } + } + + fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) { + // Explicitly do nothing here. ImplItemRefs contain hir::Visibility + // values that actually belong to an ImplItem instead of the ItemImpl + // we are currently in. So for those it's correct that they have a + // different owner. + } +} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5d074903b2b99..3def41fd42566 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -36,6 +36,7 @@ pub mod blocks; mod collector; mod def_collector; pub mod definitions; +mod hir_id_validator; #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { @@ -964,13 +965,17 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, entries, vector_length, (entries as f64 / vector_length as f64) * 100.); } - Map { + let map = Map { forest: forest, dep_graph: forest.dep_graph.clone(), map: map, definitions: definitions, inlined_bodies: RefCell::new(DefIdMap()), - } + }; + + hir_id_validator::check_crate(&map); + + map } /// Identical to the `PpAnn` implementation for `hir::Crate`, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index edcfcffaa03a4..1c79a02d3da0e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -30,7 +30,7 @@ pub use self::Visibility::{Public, Inherited}; pub use self::PathParameters::*; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; @@ -43,6 +43,8 @@ use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; use syntax::util::ThinVec; +use rustc_data_structures::indexed_vec; + use std::collections::BTreeMap; use std::fmt; @@ -73,6 +75,63 @@ pub mod pat_util; pub mod print; pub mod svh; +/// A HirId uniquely identifies a node in the HIR of then current crate. It is +/// composed of the `owner`, which is the DefIndex of the directly enclosing +/// hir::Item, hir::TraitItem, or hir::ImplItem (i.e. the closest "item-like"), +/// and the `local_id` which is unique within the given owner. +/// +/// This two-level structure makes for more stable values: One can move an item +/// around within the source code, or add or remove stuff before it, without +/// the local_id part of the HirId changing, which is a very useful property +/// incremental compilation where we have to persist things through changes to +/// the code base. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, + RustcEncodable, RustcDecodable)] +pub struct HirId { + pub owner: DefIndex, + pub local_id: ItemLocalId, +} + +/// An `ItemLocalId` uniquely identifies something within a given "item-like", +/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no +/// guarantee that the numerical value of a given `ItemLocalId` corresponds to +/// the node's position within the owning item in any way, but there is a +/// guarantee that the `LocalItemId`s within an owner occupy a dense range of +/// integers starting at zero, so a mapping that maps all or most nodes within +/// an "item-like" to something else can be implement by a `Vec` instead of a +/// tree or hash map. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, + RustcEncodable, RustcDecodable)] +pub struct ItemLocalId(pub u32); + +impl ItemLocalId { + pub fn as_usize(&self) -> usize { + self.0 as usize + } +} + +impl indexed_vec::Idx for ItemLocalId { + fn new(idx: usize) -> Self { + debug_assert!((idx as u32) as usize == idx); + ItemLocalId(idx as u32) + } + + fn index(self) -> usize { + self.0 as usize + } +} + +/// The `HirId` corresponding to CRATE_NODE_ID and CRATE_DEF_INDEX +pub const CRATE_HIR_ID: HirId = HirId { + owner: CRATE_DEF_INDEX, + local_id: ItemLocalId(0) +}; + +pub const DUMMY_HIR_ID: HirId = HirId { + owner: CRATE_DEF_INDEX, + local_id: ItemLocalId(!0) +}; + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f60b1d17a5e2f..f0e328a551d5f 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -178,17 +178,9 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { block.stmts = block.stmts.move_flat_map(|mut stmt| { remaining_stmts -= 1; - match stmt.node { - // Avoid wasting a node id on a trailing expression statement, - // which shares a HIR node with the expression itself. - ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, - - _ if self.monotonic => { - assert_eq!(stmt.id, ast::DUMMY_NODE_ID); - stmt.id = self.cx.resolver.next_node_id(); - } - - _ => {} + if self.monotonic { + assert_eq!(stmt.id, ast::DUMMY_NODE_ID); + stmt.id = self.cx.resolver.next_node_id(); } Some(stmt) diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs index 503b577b1f1b4..fd8d5ff9e7ea8 100644 --- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs +++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs @@ -18,7 +18,7 @@ trait SomeTrait { } // Bounds on object types: -struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used +struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used // All of these are ok, because we can derive exactly one bound: a: Box, b: Box>, From 090767b5ef59188e5defb466ff6580b99891f1ed Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 16 Mar 2017 18:17:18 +0100 Subject: [PATCH 210/662] Allocate numerical values of DefIndexes from two seperate ranges. This way we can have all item-likes occupy a dense range of DefIndexes, which is good for making fast, array-based dictionaries. --- src/librustc/hir/def_id.rs | 53 +++++++++++++ src/librustc/hir/lowering.rs | 7 +- src/librustc/hir/map/def_collector.rs | 67 +++++++++++----- src/librustc/hir/map/definitions.rs | 104 ++++++++++++++++++------- src/librustc/hir/map/mod.rs | 9 +-- src/librustc_metadata/index.rs | 67 ++++++++++++---- src/librustc_metadata/index_builder.rs | 2 +- 7 files changed, 237 insertions(+), 72 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index cbf162cc1366e..a6b18ac10a790 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -78,33 +78,86 @@ impl serialize::UseSpecializedDecodable for CrateNum { /// A DefIndex is an index into the hir-map for a crate, identifying a /// particular definition. It should really be considered an interned /// shorthand for a particular DefPath. +/// +/// At the moment we are allocating the numerical values of DefIndexes into two +/// ranges: the "low" range (starting at zero) and the "high" range (starting at +/// DEF_INDEX_HI_START). This allows us to allocate the DefIndexes of all +/// item-likes (Items, TraitItems, and ImplItems) into one of these ranges and +/// consequently use a simple array for lookup tables keyed by DefIndex and +/// known to be densely populated. This is especially important for the HIR map. +/// +/// Since the DefIndex is mostly treated as an opaque ID, you probably +/// don't have to care about these ranges. #[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct DefIndex(u32); impl DefIndex { + #[inline] pub fn new(x: usize) -> DefIndex { assert!(x < (u32::MAX as usize)); DefIndex(x as u32) } + #[inline] pub fn from_u32(x: u32) -> DefIndex { DefIndex(x) } + #[inline] pub fn as_usize(&self) -> usize { self.0 as usize } + #[inline] pub fn as_u32(&self) -> u32 { self.0 } + + #[inline] + pub fn address_space(&self) -> DefIndexAddressSpace { + if self.0 < DEF_INDEX_HI_START.0 { + DefIndexAddressSpace::Low + } else { + DefIndexAddressSpace::High + } + } + + /// Converts this DefIndex into a zero-based array index. + /// This index is the offset within the given "range" of the DefIndex, + /// that is, if the DefIndex is part of the "high" range, the resulting + /// index will be (DefIndex - DEF_INDEX_HI_START). + #[inline] + pub fn as_array_index(&self) -> usize { + (self.0 & !DEF_INDEX_HI_START.0) as usize + } } +/// The start of the "high" range of DefIndexes. +const DEF_INDEX_HI_START: DefIndex = DefIndex(1 << 31); + /// The crate root is always assigned index 0 by the AST Map code, /// thanks to `NodeCollector::new`. pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0); +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub enum DefIndexAddressSpace { + Low = 0, + High = 1, +} + +impl DefIndexAddressSpace { + #[inline] + pub fn index(&self) -> usize { + *self as usize + } + + #[inline] + pub fn start(&self) -> usize { + self.index() * DEF_INDEX_HI_START.as_usize() + } +} + /// A DefId identifies a particular *definition*, by combining a crate /// index and a def index. #[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)] diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 22ca0e421be85..2ac1a036f99e1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -41,7 +41,7 @@ // in the HIR, especially for multiple identifiers. use hir; -use hir::map::{Definitions, DefKey}; +use hir::map::{Definitions, DefKey, REGULAR_SPACE}; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX}; use hir::def::{Def, PathResolution}; @@ -2711,7 +2711,10 @@ impl<'a> LoweringContext<'a> { let def_id = { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); - let def_index = defs.create_def_with_parent(parent_def, id, def_path_data); + let def_index = defs.create_def_with_parent(parent_def, + id, + def_path_data, + REGULAR_SPACE); DefId::local(def_index) }; diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index f15e063e81e33..cae358a303e02 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -9,13 +9,15 @@ // except according to those terms. use hir::map::definitions::*; -use hir::def_id::{CRATE_DEF_INDEX, DefIndex}; +use hir::def_id::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace}; use syntax::ast::*; use syntax::ext::hygiene::Mark; use syntax::visit; use syntax::symbol::{Symbol, keywords}; +use hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE}; + /// Creates def ids for nodes in the AST. pub struct DefCollector<'a> { definitions: &'a mut Definitions, @@ -39,23 +41,31 @@ impl<'a> DefCollector<'a> { } pub fn collect_root(&mut self) { - let root = self.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot); + let root = self.create_def_with_parent(None, + CRATE_NODE_ID, + DefPathData::CrateRoot, + ITEM_LIKE_SPACE); assert_eq!(root, CRATE_DEF_INDEX); self.parent_def = Some(root); } - fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex { + fn create_def(&mut self, + node_id: NodeId, + data: DefPathData, + address_space: DefIndexAddressSpace) + -> DefIndex { let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.definitions.create_def_with_parent(parent_def, node_id, data) + self.definitions.create_def_with_parent(parent_def, node_id, data, address_space) } fn create_def_with_parent(&mut self, parent: Option, node_id: NodeId, - data: DefPathData) + data: DefPathData, + address_space: DefIndexAddressSpace) -> DefIndex { - self.definitions.create_def_with_parent(parent, node_id, data) + self.definitions.create_def_with_parent(parent, node_id, data, address_space) } pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { @@ -76,7 +86,7 @@ impl<'a> DefCollector<'a> { _ => {} } - self.create_def(expr.id, DefPathData::Initializer); + self.create_def(expr.id, DefPathData::Initializer, REGULAR_SPACE); } fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) { @@ -118,14 +128,16 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ViewPathSimple(..) => {} ViewPathList(_, ref imports) => { for import in imports { - self.create_def(import.node.id, DefPathData::Misc); + self.create_def(import.node.id, + DefPathData::Misc, + ITEM_LIKE_SPACE); } } } DefPathData::Misc } }; - let def = self.create_def(i.id, def_data); + let def = self.create_def(i.id, def_data, ITEM_LIKE_SPACE); self.with_parent(def, |this| { match i.node { @@ -133,12 +145,15 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { for v in &enum_definition.variants { let variant_def_index = this.create_def(v.node.data.id(), - DefPathData::EnumVariant(v.node.name.name.as_str())); + DefPathData::EnumVariant(v.node.name.name.as_str()), + REGULAR_SPACE); this.with_parent(variant_def_index, |this| { for (index, field) in v.node.data.fields().iter().enumerate() { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| Symbol::intern(&index.to_string())); - this.create_def(field.id, DefPathData::Field(name.as_str())); + this.create_def(field.id, + DefPathData::Field(name.as_str()), + REGULAR_SPACE); } if let Some(ref expr) = v.node.disr_expr { @@ -151,13 +166,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // If this is a tuple-like struct, register the constructor. if !struct_def.is_struct() { this.create_def(struct_def.id(), - DefPathData::StructCtor); + DefPathData::StructCtor, + REGULAR_SPACE); } for (index, field) in struct_def.fields().iter().enumerate() { let name = field.ident.map(|ident| ident.name.as_str()) .unwrap_or(Symbol::intern(&index.to_string()).as_str()); - this.create_def(field.id, DefPathData::Field(name)); + this.create_def(field.id, DefPathData::Field(name), REGULAR_SPACE); } } _ => {} @@ -168,7 +184,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { let def = self.create_def(foreign_item.id, - DefPathData::ValueNs(foreign_item.ident.name.as_str())); + DefPathData::ValueNs(foreign_item.ident.name.as_str()), + REGULAR_SPACE); self.with_parent(def, |this| { visit::walk_foreign_item(this, foreign_item); @@ -177,7 +194,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_generics(&mut self, generics: &'a Generics) { for ty_param in generics.ty_params.iter() { - self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str())); + self.create_def(ty_param.id, + DefPathData::TypeParam(ty_param.ident.name.as_str()), + REGULAR_SPACE); } visit::walk_generics(self, generics); @@ -191,7 +210,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false), }; - let def = self.create_def(ti.id, def_data); + let def = self.create_def(ti.id, def_data, ITEM_LIKE_SPACE); self.with_parent(def, |this| { if let TraitItemKind::Const(_, Some(ref expr)) = ti.node { this.visit_const_expr(expr); @@ -209,7 +228,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false), }; - let def = self.create_def(ii.id, def_data); + let def = self.create_def(ii.id, def_data, ITEM_LIKE_SPACE); self.with_parent(def, |this| { if let ImplItemKind::Const(_, ref expr) = ii.node { this.visit_const_expr(expr); @@ -225,7 +244,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { match pat.node { PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false), PatKind::Ident(_, id, _) => { - let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str())); + let def = self.create_def(pat.id, + DefPathData::Binding(id.node.name.as_str()), + REGULAR_SPACE); self.parent_def = Some(def); } _ => {} @@ -242,7 +263,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false), ExprKind::Repeat(_, ref count) => self.visit_const_expr(count), ExprKind::Closure(..) => { - let def = self.create_def(expr.id, DefPathData::ClosureExpr); + let def = self.create_def(expr.id, + DefPathData::ClosureExpr, + REGULAR_SPACE); self.parent_def = Some(def); } _ => {} @@ -257,7 +280,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false), TyKind::Array(_, ref length) => self.visit_const_expr(length), TyKind::ImplTrait(..) => { - self.create_def(ty.id, DefPathData::ImplTrait); + self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE); } TyKind::Typeof(ref expr) => self.visit_const_expr(expr), _ => {} @@ -266,7 +289,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) { - self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); + self.create_def(def.lifetime.id, + DefPathData::LifetimeDef(def.lifetime.name.as_str()), + REGULAR_SPACE); } fn visit_stmt(&mut self, stmt: &'a Stmt) { diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 0f7e54953b052..809d5db3071d7 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -15,7 +15,7 @@ //! expressions) that are mostly just leftovers. use hir; -use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::StableHasher; @@ -31,24 +31,44 @@ use util::nodemap::NodeMap; /// Internally the DefPathTable holds a tree of DefKeys, where each DefKey /// stores the DefIndex of its parent. /// There is one DefPathTable for each crate. -#[derive(Clone)] pub struct DefPathTable { - index_to_key: Vec, + index_to_key: [Vec; 2], key_to_index: FxHashMap, } +// Unfortunately we have to provide a manual impl of Clone because of the +// fixed-sized array field. +impl Clone for DefPathTable { + fn clone(&self) -> Self { + DefPathTable { + index_to_key: [self.index_to_key[0].clone(), + self.index_to_key[1].clone()], + key_to_index: self.key_to_index.clone(), + } + } +} + impl DefPathTable { - fn insert(&mut self, key: DefKey) -> DefIndex { - let index = DefIndex::new(self.index_to_key.len()); - debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); - self.index_to_key.push(key.clone()); + + fn allocate(&mut self, + key: DefKey, + address_space: DefIndexAddressSpace) + -> DefIndex { + let index = { + let index_to_key = &mut self.index_to_key[address_space.index()]; + let index = DefIndex::new(index_to_key.len() + address_space.start()); + debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); + index_to_key.push(key.clone()); + index + }; self.key_to_index.insert(key, index); index } #[inline(always)] pub fn def_key(&self, index: DefIndex) -> DefKey { - self.index_to_key[index.as_usize()].clone() + self.index_to_key[index.address_space().index()] + [index.as_array_index()].clone() } #[inline(always)] @@ -96,17 +116,28 @@ impl DefPathTable { impl Encodable for DefPathTable { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.index_to_key.encode(s) + self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?; + self.index_to_key[DefIndexAddressSpace::High.index()].encode(s) } } impl Decodable for DefPathTable { fn decode(d: &mut D) -> Result { - let index_to_key: Vec = Decodable::decode(d)?; - let key_to_index = index_to_key.iter() - .enumerate() - .map(|(index, key)| (key.clone(), DefIndex::new(index))) - .collect(); + let index_to_key_lo: Vec = Decodable::decode(d)?; + let index_to_key_high: Vec = Decodable::decode(d)?; + + let index_to_key = [index_to_key_lo, index_to_key_high]; + + let mut key_to_index = FxHashMap(); + + for space in &[DefIndexAddressSpace::Low, DefIndexAddressSpace::High] { + key_to_index.extend(index_to_key[space.index()] + .iter() + .enumerate() + .map(|(index, key)| (key.clone(), + DefIndex::new(index + space.start())))) + } + Ok(DefPathTable { index_to_key: index_to_key, key_to_index: key_to_index, @@ -118,14 +149,29 @@ impl Decodable for DefPathTable { /// The definition table containing node definitions. /// It holds the DefPathTable for local DefIds/DefPaths and it also stores a /// mapping from NodeIds to local DefIds. -#[derive(Clone)] pub struct Definitions { table: DefPathTable, node_to_def_index: NodeMap, - def_index_to_node: Vec, + def_index_to_node: [Vec; 2], pub(super) node_to_hir_id: IndexVec, } +// Unfortunately we have to provide a manual impl of Clone because of the +// fixed-sized array field. +impl Clone for Definitions { + fn clone(&self) -> Self { + Definitions { + table: self.table.clone(), + node_to_def_index: self.node_to_def_index.clone(), + def_index_to_node: [ + self.def_index_to_node[0].clone(), + self.def_index_to_node[1].clone(), + ], + node_to_hir_id: self.node_to_hir_id.clone(), + } + } +} + /// A unique identifier that we can use to lookup a definition /// precisely. It combines the index of the definition's parent (if /// any) with a `DisambiguatedDefPathData`. @@ -290,11 +336,11 @@ impl Definitions { pub fn new() -> Definitions { Definitions { table: DefPathTable { - index_to_key: vec![], + index_to_key: [vec![], vec![]], key_to_index: FxHashMap(), }, node_to_def_index: NodeMap(), - def_index_to_node: vec![], + def_index_to_node: [vec![], vec![]], node_to_hir_id: IndexVec::new(), } } @@ -304,8 +350,9 @@ impl Definitions { } /// Get the number of definitions. - pub fn len(&self) -> usize { - self.def_index_to_node.len() + pub fn def_index_counts_lo_hi(&self) -> (usize, usize) { + (self.def_index_to_node[DefIndexAddressSpace::Low.index()].len(), + self.def_index_to_node[DefIndexAddressSpace::High.index()].len()) } pub fn def_key(&self, index: DefIndex) -> DefKey { @@ -339,8 +386,9 @@ impl Definitions { pub fn as_local_node_id(&self, def_id: DefId) -> Option { if def_id.krate == LOCAL_CRATE { - assert!(def_id.index.as_usize() < self.def_index_to_node.len()); - Some(self.def_index_to_node[def_id.index.as_usize()]) + let space_index = def_id.index.address_space().index(); + let array_index = def_id.index.as_array_index(); + Some(self.def_index_to_node[space_index][array_index]) } else { None } @@ -350,7 +398,9 @@ impl Definitions { pub fn create_def_with_parent(&mut self, parent: Option, node_id: ast::NodeId, - data: DefPathData) + data: DefPathData, + // is_owner: bool) + address_space: DefIndexAddressSpace) -> DefIndex { debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})", parent, node_id, data); @@ -380,11 +430,13 @@ impl Definitions { debug!("create_def_with_parent: after disambiguation, key = {:?}", key); // Create the definition. - let index = self.table.insert(key); + let index = self.table.allocate(key, address_space); + assert_eq!(index.as_array_index(), + self.def_index_to_node[address_space.index()].len()); + self.def_index_to_node[address_space.index()].push(node_id); + debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id); self.node_to_def_index.insert(node_id, index); - assert_eq!(index.as_usize(), self.def_index_to_node.len()); - self.def_index_to_node.push(node_id); index } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 3def41fd42566..583b3b848f30d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -17,7 +17,7 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, use dep_graph::{DepGraph, DepNode}; -use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; +use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex, DefIndexAddressSpace}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; @@ -38,6 +38,9 @@ mod def_collector; pub mod definitions; mod hir_id_validator; +pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low; +pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; + #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { NodeItem(&'hir Item), @@ -347,10 +350,6 @@ impl<'hir> Map<'hir> { } } - pub fn num_local_def_ids(&self) -> usize { - self.definitions.len() - } - pub fn definitions(&self) -> &Definitions { &self.definitions } diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index db9fc870fa86a..970a401177ba5 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -10,7 +10,7 @@ use schema::*; -use rustc::hir::def_id::{DefId, DefIndex}; +use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace}; use std::io::{Cursor, Write}; use std::slice; use std::u32; @@ -23,12 +23,15 @@ use std::u32; /// appropriate spot by calling `record_position`. We should never /// visit the same index twice. pub struct Index { - positions: Vec, + positions: [Vec; 2] } impl Index { - pub fn new(max_index: usize) -> Index { - Index { positions: vec![u32::MAX; max_index] } + pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index { + Index { + positions: [vec![u32::MAX; max_index_lo], + vec![u32::MAX; max_index_hi]], + } } pub fn record(&mut self, def_id: DefId, entry: Lazy) { @@ -37,24 +40,31 @@ impl Index { } pub fn record_index(&mut self, item: DefIndex, entry: Lazy) { - let item = item.as_usize(); - assert!(entry.position < (u32::MAX as usize)); let position = entry.position as u32; + let space_index = item.address_space().index(); + let array_index = item.as_array_index(); - assert!(self.positions[item] == u32::MAX, + assert!(self.positions[space_index][array_index] == u32::MAX, "recorded position for item {:?} twice, first at {:?} and now at {:?}", item, - self.positions[item], + self.positions[space_index][array_index], position); - self.positions[item] = position.to_le(); + self.positions[space_index][array_index] = position.to_le(); } pub fn write_index(&self, buf: &mut Cursor>) -> LazySeq { let pos = buf.position(); - buf.write_all(words_to_bytes(&self.positions)).unwrap(); - LazySeq::with_position_and_length(pos as usize, self.positions.len()) + + // First we write the length of the lower range ... + buf.write_all(words_to_bytes(&[self.positions[0].len() as u32])).unwrap(); + // ... then the values in the lower range ... + buf.write_all(words_to_bytes(&self.positions[0][..])).unwrap(); + // ... then the values in the higher range. + buf.write_all(words_to_bytes(&self.positions[1][..])).unwrap(); + LazySeq::with_position_and_length(pos as usize, + self.positions[0].len() + self.positions[1].len() + 1) } } @@ -70,7 +80,18 @@ impl<'tcx> LazySeq { index, words.len()); - let position = u32::from_le(words[index].get()); + let positions = match def_index.address_space() { + DefIndexAddressSpace::Low => &words[1..], + DefIndexAddressSpace::High => { + // This is a DefIndex in the higher range, so find out where + // that starts: + let lo_count = u32::from_le(words[0].get()) as usize; + &words[lo_count + 1 .. ] + } + }; + + let array_index = def_index.as_array_index(); + let position = u32::from_le(positions[array_index].get()); if position == u32::MAX { debug!("Index::lookup: position=u32::MAX"); None @@ -84,14 +105,26 @@ impl<'tcx> LazySeq { bytes: &'a [u8]) -> impl Iterator>)> + 'a { let words = &bytes_to_words(&bytes[self.position..])[..self.len]; - words.iter().map(|word| word.get()).enumerate().filter_map(|(index, position)| { - if position == u32::MAX { + let lo_count = u32::from_le(words[0].get()) as usize; + let lo = &words[1 .. lo_count + 1]; + let hi = &words[1 + lo_count ..]; + + lo.iter().map(|word| word.get()).enumerate().filter_map(|(index, pos)| { + if pos == u32::MAX { + None + } else { + let pos = u32::from_le(pos) as usize; + Some((DefIndex::new(index), Lazy::with_position(pos))) + } + }).chain(hi.iter().map(|word| word.get()).enumerate().filter_map(|(index, pos)| { + if pos == u32::MAX { None } else { - let position = u32::from_le(position) as usize; - Some((DefIndex::new(index), Lazy::with_position(position))) + let pos = u32::from_le(pos) as usize; + Some((DefIndex::new(index + DefIndexAddressSpace::High.start()), + Lazy::with_position(pos))) } - }) + })) } } diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 2359c747d888d..a811f72bc956c 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -90,7 +90,7 @@ impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { IndexBuilder { - items: Index::new(ecx.tcx.hir.num_local_def_ids()), + items: Index::new(ecx.tcx.hir.definitions().def_index_counts_lo_hi()), ecx: ecx, } } From d6da1d9b46f7090b18be357bef8d55ffa3673d2f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 22 Mar 2017 01:42:23 +0100 Subject: [PATCH 211/662] Various fixes to wording consistency in the docs --- src/libcollections/binary_heap.rs | 4 ++-- src/libcollections/btree/map.rs | 4 ++-- src/libcollections/btree/set.rs | 2 +- src/libcollections/enum_set.rs | 2 +- src/libcollections/range.rs | 8 +++---- src/libcollections/slice.rs | 37 +++++++++++++++---------------- src/libcollections/str.rs | 2 +- src/libcollections/vec_deque.rs | 4 ++-- src/libcore/any.rs | 2 +- src/libcore/cmp.rs | 6 ++--- src/libcore/iter_private.rs | 2 +- src/libcore/num/bignum.rs | 6 ++--- src/libcore/num/mod.rs | 8 +++---- src/libcore/ptr.rs | 4 ++-- src/libcore/result.rs | 4 ++-- src/libcore/slice/mod.rs | 10 ++++----- src/libcore/slice/sort.rs | 4 ++-- src/libcore/str/mod.rs | 14 ++++++------ 18 files changed, 61 insertions(+), 62 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 519117ff9e519..efa96ca468e01 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -930,13 +930,13 @@ impl<'a, T> Hole<'a, T> { self.pos } - /// Return a reference to the element removed + /// Returns a reference to the element removed. #[inline] fn element(&self) -> &T { self.elt.as_ref().unwrap() } - /// Return a reference to the element at `index`. + /// Returns a reference to the element at `index`. /// /// Unsafe because index must be within the data slice and not equal to pos. #[inline] diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 53fe6b4bc9f4f..bed216ba3d111 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -526,7 +526,7 @@ impl BTreeMap { } } - /// Returns true if the map contains a value for the specified key. + /// Returns `true` if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. @@ -1965,7 +1965,7 @@ impl BTreeMap { self.length } - /// Returns true if the map contains no elements. + /// Returns `true` if the map contains no elements. /// /// # Examples /// diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 72d25f87bca95..9dbb61379379e 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -415,7 +415,7 @@ impl BTreeSet { self.map.len() } - /// Returns true if the set contains no elements. + /// Returns `true` if the set contains no elements. /// /// # Examples /// diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 602e874aaeec0..e56b94b2e1ea2 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -106,7 +106,7 @@ impl EnumSet { self.bits.count_ones() as usize } - /// Returns true if the `EnumSet` is empty. + /// Returns `true` if the `EnumSet` is empty. pub fn is_empty(&self) -> bool { self.bits == 0 } diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 31e4d001397bf..d10ca087f93e7 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -20,9 +20,9 @@ use Bound::{self, Excluded, Included, Unbounded}; /// **RangeArgument** is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. pub trait RangeArgument { - /// Start index bound + /// Start index bound. /// - /// Return start value as a `Bound` + /// Returns start value as a `Bound`. /// /// # Examples /// @@ -42,9 +42,9 @@ pub trait RangeArgument { /// ``` fn start(&self) -> Bound<&T>; - /// End index bound + /// End index bound. /// - /// Return end value as a `Bound` + /// Returns end value as a `Bound`. /// /// # Examples /// diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 5233887620a91..d3723ace9efb3 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -195,7 +195,7 @@ impl [T] { core_slice::SliceExt::is_empty(self) } - /// Returns the first element of a slice, or `None` if it is empty. + /// Returns the first element of the slice, or `None` if it is empty. /// /// # Examples /// @@ -212,7 +212,7 @@ impl [T] { core_slice::SliceExt::first(self) } - /// Returns a mutable pointer to the first element of a slice, or `None` if it is empty. + /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. /// /// # Examples /// @@ -230,7 +230,7 @@ impl [T] { core_slice::SliceExt::first_mut(self) } - /// Returns the first and all the rest of the elements of a slice, or `None` if it is empty. + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. /// /// # Examples /// @@ -248,7 +248,7 @@ impl [T] { core_slice::SliceExt::split_first(self) } - /// Returns the first and all the rest of the elements of a slice, or `None` if it is empty. + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. /// /// # Examples /// @@ -268,7 +268,7 @@ impl [T] { core_slice::SliceExt::split_first_mut(self) } - /// Returns the last and all the rest of the elements of a slice, or `None` if it is empty. + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. /// /// # Examples /// @@ -287,7 +287,7 @@ impl [T] { } - /// Returns the last and all the rest of the elements of a slice, or `None` if it is empty. + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. /// /// # Examples /// @@ -307,7 +307,7 @@ impl [T] { core_slice::SliceExt::split_last_mut(self) } - /// Returns the last element of a slice, or `None` if it is empty. + /// Returns the last element of the slice, or `None` if it is empty. /// /// # Examples /// @@ -485,7 +485,7 @@ impl [T] { core_slice::SliceExt::as_mut_ptr(self) } - /// Swaps two elements in a slice. + /// Swaps two elements in the slice. /// /// # Arguments /// @@ -509,7 +509,7 @@ impl [T] { core_slice::SliceExt::swap(self, a, b) } - /// Reverses the order of elements in a slice, in place. + /// Reverses the order of elements in the slice, in place. /// /// # Example /// @@ -955,7 +955,7 @@ impl [T] { core_slice::SliceExt::ends_with(self, needle) } - /// Binary search a sorted slice for a given element. + /// Binary searches this sorted slice for a given element. /// /// If the value is found then `Ok` is returned, containing the /// index of the matching element; if the value is not found then @@ -984,7 +984,7 @@ impl [T] { core_slice::SliceExt::binary_search(self, x) } - /// Binary search a sorted slice with a comparator function. + /// Binary searches this sorted slice with a comparator function. /// /// The comparator function should implement an order consistent /// with the sort order of the underlying slice, returning an @@ -1023,7 +1023,7 @@ impl [T] { core_slice::SliceExt::binary_search_by(self, f) } - /// Binary search a sorted slice with a key extraction function. + /// Binary searches this sorted slice with a key extraction function. /// /// Assumes that the slice is sorted by the key, for instance with /// [`sort_by_key`] using the same key extraction function. @@ -1092,7 +1092,7 @@ impl [T] { merge_sort(self, |a, b| a.lt(b)); } - /// Sorts the slice using `compare` to compare elements. + /// Sorts the slice with a comparator function. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. /// @@ -1125,7 +1125,7 @@ impl [T] { merge_sort(self, |a, b| compare(a, b) == Less); } - /// Sorts the slice using `f` to extract a key to compare elements by. + /// Sorts the slice with a key extraction function. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. /// @@ -1191,8 +1191,8 @@ impl [T] { core_slice::SliceExt::sort_unstable(self); } - /// Sorts the slice using `compare` to compare elements, but may not preserve the order of - /// equal elements. + /// Sorts the slice with a comparator function, but may not preserve the order of equal + /// elements. /// /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), /// and `O(n log n)` worst-case. @@ -1231,8 +1231,8 @@ impl [T] { core_slice::SliceExt::sort_unstable_by(self, compare); } - /// Sorts the slice using `f` to extract a key to compare elements by, but may not preserve the - /// order of equal elements. + /// Sorts the slice with a key extraction function, but may not preserve the order of equal + /// elements. /// /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), /// and `O(n log n)` worst-case. @@ -1313,7 +1313,6 @@ impl [T] { core_slice::SliceExt::copy_from_slice(self, src) } - /// Copies `self` into a new `Vec`. /// /// # Examples diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 90e54a383d623..8abc9ca7e9fe8 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -204,7 +204,7 @@ impl str { core_str::StrExt::len(self) } - /// Returns true if this slice has a length of zero bytes. + /// Returns `true` if `self` has a length of zero bytes. /// /// # Examples /// diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 6a04d47a345e8..cb92236ec736c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -133,7 +133,7 @@ impl VecDeque { ptr::write(self.ptr().offset(off as isize), value); } - /// Returns true if and only if the buffer is at capacity + /// Returns `true` if and only if the buffer is at full capacity. #[inline] fn is_full(&self) -> bool { self.cap() - self.len() == 1 @@ -788,7 +788,7 @@ impl VecDeque { count(self.tail, self.head, self.cap()) } - /// Returns true if the buffer contains no elements + /// Returns `true` if the `VecDeque` is empty. /// /// # Examples /// diff --git a/src/libcore/any.rs b/src/libcore/any.rs index b8a4174766a78..338e5c7fd95b4 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -137,7 +137,7 @@ impl fmt::Debug for Any + Send { } impl Any { - /// Returns true if the boxed type is the same as `T`. + /// Returns `true` if the boxed type is the same as `T`. /// /// # Examples /// diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index cb39796eecd7d..7db35359a1f7d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -210,7 +210,7 @@ pub enum Ordering { } impl Ordering { - /// Reverse the `Ordering`. + /// Reverses the `Ordering`. /// /// * `Less` becomes `Greater`. /// * `Greater` becomes `Less`. @@ -616,7 +616,7 @@ pub trait PartialOrd: PartialEq { } } -/// Compare and return the minimum of two values. +/// Compares and returns the minimum of two values. /// /// Returns the first argument if the comparison determines them to be equal. /// @@ -634,7 +634,7 @@ pub fn min(v1: T, v2: T) -> T { if v1 <= v2 { v1 } else { v2 } } -/// Compare and return the maximum of two values. +/// Compares and returns the maximum of two values. /// /// Returns the second argument if the comparison determines them to be equal. /// diff --git a/src/libcore/iter_private.rs b/src/libcore/iter_private.rs index bc1aaa09f3dbd..c4d54d2c7b81d 100644 --- a/src/libcore/iter_private.rs +++ b/src/libcore/iter_private.rs @@ -22,7 +22,7 @@ #[doc(hidden)] pub unsafe trait TrustedRandomAccess : ExactSizeIterator { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; - /// Return `true` if getting an iterator element may have + /// Returns `true` if getting an iterator element may have /// side effects. Remember to take inner iterators into account. fn may_have_side_effect() -> bool; } diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index a1f4630c304bf..8904322ca48f7 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -148,14 +148,14 @@ macro_rules! define_bignum { $name { size: sz, base: base } } - /// Return the internal digits as a slice `[a, b, c, ...]` such that the numeric + /// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric /// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in /// the digit type. pub fn digits(&self) -> &[$ty] { &self.base[..self.size] } - /// Return the `i`-th bit where bit 0 is the least significant one. + /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. pub fn get_bit(&self, i: usize) -> u8 { use mem; @@ -166,7 +166,7 @@ macro_rules! define_bignum { ((self.base[d] >> b) & 1) as u8 } - /// Returns true if the bignum is zero. + /// Returns `true` if the bignum is zero. pub fn is_zero(&self) -> bool { self.digits().iter().all(|&v| v == 0) } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ccfe6364e6af6..df343c9d45f20 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2568,17 +2568,17 @@ pub trait Float: Sized { implementable outside the standard library")] fn one() -> Self; - /// Returns true if this value is NaN and false otherwise. + /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; - /// Returns true if this value is positive infinity or negative infinity and + /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_infinite(self) -> bool; - /// Returns true if this number is neither infinite nor NaN. + /// Returns `true` if this number is neither infinite nor NaN. #[stable(feature = "core", since = "1.6.0")] fn is_finite(self) -> bool; - /// Returns true if this number is neither zero, infinite, denormal, or NaN. + /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. #[stable(feature = "core", since = "1.6.0")] fn is_normal(self) -> bool; /// Returns the category that this number falls into. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 98544f8ba5e73..d2830a6d00cec 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -380,7 +380,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { #[lang = "const_ptr"] impl *const T { - /// Returns true if the pointer is null. + /// Returns `true` if the pointer is null. /// /// # Examples /// @@ -504,7 +504,7 @@ impl *const T { #[lang = "mut_ptr"] impl *mut T { - /// Returns true if the pointer is null. + /// Returns `true` if the pointer is null. /// /// # Examples /// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 00ff2fd2ce5ef..6ec8a37dfa433 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -268,7 +268,7 @@ impl Result { // Querying the contained values ///////////////////////////////////////////////////////////////////////// - /// Returns true if the result is `Ok`. + /// Returns `true` if the result is `Ok`. /// /// # Examples /// @@ -290,7 +290,7 @@ impl Result { } } - /// Returns true if the result is `Err`. + /// Returns `true` if the result is `Err`. /// /// # Examples /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f8b199f886b7..af492b3c63976 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1511,7 +1511,7 @@ fn ptrdistance(start: *const T, end: *const T) -> usize { trait PointerExt : Copy { unsafe fn slice_offset(self, i: isize) -> Self; - /// Increment self by 1, but return the old value + /// Increments `self` by 1, but returns the old value. #[inline(always)] unsafe fn post_inc(&mut self) -> Self { let current = *self; @@ -1519,7 +1519,7 @@ trait PointerExt : Copy { current } - /// Decrement self by 1, and return the new value + /// Decrements `self` by 1, and returns the new value. #[inline(always)] unsafe fn pre_dec(&mut self) -> Self { *self = self.slice_offset(-1); @@ -1545,7 +1545,7 @@ impl PointerExt for *mut T { /// splitn, splitn_mut etc can be implemented once. #[doc(hidden)] trait SplitIter: DoubleEndedIterator { - /// Mark the underlying iterator as complete, extracting the remaining + /// Marks the underlying iterator as complete, extracting the remaining /// portion of the slice. fn finish(&mut self) -> Option; } @@ -2267,11 +2267,11 @@ pub fn heapsort(v: &mut [T], mut is_less: F) // extern { - /// Call implementation provided memcmp + /// Calls implementation provided memcmp. /// /// Interprets the data as u8. /// - /// Return 0 for equal, < 0 for less than and > 0 for greater + /// Returns 0 for equal, < 0 for less than and > 0 for greater /// than. // FIXME(#32610): Return type should be c_int fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index fdfba33f8a9d9..d13d537d99301 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -104,7 +104,7 @@ fn shift_tail(v: &mut [T], is_less: &mut F) /// Partially sorts a slice by shifting several out-of-order elements around. /// -/// Returns true if the slice is sorted at the end. This function is `O(n)` worst-case. +/// Returns `true` if the slice is sorted at the end. This function is `O(n)` worst-case. #[cold] fn partial_insertion_sort(v: &mut [T], is_less: &mut F) -> bool where F: FnMut(&T, &T) -> bool @@ -528,7 +528,7 @@ fn break_patterns(v: &mut [T]) { } } -/// Chooses a pivot in `v` and returns the index and true if the slice is likely already sorted. +/// Chooses a pivot in `v` and returns the index and `true` if the slice is likely already sorted. /// /// Elements in `v` might be reordered in the process. fn choose_pivot(v: &mut [T], is_less: &mut F) -> (usize, bool) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index cf3e8a684dfab..1efd8137fa316 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -343,13 +343,13 @@ pub struct Chars<'a> { iter: slice::Iter<'a, u8> } -/// Return the initial codepoint accumulator for the first byte. +/// Returns the initial codepoint accumulator for the first byte. /// The first byte is special, only want bottom 5 bits for width 2, 4 bits /// for width 3, and 3 bits for width 4. #[inline] fn utf8_first_byte(byte: u8, width: u32) -> u32 { (byte & (0x7F >> width)) as u32 } -/// Return the value of `ch` updated with continuation byte `byte`. +/// Returns the value of `ch` updated with continuation byte `byte`. #[inline] fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { (ch << 6) | (byte & CONT_MASK) as u32 } @@ -1244,13 +1244,13 @@ Section: UTF-8 validation // use truncation to fit u64 into usize const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; -/// Return `true` if any byte in the word `x` is nonascii (>= 128). +/// Returns `true` if any byte in the word `x` is nonascii (>= 128). #[inline] fn contains_nonascii(x: usize) -> bool { (x & NONASCII_MASK) != 0 } -/// Walk through `iter` checking that it's a valid UTF-8 sequence, +/// Walks through `iter` checking that it's a valid UTF-8 sequence, /// returning `true` in that case, or, if it is invalid, `false` with /// `iter` reset such that it is pointing at the first byte in the /// invalid sequence. @@ -1389,16 +1389,16 @@ static UTF8_CHAR_WIDTH: [u8; 256] = [ 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF ]; -/// Given a first byte, determine how many bytes are in this UTF-8 character +/// Given a first byte, determines how many bytes are in this UTF-8 character. #[unstable(feature = "str_internals", issue = "0")] #[inline] pub fn utf8_char_width(b: u8) -> usize { return UTF8_CHAR_WIDTH[b as usize] as usize; } -/// Mask of the value bits of a continuation byte +/// Mask of the value bits of a continuation byte. const CONT_MASK: u8 = 0b0011_1111; -/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte +/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. const TAG_CONT_U8: u8 = 0b1000_0000; /* From 2f0dd63bbe83938b9eda5b6076543d420bae2f2b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 18:36:43 +0200 Subject: [PATCH 212/662] Checked (and unchecked) slicing for strings? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What is this magic‽ --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 8 +- src/libcollections/str.rs | 110 +++++++++++- src/libcore/slice/mod.rs | 52 +++--- src/libcore/str/mod.rs | 326 +++++++++++++++++++++++++++++++++--- 5 files changed, 441 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa9..00448b6abb2cf 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -60,6 +60,7 @@ #![feature(unicode)] #![feature(unique)] #![feature(untagged_unions)] +#![cfg_attr(not(test), feature(str_checked_slicing))] #![cfg_attr(test, feature(rand, test))] #![no_std] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 5233887620a91..424e175996ec8 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -362,7 +362,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get(self, index) } @@ -385,7 +385,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_mut(self, index) } @@ -405,7 +405,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked(self, index) } @@ -427,7 +427,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked_mut(self, index) } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 90e54a383d623..84b73090817d2 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -32,7 +32,7 @@ use borrow::{Borrow, ToOwned}; use string::String; use std_unicode; use vec::Vec; -use slice::SliceConcatExt; +use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] @@ -291,6 +291,114 @@ impl str { core_str::StrExt::as_ptr(self) } + /// Returns a subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever + /// equivalent indexing operation would panic. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let v = "🗻∈🌏"; + /// assert_eq!(Some("🗻"), v.get(0..4)); + /// assert!(v.get(1..).is_none()); + /// assert!(v.get(..8).is_none()); + /// assert!(v.get(..42).is_none()); + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "0")] + #[inline] + pub fn get>(&self, i: I) -> Option<&I::Output> { + core_str::StrExt::get(self, i) + } + + /// Returns a mutable subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever + /// equivalent indexing operation would panic. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let mut v = String::from("🗻∈🌏"); + /// assert_eq!(Some("🗻"), v.get_mut(0..4).map(|v| &*v)); + /// assert!(v.get_mut(1..).is_none()); + /// assert!(v.get_mut(..8).is_none()); + /// assert!(v.get_mut(..42).is_none()); + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "0")] + #[inline] + pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + core_str::StrExt::get_mut(self, i) + } + + /// Returns a unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let v = "🗻∈🌏"; + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked(0..4)); + /// assert_eq!("∈", v.get_unchecked(4..7)); + /// assert_eq!("🌏", v.get_unchecked(7..11)); + /// } + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "0")] + #[inline] + pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { + core_str::StrExt::get_unchecked(self, i) + } + + /// Returns a mutable, unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let mut v = String::from("🗻∈🌏"); + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked_mut(0..4)); + /// assert_eq!("∈", v.get_unchecked_mut(4..7)); + /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); + /// } + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "0")] + #[inline] + pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { + core_str::StrExt::get_unchecked_mut(self, i) + } + /// Creates a string slice from another string slice, bypassing safety /// checks. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f8b199f886b7..4e56fa80cd9ca 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -97,8 +97,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn first(&self) -> Option<&Self::Item>; @@ -113,8 +112,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_ptr(&self) -> *const Self::Item; @@ -141,8 +139,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn iter_mut(&mut self) -> IterMut; @@ -184,8 +181,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -337,7 +333,7 @@ impl SliceExt for [T] { #[inline] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get(self) } @@ -365,7 +361,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked(self) } @@ -406,7 +402,7 @@ impl SliceExt for [T] { #[inline] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_mut(self) } @@ -538,7 +534,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked_mut(self) } @@ -631,7 +627,7 @@ impl SliceExt for [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::Index for [T] - where I: SliceIndex + where I: SliceIndex<[T]> { type Output = I::Output; @@ -644,7 +640,7 @@ impl ops::Index for [T] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut for [T] - where I: SliceIndex + where I: SliceIndex<[T]> { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -667,37 +663,37 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { /// A helper trait used for indexing operations. #[unstable(feature = "slice_get_slice", issue = "35729")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] -pub trait SliceIndex { +pub trait SliceIndex { /// The output type returned by methods. type Output: ?Sized; /// Returns a shared reference to the output at this location, if in /// bounds. - fn get(self, slice: &[T]) -> Option<&Self::Output>; + fn get(self, slice: &T) -> Option<&Self::Output>; /// Returns a mutable reference to the output at this location, if in /// bounds. - fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>; + fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; /// Returns a shared reference to the output at this location, without /// performing any bounds checking. - unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output; + unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut Self::Output; + unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; /// Returns a shared reference to the output at this location, panicking /// if out of bounds. - fn index(self, slice: &[T]) -> &Self::Output; + fn index(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, panicking /// if out of bounds. - fn index_mut(self, slice: &mut [T]) -> &mut Self::Output; + fn index_mut(self, slice: &mut T) -> &mut Self::Output; } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for usize { +impl SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -746,7 +742,7 @@ impl SliceIndex for usize { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::Range { +impl SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -807,7 +803,7 @@ impl SliceIndex for ops::Range { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeTo { +impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -842,7 +838,7 @@ impl SliceIndex for ops::RangeTo { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFrom { +impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -877,7 +873,7 @@ impl SliceIndex for ops::RangeFrom { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFull { +impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -913,7 +909,7 @@ impl SliceIndex for ops::RangeFull { #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeInclusive { +impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -976,7 +972,7 @@ impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeToInclusive { +impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index cf3e8a684dfab..aecfaa7ee023b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -22,7 +22,7 @@ use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; use mem; -use slice; +use slice::{self, SliceIndex}; pub mod pattern; @@ -1408,6 +1408,8 @@ Section: Trait implementations mod traits { use cmp::Ordering; use ops; + use mem; + use slice::{self, SliceIndex}; use str::eq_slice; /// Implements ordering of strings. @@ -1490,14 +1492,7 @@ mod traits { type Output = str; #[inline] fn index(&self, index: ops::Range) -> &str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index(self) } } @@ -1519,14 +1514,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_mut_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index_mut(self) } } @@ -1694,8 +1682,276 @@ mod traits { self.index_mut(0...index.end) } } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeFull { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + Some(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + Some(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::Range { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // canot reuse `get` as above, because of NLL trouble + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeTo { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr(); + super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr(); + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeFrom { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_mut(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked(slice) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked_mut(slice) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index_mut(slice) + } + } + + + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeToInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr(); + super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr(); + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end + 1; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end + 1) + } + } + } + } + /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] @@ -1745,6 +2001,14 @@ pub trait StrExt { #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] #[allow(deprecated)] fn lines_any(&self) -> LinesAny; + #[unstable(feature = "str_checked_slicing", issue = "0")] + fn get>(&self, i: I) -> Option<&I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "0")] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "0")] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output; + #[unstable(feature = "str_checked_slicing", issue = "0")] + unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; #[stable(feature = "core", since = "1.6.0")] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; #[stable(feature = "core", since = "1.6.0")] @@ -1934,18 +2198,34 @@ impl StrExt for str { LinesAny(self.lines()) } + #[inline] + fn get>(&self, i: I) -> Option<&I::Output> { + i.get(self) + } + + #[inline] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + i.get_mut(self) + } + + #[inline] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output { + i.get_unchecked(self) + } + + #[inline] + unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { + i.get_unchecked_mut(self) + } + #[inline] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + (begin..end).get_unchecked(self) } #[inline] unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + (begin..end).get_unchecked_mut(self) } #[inline] From 99e4c0ad8b0c2e551e7ef0db60b8a2b84f35c1ee Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 18:39:41 +0200 Subject: [PATCH 213/662] Tracking issue numbers --- src/libcollections/str.rs | 8 ++++---- src/libcore/str/mod.rs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 84b73090817d2..4fe2b826c96f5 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -306,7 +306,7 @@ impl str { /// assert!(v.get(..8).is_none()); /// assert!(v.get(..42).is_none()); /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub fn get>(&self, i: I) -> Option<&I::Output> { core_str::StrExt::get(self, i) @@ -327,7 +327,7 @@ impl str { /// assert!(v.get_mut(..8).is_none()); /// assert!(v.get_mut(..42).is_none()); /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { core_str::StrExt::get_mut(self, i) @@ -360,7 +360,7 @@ impl str { /// assert_eq!("🌏", v.get_unchecked(7..11)); /// } /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { core_str::StrExt::get_unchecked(self, i) @@ -393,7 +393,7 @@ impl str { /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); /// } /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { core_str::StrExt::get_unchecked_mut(self, i) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index aecfaa7ee023b..b6c421ecd3201 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1683,7 +1683,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeFull { type Output = str; #[inline] @@ -1712,7 +1712,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::Range { type Output = str; #[inline] @@ -1766,7 +1766,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeTo { type Output = str; #[inline] @@ -1810,7 +1810,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeFrom { type Output = str; #[inline] @@ -1856,7 +1856,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] @@ -1905,7 +1905,7 @@ mod traits { - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] @@ -2001,13 +2001,13 @@ pub trait StrExt { #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] #[allow(deprecated)] fn lines_any(&self) -> LinesAny; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] fn get>(&self, i: I) -> Option<&I::Output>; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] unsafe fn get_unchecked>(&self, i: I) -> &I::Output; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; #[stable(feature = "core", since = "1.6.0")] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; From a033f1a8eeb55bdf93749a5d0c4d803bbe0d8dfc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 22 Mar 2017 10:32:38 -0700 Subject: [PATCH 214/662] Simplify hash table drops This replaces the `std::collections::hash::table::RevMoveBuckets` iterator with a simpler `while` loop. This iterator was only used for dropping the remaining elements of a `RawTable`, so instead we can just loop through directly and drop them in place. This should be functionally equivalent to the former code, but a little easier to read. I was hoping it might have some performance benefit too, but it seems the optimizer was already good enough to see through the iterator -- the generated code is nearly the same. Maybe it will still help if an element type has more complicated drop code. --- src/libstd/collections/hash/table.rs | 65 ++++++++-------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 211605bef1ee0..da5fb1a47333e 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -896,15 +896,23 @@ impl RawTable { } } - /// Returns an iterator that copies out each entry. Used while the table - /// is being dropped. - unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets { - let raw_bucket = self.first_bucket_raw(); - RevMoveBuckets { - raw: raw_bucket.offset(self.capacity as isize), - hashes_end: raw_bucket.hash, - elems_left: self.size, - marker: marker::PhantomData, + /// Drops buckets in reverse order. It leaves the table in an inconsistent + /// state and should only be used for dropping the table's remaining + /// entries. It's used in the implementation of Drop. + unsafe fn rev_drop_buckets(&mut self) { + let first_raw = self.first_bucket_raw(); + let mut raw = first_raw.offset(self.capacity as isize); + let mut elems_left = self.size; + + while elems_left != 0 { + debug_assert!(raw.hash != first_raw.hash); + + raw = raw.offset(-1); + + if *raw.hash != EMPTY_BUCKET { + elems_left -= 1; + ptr::drop_in_place(raw.pair as *mut (K, V)); + } } } @@ -964,43 +972,6 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { } } -/// An iterator that moves out buckets in reverse order. It leaves the table -/// in an inconsistent state and should only be used for dropping -/// the table's remaining entries. It's used in the implementation of Drop. -struct RevMoveBuckets<'a, K, V> { - raw: RawBucket, - hashes_end: *mut HashUint, - elems_left: usize, - - // As above, `&'a (K,V)` would seem better, but we often use - // 'static for the lifetime, and this is not a publicly exposed - // type. - marker: marker::PhantomData<&'a ()>, -} - -impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> { - type Item = (K, V); - - fn next(&mut self) -> Option<(K, V)> { - if self.elems_left == 0 { - return None; - } - - loop { - debug_assert!(self.raw.hash != self.hashes_end); - - unsafe { - self.raw = self.raw.offset(-1); - - if *self.raw.hash != EMPTY_BUCKET { - self.elems_left -= 1; - return Some(ptr::read(self.raw.pair)); - } - } - } - } -} - /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, @@ -1227,7 +1198,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { unsafe { if needs_drop::<(K, V)>() { // avoid linear runtime for types that don't need drop - for _ in self.rev_move_buckets() {} + self.rev_drop_buckets(); } } From b7a3d46efa1f5982f7f86277eb7dbe9f8bc066b0 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 22 Mar 2017 18:42:42 +0100 Subject: [PATCH 215/662] Add 'the' before 'start'/'end' --- src/libcollections/range.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index d10ca087f93e7..06d89a6a70b4a 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -22,7 +22,7 @@ use Bound::{self, Excluded, Included, Unbounded}; pub trait RangeArgument { /// Start index bound. /// - /// Returns start value as a `Bound`. + /// Returns the start value as a `Bound`. /// /// # Examples /// @@ -44,7 +44,7 @@ pub trait RangeArgument { /// End index bound. /// - /// Returns end value as a `Bound`. + /// Returns the end value as a `Bound`. /// /// # Examples /// From 53a36923f12d6c9b7ef9cb0fe73cda50385b1f70 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 22:02:42 +0200 Subject: [PATCH 216/662] Fix the tests --- src/test/compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-indexing.rs | 8 ++++---- src/test/compile-fail/on-unimplemented/slice-index.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 1889d76c03c03..624944f7344cb 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<{integer}>` is not satisfied + [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs index 1815d0e978a94..659b08b55a00a 100644 --- a/src/test/compile-fail/integral-indexing.rs +++ b/src/test/compile-fail/integral-indexing.rs @@ -19,8 +19,8 @@ pub fn main() { v[3i32]; //~ERROR : std::ops::Index` is not satisfied s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex` is not satisfied + s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index d28b823ddc145..1a9ed2dd6e4dc 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -20,10 +20,10 @@ fn main() { let x = &[1, 2, 3] as &[i32]; x[1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `i32` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32` //~| NOTE required because of the requirements on the impl of `std::ops::Index` x[..1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `std::ops::RangeTo` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` //~| NOTE requirements on the impl of `std::ops::Index>` } From c5a9f1f3f6d36d6e48586d16fdc3a69e9c75781a Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Wed, 22 Mar 2017 13:39:17 -0400 Subject: [PATCH 217/662] Basic documentation for inclusive range syntax --- src/doc/unstable-book/src/inclusive-range-syntax.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/doc/unstable-book/src/inclusive-range-syntax.md b/src/doc/unstable-book/src/inclusive-range-syntax.md index 74d85536399d7..255445c318dca 100644 --- a/src/doc/unstable-book/src/inclusive-range-syntax.md +++ b/src/doc/unstable-book/src/inclusive-range-syntax.md @@ -6,5 +6,15 @@ The tracking issue for this feature is: [#28237] ------------------------ +To get a range that goes from 0 to 10 and includes the value 10, you +can write `0...10`: +```rust +#![feature(inclusive_range_syntax)] +fn main() { + for i in 0...10 { + println!("{}", i); + } +} +``` From 85dbc6570a304d7e61fc41d1a121d0b01619fb45 Mon Sep 17 00:00:00 2001 From: mandeep Date: Wed, 22 Mar 2017 21:16:37 -0500 Subject: [PATCH 218/662] Changed error message for ObjectSafetyViolation::SupertraitSelf --- src/librustc/traits/object_safety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 2ebe0d459fab1..7cd0b26940d91 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -46,7 +46,7 @@ impl ObjectSafetyViolation { "the trait cannot require that `Self : Sized`".into(), ObjectSafetyViolation::SupertraitSelf => "the trait cannot use `Self` as a type parameter \ - in the supertrait listing".into(), + in the supertraits or where-clauses".into(), ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) => format!("method `{}` has no receiver", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => From 3ec61ea921a0090e97d3ec6a306561c8c6bacc91 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 23 Mar 2017 16:32:49 +1300 Subject: [PATCH 219/662] save-analysis: allow clients to get data directly without writing to a file --- src/librustc_driver/driver.rs | 5 +- src/librustc_driver/lib.rs | 6 +- src/librustc_save_analysis/json_dumper.rs | 50 +++++-- src/librustc_save_analysis/lib.rs | 175 +++++++++++++++------- 4 files changed, 164 insertions(+), 72 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2126a5a7c71bd..10a92d8c3a5fe 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -250,10 +250,7 @@ fn keep_hygiene_data(sess: &Session) -> bool { } fn keep_ast(sess: &Session) -> bool { - sess.opts.debugging_opts.keep_ast || - sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv || - sess.opts.debugging_opts.save_analysis_api + sess.opts.debugging_opts.keep_ast || ::save_analysis(sess) } /// The name used for source code that doesn't originate in a file diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 62d7512655728..f05bcd7780990 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -66,6 +66,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; +use rustc_save_analysis::DumpHandler; use rustc_trans::back::link; use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS}; use rustc::dep_graph::DepGraph; @@ -506,8 +507,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { state.expanded_crate.unwrap(), state.analysis.unwrap(), state.crate_name.unwrap(), - state.out_dir, - save_analysis_format(state.session)) + DumpHandler::new(save_analysis_format(state.session), + state.out_dir, + state.crate_name.unwrap())) }); }; control.after_analysis.run_callback_on_error = true; diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index acc877d394775..2d1e12bf0a10d 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -22,25 +22,55 @@ use external_data::*; use data::{self, VariableKind}; use dump::Dump; -pub struct JsonDumper<'b, W: Write + 'b> { - output: &'b mut W, +pub struct JsonDumper { result: Analysis, + output: O, } -impl<'b, W: Write> JsonDumper<'b, W> { - pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> { - JsonDumper { output: writer, result: Analysis::new() } - } +pub trait DumpOutput { + fn dump(&mut self, result: &Analysis); } -impl<'b, W: Write> Drop for JsonDumper<'b, W> { - fn drop(&mut self) { - if let Err(_) = write!(self.output, "{}", as_json(&self.result)) { +pub struct WriteOutput<'b, W: Write + 'b> { + output: &'b mut W, +} + +impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> { + fn dump(&mut self, result: &Analysis) { + if let Err(_) = write!(self.output, "{}", as_json(&result)) { error!("Error writing output"); } } } +pub struct CallbackOutput<'b> { + callback: &'b mut FnMut(&Analysis), +} + +impl<'b> DumpOutput for CallbackOutput<'b> { + fn dump(&mut self, result: &Analysis) { + (self.callback)(result) + } +} + +impl<'b, W: Write> JsonDumper> { + pub fn new(writer: &'b mut W) -> JsonDumper> { + JsonDumper { output: WriteOutput { output: writer }, result: Analysis::new() } + } +} + +impl<'b> JsonDumper> { + pub fn with_callback(callback: &'b mut FnMut(&Analysis)) -> JsonDumper> { + JsonDumper { output: CallbackOutput { callback: callback }, result: Analysis::new() } + } +} + +impl Drop for JsonDumper { + fn drop(&mut self) { + self.output.dump(&self.result); + } +} + macro_rules! impl_fn { ($fn_name: ident, $data_type: ident, $bucket: ident) => { fn $fn_name(&mut self, data: $data_type) { @@ -49,7 +79,7 @@ macro_rules! impl_fn { } } -impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { +impl<'b, O: DumpOutput + 'b> Dump for JsonDumper { fn crate_prelude(&mut self, data: CratePreludeData) { self.result.prelude = Some(data) } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 5e2b1df9d34f8..e5c04f6b61ec2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -48,6 +48,7 @@ use rustc::hir::def::Def; use rustc::hir::map::Node; use rustc::hir::def_id::DefId; use rustc::session::config::CrateType::CrateTypeExecutable; +use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use std::env; @@ -866,55 +867,131 @@ impl Format { } } -pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, - krate: &ast::Crate, - analysis: &'l ty::CrateAnalysis, - cratename: &str, - odir: Option<&Path>, - format: Format) { - let _ignore = tcx.dep_graph.in_ignore(); +/// Defines what to do with the results of saving the analysis. +pub trait SaveHandler { + fn save<'l, 'tcx>(&mut self, + save_ctxt: SaveContext<'l, 'tcx>, + krate: &ast::Crate, + cratename: &str); +} - assert!(analysis.glob_map.is_some()); +/// Dump the save-analysis results to a file. +pub struct DumpHandler<'a> { + format: Format, + odir: Option<&'a Path>, + cratename: String +} - info!("Dumping crate {}", cratename); +impl<'a> DumpHandler<'a> { + pub fn new(format: Format, odir: Option<&'a Path>, cratename: &str) -> DumpHandler<'a> { + DumpHandler { + format: format, + odir: odir, + cratename: cratename.to_owned() + } + } - // find a path to dump our data to - let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") { - Some(val) => PathBuf::from(val), - None => match odir { - Some(val) => val.join("save-analysis"), - None => PathBuf::from("save-analysis-temp"), - }, - }; + fn output_file(&self, sess: &Session) -> File { + let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") { + Some(val) => PathBuf::from(val), + None => match self.odir { + Some(val) => val.join("save-analysis"), + None => PathBuf::from("save-analysis-temp"), + }, + }; - if let Err(e) = std::fs::create_dir_all(&root_path) { - tcx.sess.err(&format!("Could not create directory {}: {}", - root_path.display(), - e)); + if let Err(e) = std::fs::create_dir_all(&root_path) { + error!("Could not create directory {}: {}", root_path.display(), e); + } + + { + let disp = root_path.display(); + info!("Writing output to {}", disp); + } + + let executable = sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable); + let mut out_name = if executable { + "".to_owned() + } else { + "lib".to_owned() + }; + out_name.push_str(&self.cratename); + out_name.push_str(&sess.opts.cg.extra_filename); + out_name.push_str(self.format.extension()); + root_path.push(&out_name); + let output_file = File::create(&root_path).unwrap_or_else(|e| { + let disp = root_path.display(); + sess.fatal(&format!("Could not open {}: {}", disp, e)); + }); + root_path.pop(); + output_file } +} + +impl<'a> SaveHandler for DumpHandler<'a> { + fn save<'l, 'tcx>(&mut self, + save_ctxt: SaveContext<'l, 'tcx>, + krate: &ast::Crate, + cratename: &str) { + macro_rules! dump { + ($new_dumper: expr) => {{ + let mut dumper = $new_dumper; + let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); + + visitor.dump_crate_info(cratename, krate); + visit::walk_crate(&mut visitor, krate); + }} + } + + let output = &mut self.output_file(&save_ctxt.tcx.sess); - { - let disp = root_path.display(); - info!("Writing output to {}", disp); + match self.format { + Format::Csv => dump!(CsvDumper::new(output)), + Format::Json => dump!(JsonDumper::new(output)), + Format::JsonApi => dump!(JsonApiDumper::new(output)), + } } +} - // Create output file. - let executable = tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable); - let mut out_name = if executable { - "".to_owned() - } else { - "lib".to_owned() - }; - out_name.push_str(&cratename); - out_name.push_str(&tcx.sess.opts.cg.extra_filename); - out_name.push_str(format.extension()); - root_path.push(&out_name); - let mut output_file = File::create(&root_path).unwrap_or_else(|e| { - let disp = root_path.display(); - tcx.sess.fatal(&format!("Could not open {}: {}", disp, e)); - }); - root_path.pop(); - let output = &mut output_file; +/// Call a callback with the results of save-analysis. +pub struct CallbackHandler<'b> { + pub callback: &'b mut FnMut(&rls_data::Analysis), +} + +impl<'b> SaveHandler for CallbackHandler<'b> { + fn save<'l, 'tcx>(&mut self, + save_ctxt: SaveContext<'l, 'tcx>, + krate: &ast::Crate, + cratename: &str) { + macro_rules! dump { + ($new_dumper: expr) => {{ + let mut dumper = $new_dumper; + let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); + + visitor.dump_crate_info(cratename, krate); + visit::walk_crate(&mut visitor, krate); + }} + } + + // We're using the JsonDumper here because it has the format of the + // save-analysis results that we will pass to the callback. IOW, we are + // using the JsonDumper to collect the save-analysis results, but not + // actually to dump them to a file. This is all a bit convoluted and + // there is certainly a simpler design here trying to get out (FIXME). + dump!(JsonDumper::with_callback(self.callback)) + } +} + +pub fn process_crate<'l, 'tcx, H: SaveHandler>(tcx: TyCtxt<'l, 'tcx, 'tcx>, + krate: &ast::Crate, + analysis: &'l ty::CrateAnalysis, + cratename: &str, + mut handler: H) { + let _ignore = tcx.dep_graph.in_ignore(); + + assert!(analysis.glob_map.is_some()); + + info!("Dumping crate {}", cratename); let save_ctxt = SaveContext { tcx: tcx, @@ -923,21 +1000,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, span_utils: SpanUtils::new(&tcx.sess), }; - macro_rules! dump { - ($new_dumper: expr) => {{ - let mut dumper = $new_dumper; - let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); - - visitor.dump_crate_info(cratename, krate); - visit::walk_crate(&mut visitor, krate); - }} - } - - match format { - Format::Csv => dump!(CsvDumper::new(output)), - Format::Json => dump!(JsonDumper::new(output)), - Format::JsonApi => dump!(JsonApiDumper::new(output)), - } + handler.save(save_ctxt, krate, cratename) } // Utility functions for the module. From 7d302d25826ee41703e10d6acd6d3114930e1dd2 Mon Sep 17 00:00:00 2001 From: mandeep Date: Wed, 22 Mar 2017 23:06:56 -0500 Subject: [PATCH 220/662] Changed E0038 error message in test to comply with new message --- src/test/compile-fail/object-safety-supertrait-mentions-Self.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs index 74d1ad62f14c3..a93c056c410c6 100644 --- a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs +++ b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs @@ -24,7 +24,7 @@ fn make_bar>(t: &T) -> &Bar { fn make_baz(t: &T) -> &Baz { //~^ ERROR E0038 - //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing + //~| NOTE the trait cannot use `Self` as a type parameter in the supertraits or where-clauses //~| NOTE the trait `Baz` cannot be made into an object t } From 769b95dc9f92edb51146727813ea7eae00b5b651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Mar 2017 21:13:00 -0700 Subject: [PATCH 221/662] Add diagnostic for incorrect `pub (restriction)` Given the following statement ```rust pub (a) fn afn() {} ``` Provide the following diagnostic: ```rust error: incorrect restriction in `pub` --> file.rs:15:1 | 15 | pub (a) fn afn() {} | ^^^^^^^ | = help: some valid visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path help: to make this visible only to module `a`, add `in` before the path: | pub (in a) fn afn() {} ``` Remove cruft from old `pub(path)` syntax. --- src/libsyntax/parse/parser.rs | 64 +++++++++++-------- .../restricted/tuple-struct-fields/test.rs | 7 +- .../restricted/tuple-struct-fields/test2.rs | 7 +- .../restricted/tuple-struct-fields/test3.rs | 7 +- src/test/ui/pub/pub-restricted-error-fn.rs | 13 ++++ .../ui/pub/pub-restricted-error-fn.stderr | 8 +++ src/test/ui/pub/pub-restricted-error.rs | 19 ++++++ src/test/ui/pub/pub-restricted-error.stderr | 8 +++ src/test/ui/pub/pub-restricted-non-path.rs | 15 +++++ .../ui/pub/pub-restricted-non-path.stderr | 8 +++ src/test/ui/pub/pub-restricted.rs | 37 +++++++++++ src/test/ui/pub/pub-restricted.stderr | 47 ++++++++++++++ 12 files changed, 205 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/pub/pub-restricted-error-fn.rs create mode 100644 src/test/ui/pub/pub-restricted-error-fn.stderr create mode 100644 src/test/ui/pub/pub-restricted-error.rs create mode 100644 src/test/ui/pub/pub-restricted-error.stderr create mode 100644 src/test/ui/pub/pub-restricted-non-path.rs create mode 100644 src/test/ui/pub/pub-restricted-non-path.stderr create mode 100644 src/test/ui/pub/pub-restricted.rs create mode 100644 src/test/ui/pub/pub-restricted.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c0421..649e90599345b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4626,7 +4626,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility()?; + let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4939,25 +4939,8 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility()?; - let ty_is_interpolated = - p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); - let mut ty = p.parse_ty()?; - - // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`. - if vis == Visibility::Public && !ty_is_interpolated && - p.token != token::Comma && p.token != token::CloseDelim(token::Paren) { - ty = if let TyKind::Paren(ref path_ty) = ty.node { - if let TyKind::Path(None, ref path) = path_ty.node { - vis = Visibility::Restricted { path: P(path.clone()), id: path_ty.id }; - Some(p.parse_ty()?) - } else { - None - } - } else { - None - }.unwrap_or(ty); - } + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; Ok(StructField { span: mk_sp(lo, p.span.hi), vis: vis, @@ -4996,18 +4979,25 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility()?; + let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } - // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts - // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. - fn parse_visibility(&mut self) -> PResult<'a, Visibility> { + /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)` + /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's + /// a function definition, it's not a tuple struct field) and the contents within the parens + /// isn't valid, emit a proper diagnostic. + fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } if self.check(&token::OpenDelim(token::Paren)) { + let start_span = self.span; + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { // `pub(crate)` self.bump(); // `(` @@ -5032,6 +5022,28 @@ impl<'a> Parser<'a> { let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; self.expect(&token::CloseDelim(token::Paren))?; // `)` return Ok(vis) + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct + // `pub(something) fn ...` or `struct X { pub(something) y: Z }` + self.bump(); // `(` + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + let path = self.parse_path(PathStyle::Mod)?; + let path_span = self.prev_span; + let help_msg = format!("to make this visible only to module `{}`, add `in` before \ + the path:", + path); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let sp = Span { + lo: start_span.lo, + hi: self.prev_span.hi, + expn_id: start_span.expn_id, + }; + let mut err = self.span_fatal_help(sp, &msg, &suggestion); + err.span_suggestion(path_span, &help_msg, format!("in {}", path)); + err.emit(); // emit diagnostic, but continue with public visibility } } @@ -5508,7 +5520,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5787,7 +5799,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index 208f1a0e2ee25..d17b604717e70 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -10,7 +10,8 @@ mod foo { type T = (); - struct S1(pub(foo) (), pub(T), pub(crate) (), pub(((), T))); - struct S2(pub((foo)) ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T))); + struct S2(pub((foo)) ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 57769646e3b8f..166d5e27e8d96 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -11,9 +11,10 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); - struct S2(pub (foo) ()); - struct S3(pub $t ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S2(pub (in foo) ()); + struct S3(pub $t ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index db3358f7d50ae..edab175f4cd91 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -11,9 +11,10 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); - struct S2(pub (foo) ()); - struct S3(pub($t) ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S2(pub (in foo) ()); + struct S3(pub($t) ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs new file mode 100644 index 0000000000000..13514310371cc --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error-fn.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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(pub_restricted)] + +pub(crate) () fn foo() {} diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr new file mode 100644 index 0000000000000..470e833124785 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -0,0 +1,8 @@ +error: unmatched visibility `pub` + --> $DIR/pub-restricted-error-fn.rs:13:10 + | +13 | pub(crate) () fn foo() {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted-error.rs b/src/test/ui/pub/pub-restricted-error.rs new file mode 100644 index 0000000000000..99af031899ab6 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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(pub_restricted)] + +struct Bar(pub(())); + +struct Foo { + pub(crate) () foo: usize, +} + + diff --git a/src/test/ui/pub/pub-restricted-error.stderr b/src/test/ui/pub/pub-restricted-error.stderr new file mode 100644 index 0000000000000..b8b4c80778d96 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `(` + --> $DIR/pub-restricted-error.rs:16:16 + | +16 | pub(crate) () foo: usize, + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted-non-path.rs b/src/test/ui/pub/pub-restricted-non-path.rs new file mode 100644 index 0000000000000..3f74285717a7b --- /dev/null +++ b/src/test/ui/pub/pub-restricted-non-path.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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(pub_restricted)] + +pub (.) fn afn() {} + +fn main() {} diff --git a/src/test/ui/pub/pub-restricted-non-path.stderr b/src/test/ui/pub/pub-restricted-non-path.stderr new file mode 100644 index 0000000000000..ebfccc4d72045 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-non-path.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `.` + --> $DIR/pub-restricted-non-path.rs:13:6 + | +13 | pub (.) fn afn() {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted.rs b/src/test/ui/pub/pub-restricted.rs new file mode 100644 index 0000000000000..48e487f71a791 --- /dev/null +++ b/src/test/ui/pub/pub-restricted.rs @@ -0,0 +1,37 @@ +// Copyright 2017 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(pub_restricted)] + +mod a {} + +pub (a) fn afn() {} +pub (b) fn bfn() {} +pub fn privfn() {} +mod x { + mod y { + pub (in x) fn foo() {} + pub (super) fn bar() {} + pub (crate) fn qux() {} + } +} + +mod y { + struct Foo { + pub (crate) c: usize, + pub (super) s: usize, + valid_private: usize, + pub (in y) valid_in_x: usize, + pub (a) invalid: usize, + pub (in x) non_parent_invalid: usize, + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr new file mode 100644 index 0000000000000..5bc230e8da377 --- /dev/null +++ b/src/test/ui/pub/pub-restricted.stderr @@ -0,0 +1,47 @@ +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:15:5 + | +15 | pub (a) fn afn() {} + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `a`, add `in` before the path: + | pub (in a) fn afn() {} + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:16:5 + | +16 | pub (b) fn bfn() {} + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `b`, add `in` before the path: + | pub (in b) fn bfn() {} + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:32:13 + | +32 | pub (a) invalid: usize, + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `a`, add `in` before the path: + | pub (in a) invalid: usize, + +error: visibilities can only be restricted to ancestor modules + --> $DIR/pub-restricted.rs:33:17 + | +33 | pub (in x) non_parent_invalid: usize, + | ^ + +error: aborting due to 4 previous errors + From 49c408e679653d8b5e01209b9fe01f952db9ca29 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 23 Mar 2017 12:20:13 +0100 Subject: [PATCH 222/662] Fix markdown links to pdqsort --- src/libcollections/slice.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d3723ace9efb3..f7451f574ffa3 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1162,7 +1162,7 @@ impl [T] { /// /// # Current implementation /// - /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort], + /// The current algorithm is based on Orson Peters' [pattern-defeating quicksort][pdqsort], /// which is a quicksort variant designed to be very fast on certain kinds of patterns, /// sometimes achieving linear time. It is randomized but deterministic, and falls back to /// heapsort on degenerate inputs. @@ -1199,7 +1199,7 @@ impl [T] { /// /// # Current implementation /// - /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort], + /// The current algorithm is based on Orson Peters' [pattern-defeating quicksort][pdqsort], /// which is a quicksort variant designed to be very fast on certain kinds of patterns, /// sometimes achieving linear time. It is randomized but deterministic, and falls back to /// heapsort on degenerate inputs. @@ -1239,7 +1239,7 @@ impl [T] { /// /// # Current implementation /// - /// The current algorithm is based on Orson Peters' [pdqsort][pattern-defeating quicksort], + /// The current algorithm is based on Orson Peters' [pattern-defeating quicksort][pdqsort], /// which is a quicksort variant designed to be very fast on certain kinds of patterns, /// sometimes achieving linear time. It is randomized but deterministic, and falls back to /// heapsort on degenerate inputs. From 823715c18e77af3a4318d8c57c9f956f86d5da1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 07:07:02 -0700 Subject: [PATCH 223/662] appveyor: Leverage auto-retry to upload to S3 This was recently implemented (appveyor/ci#1387) in response to one of our feature requests, so let's take advantage of it! I'm going to optimistically say... Closes #39074 --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 0e7ebf12a2a91..21bd9cee53f57 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -182,6 +182,7 @@ deploy: on: branch: auto DEPLOY: 1 + max_error_retry: 5 # This provider is the same as the one above except that it has a slightly # different upload directory and a slightly different trigger @@ -198,6 +199,7 @@ deploy: on: branch: auto DEPLOY_ALT: 1 + max_error_retry: 5 # init: # - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) From 5ca8a735ca36219abbf601624606c41148b95210 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Mar 2017 22:27:12 -0700 Subject: [PATCH 224/662] std: Don't cache stdio handles on Windows This alters the stdio code on Windows to always call `GetStdHandle` whenever the stdio read/write functions are called as this allows us to track changes to the value over time (such as if a process calls `SetStdHandle` while it's running). Closes #40490 --- src/libstd/sys/windows/process.rs | 9 +- src/libstd/sys/windows/stdio.rs | 92 +++++++++------------ src/test/run-pass-fulldeps/switch-stdout.rs | 64 ++++++++++++++ 3 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 src/test/run-pass-fulldeps/switch-stdout.rs diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 1afb3728c9d72..dfbc1b581ee55 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -257,8 +257,13 @@ impl Stdio { // INVALID_HANDLE_VALUE. Stdio::Inherit => { match stdio::get(stdio_id) { - Ok(io) => io.handle().duplicate(0, true, - c::DUPLICATE_SAME_ACCESS), + Ok(io) => { + let io = Handle::new(io.handle()); + let ret = io.duplicate(0, true, + c::DUPLICATE_SAME_ACCESS); + io.into_raw(); + return ret + } Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), } } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b1a57c349fbb9..d72e4b4438b7b 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -22,42 +22,43 @@ use sys::cvt; use sys::handle::Handle; use sys_common::io::read_to_end_uninitialized; -pub struct NoClose(Option); - pub enum Output { - Console(NoClose), - Pipe(NoClose), + Console(c::HANDLE), + Pipe(c::HANDLE), } pub struct Stdin { - handle: Output, utf8: Mutex>>, } -pub struct Stdout(Output); -pub struct Stderr(Output); +pub struct Stdout; +pub struct Stderr; pub fn get(handle: c::DWORD) -> io::Result { let handle = unsafe { c::GetStdHandle(handle) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else if handle.is_null() { - Err(io::Error::new(io::ErrorKind::Other, - "no stdio handle available for this process")) + Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) } else { - let ret = NoClose::new(handle); let mut out = 0; match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(ret)), - _ => Ok(Output::Console(ret)), + 0 => Ok(Output::Pipe(handle)), + _ => Ok(Output::Console(handle)), } } } -fn write(out: &Output, data: &[u8]) -> io::Result { - let handle = match *out { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().write(data), +fn write(handle: c::DWORD, data: &[u8]) -> io::Result { + let handle = match try!(get(handle)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.write(data); + handle.into_raw(); + return ret + } }; + // As with stdin on windows, stdout often can't handle writes of large // sizes. For an example, see #14940. For this reason, don't try to // write the entire output buffer on windows. @@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result { impl Stdin { pub fn new() -> io::Result { - get(c::STD_INPUT_HANDLE).map(|handle| { - Stdin { - handle: handle, - utf8: Mutex::new(Cursor::new(Vec::new())), - } + Ok(Stdin { + utf8: Mutex::new(Cursor::new(Vec::new())), }) } pub fn read(&self, buf: &mut [u8]) -> io::Result { - let handle = match self.handle { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().read(buf), + let handle = match try!(get(c::STD_INPUT_HANDLE)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.read(buf); + handle.into_raw(); + return ret + } }; let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty @@ -125,11 +128,9 @@ impl Stdin { Ok(utf8) => utf8.into_bytes(), Err(..) => return Err(invalid_encoding()), }; - if let Output::Console(_) = self.handle { - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } + if let Some(&last_byte) = data.last() { + if last_byte == CTRL_Z { + data.pop(); } } *utf8 = Cursor::new(data); @@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin { impl Stdout { pub fn new() -> io::Result { - get(c::STD_OUTPUT_HANDLE).map(Stdout) + Ok(Stdout) } pub fn write(&self, data: &[u8]) -> io::Result { - write(&self.0, data) + write(c::STD_OUTPUT_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -172,11 +173,11 @@ impl Stdout { impl Stderr { pub fn new() -> io::Result { - get(c::STD_ERROR_HANDLE).map(Stderr) + Ok(Stderr) } pub fn write(&self, data: &[u8]) -> io::Result { - write(&self.0, data) + write(c::STD_ERROR_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -197,27 +198,12 @@ impl io::Write for Stderr { } } -impl NoClose { - fn new(handle: c::HANDLE) -> NoClose { - NoClose(Some(Handle::new(handle))) - } - - fn get(&self) -> &Handle { self.0.as_ref().unwrap() } -} - -impl Drop for NoClose { - fn drop(&mut self) { - self.0.take().unwrap().into_raw(); - } -} - impl Output { - pub fn handle(&self) -> &Handle { - let nc = match *self { - Output::Console(ref c) => c, - Output::Pipe(ref c) => c, - }; - nc.0.as_ref().unwrap() + pub fn handle(&self) -> c::HANDLE { + match *self { + Output::Console(c) => c, + Output::Pipe(c) => c, + } } } diff --git a/src/test/run-pass-fulldeps/switch-stdout.rs b/src/test/run-pass-fulldeps/switch-stdout.rs new file mode 100644 index 0000000000000..4542e27545a4c --- /dev/null +++ b/src/test/run-pass-fulldeps/switch-stdout.rs @@ -0,0 +1,64 @@ +// 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. + +#![feature(rustc_private)] + +extern crate rustc_back; + +use std::fs::File; +use std::io::{Read, Write}; + +use rustc_back::tempdir::TempDir; + +#[cfg(unix)] +fn switch_stdout_to(file: File) { + use std::os::unix::prelude::*; + + extern { + fn dup2(old: i32, new: i32) -> i32; + } + + unsafe { + assert_eq!(dup2(file.as_raw_fd(), 1), 1); + } +} + +#[cfg(windows)] +fn switch_stdout_to(file: File) { + use std::os::windows::prelude::*; + + extern "system" { + fn SetStdHandle(nStdHandle: u32, handle: *mut u8) -> i32; + } + + const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32; + + unsafe { + let rc = SetStdHandle(STD_OUTPUT_HANDLE, + file.into_raw_handle() as *mut _); + assert!(rc != 0); + } +} + +fn main() { + let td = TempDir::new("foo").unwrap(); + let path = td.path().join("bar"); + let f = File::create(&path).unwrap(); + + println!("foo"); + std::io::stdout().flush().unwrap(); + switch_stdout_to(f); + println!("bar"); + std::io::stdout().flush().unwrap(); + + let mut contents = String::new(); + File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + assert_eq!(contents, "bar\n"); +} From 38795677aef77e89f2d9f0031d845a59df9c8171 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 22 Mar 2017 11:33:07 -0700 Subject: [PATCH 225/662] travis: Delay sccache downloads in docker Let's have this layer be towards the end as we're emprically changing sccache more than we're changing the rest of the image, so this'll allow us to reuse as much of the cached image as possible. --- src/ci/docker/dist-arm-linux/Dockerfile | 8 ++++---- src/ci/docker/dist-armv7-aarch64-linux/Dockerfile | 8 ++++---- src/ci/docker/dist-powerpc-linux/Dockerfile | 8 ++++---- src/ci/docker/dist-powerpc64-linux/Dockerfile | 10 +++++----- src/ci/docker/dist-s390x-linux-netbsd/Dockerfile | 8 ++++---- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index ae439f5b30f29..d642a40408e6f 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -65,6 +61,10 @@ RUN ./build-toolchains.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile index 7f3c552258780..6ed0eb0a78969 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -66,6 +62,10 @@ RUN ./build-toolchains.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index 1c61714adbd2a..51617feaeeffb 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -66,6 +62,10 @@ RUN ./build-powerpc-toolchain.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin ENV \ diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 975ae1d3ec9c1..5715b0fbe72df 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -25,11 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ xz-utils \ libssl-dev \ - pkg-config - -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache + pkg-config RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ @@ -70,6 +66,10 @@ RUN apt-get install -y --no-install-recommends rpm2cpio cpio COPY build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index c68f30a6e563b..e6fb03e742f63 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -69,6 +65,10 @@ RUN ./build-netbsd-toolchain.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin ENV \ From 05c4051f640592df825d290901e0ed3e265de24c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 22 Mar 2017 19:16:41 -0700 Subject: [PATCH 226/662] travis: Update sccache binary --- .travis.yml | 2 +- appveyor.yml | 4 ++-- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/cross/Dockerfile | 2 +- src/ci/docker/dist-android/Dockerfile | 2 +- src/ci/docker/dist-arm-linux/Dockerfile | 2 +- src/ci/docker/dist-armv7-aarch64-linux/Dockerfile | 2 +- src/ci/docker/dist-freebsd/Dockerfile | 2 +- src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 2 +- src/ci/docker/dist-mips-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- src/ci/docker/dist-s390x-linux-netbsd/Dockerfile | 2 +- src/ci/docker/dist-x86-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-musl/Dockerfile | 2 +- src/ci/docker/emscripten/Dockerfile | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 2 +- src/ci/docker/i686-gnu/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-debug/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-distcheck/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-incremental/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-nopt/Dockerfile | 2 +- src/ci/docker/x86_64-gnu/Dockerfile | 2 +- 28 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index b16957344ae1a..178dbc3d50d53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp diff --git a/appveyor.yml b/appveyor.yml index 0e7ebf12a2a91..bc2a540ba670a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-pc-windows-msvc - - mv 2017-03-16-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-pc-windows-msvc + - mv 2017-03-22-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index a3e74adbb3672..a5126cb3c3f23 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 72675bc9a446c..9e7abb8b36e35 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 031ad0ddcd4e6..2785d2135f864 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index d642a40408e6f..6cdb5cfca74ba 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile index 6ed0eb0a78969..ed9b4a5929188 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-freebsd/Dockerfile index deee78847bbf6..332a1fa73a4d5 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-freebsd/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index de8ed3378eb16..dcb9aa905f14e 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index f19860405b02c..2051396988589 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 8de9b6abddd6f..3123e69e7e1df 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 134f475f82d6e..52db932dcdc38 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index 51617feaeeffb..fca931596853b 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 5715b0fbe72df..17a4734aba7d1 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -67,7 +67,7 @@ COPY build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index e6fb03e742f63..c2877b081d5d7 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -66,7 +66,7 @@ RUN ./build-netbsd-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index cd4c81912dff5..100b6dcf9937e 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -76,7 +76,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 151552331c86c..7ebd34ee904bc 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index e8eb151a0784c..630b122c9359a 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index aca4bfb546d2f..b9f47731eee75 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index 2664307b09b30..e4a9c5b258fe6 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index fdc8221ad250d..104361830e1cd 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index dae7fac3890d8..1575efdb4cb70 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 05ff4847ecc1d..94847712094d1 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 176b1f0a857db..542b4f90b119f 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index 216b2d9a65624..4d9b218c7654c 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index d91e05e2b2dff..04358ff97484a 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index d79b07efab525..dddeb82e6bfb2 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index 71ed9ab943a0a..393bcf023ea5b 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-16-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ From 4dc122580714a5f8859e993bf56a7228b0bcd7c1 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:17:21 -0400 Subject: [PATCH 227/662] Add helpful hint on io function for beginners --- src/libstd/io/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 850885a8c0f3a..dda9d6bca7977 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -144,6 +144,16 @@ //! # Ok(()) //! # } //! ``` +//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main()`). +//! Instead, you can `match` on the return value to catch any possible errors: +//! +//! ``` +//! let mut input = String::new(); +//! match io::stdin().read_line(&mut input) { +//! Err(why) => panic!("Failed to read input: {}", why.description()), +//! Ok(_) => println!("You typed: {}", input.trim()), +//! } +//! ``` //! //! And a very common source of output is standard output: //! From 1a87fc2635660bbf2947c17901dbd7dec75a63cb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 16:17:45 -0400 Subject: [PATCH 228/662] convert `custom_coerce_unsized_kind` into a `coerce_unsized_info` This "on-demand" task both checks for errors and computes the custom unsized kind, if any. This task is only defined on impls of `CoerceUnsized`; invoking it on any other kind of impl results in a bug. This is just to avoid having an `Option`, could easily be changed. --- src/librustc/ty/adjustment.rs | 15 ++++++++ src/librustc/ty/maps.rs | 4 +-- src/librustc/ty/mod.rs | 4 +-- src/librustc_metadata/cstore_impl.rs | 6 ++-- src/librustc_metadata/decoder.rs | 8 ++--- src/librustc_metadata/encoder.rs | 18 +++++++--- src/librustc_metadata/schema.rs | 4 ++- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 46 ++++++++++++++++-------- src/librustc_typeck/coherence/mod.rs | 3 ++ 10 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 34977822bc69d..d8ca30477205c 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -139,6 +139,21 @@ pub enum AutoBorrow<'tcx> { RawPtr(hir::Mutability), } +/// Information for `CoerceUnsized` impls, storing information we +/// have computed about the coercion. +/// +/// This struct can be obtained via the `coerce_impl_info` query. +/// Demanding this struct also has the side-effect of reporting errors +/// for inappropriate impls. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub struct CoerceUnsizedInfo { + /// If this is a "custom coerce" impl, then what kind of custom + /// coercion is it? This applies to impls of `CoerceUnsized` for + /// structs, primarily, where we store a bit of info about which + /// fields need to be coerced. + pub custom_kind: Option +} + #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ac8c38c7d5856..d4214dc429ced 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -393,8 +393,8 @@ define_maps! { <'tcx> pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>, /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kind: ItemSignature(DefId) - -> ty::adjustment::CustomCoerceUnsized, + pub coerce_unsized_info: ItemSignature(DefId) + -> ty::adjustment::CoerceUnsizedInfo, pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36d1ae74e9114..d140426995812 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2054,8 +2054,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized { - queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did) + pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo { + queries::coerce_unsized_info::get(self, DUMMY_SP, did) } pub fn associated_item(self, def_id: DefId) -> AssociatedItem { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2a67b79eaa52e..7cac201f14f76 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -88,9 +88,9 @@ provide! { <'tcx> tcx, def_id, cdata } associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } - custom_coerce_unsized_kind => { - cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| { - bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id); + coerce_unsized_info => { + cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { + bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); }) } mir => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6ccdf8092f210..3de1e3442c69d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -643,10 +643,10 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).polarity } - pub fn get_custom_coerce_unsized_kind(&self, - id: DefIndex) - -> Option { - self.get_impl_data(id).coerce_unsized_kind + pub fn get_coerce_unsized_info(&self, + id: DefIndex) + -> Option { + self.get_impl_data(id).coerce_unsized_info } pub fn get_impl_trait(&self, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 044ed529ef74c..5bc84759f8797 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -695,7 +695,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ImplData { polarity: hir::ImplPolarity::Positive, parent_impl: None, - coerce_unsized_kind: None, + coerce_unsized_info: None, trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), }; @@ -715,13 +715,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None }; + // if this is an impl of `CoerceUnsized`, create its + // "unsized info", else just store None + let coerce_unsized_info = + trait_ref.and_then(|t| { + if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() { + Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id)) + } else { + None + } + }); + let data = ImplData { polarity: polarity, parent_impl: parent, - coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind - .borrow() - .get(&def_id) - .cloned(), + coerce_unsized_info: coerce_unsized_info, trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), }; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 4a20913d0b3fd..abb482a50ebc2 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -285,7 +285,9 @@ pub struct TraitData<'tcx> { pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, pub parent_impl: Option, - pub coerce_unsized_kind: Option, + + /// This is `Some` only for impls of `CoerceUnsized`. + pub coerce_unsized_info: Option, pub trait_ref: Option>>, } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index fcf6937d4b6d5..382ca8ef01001 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -287,7 +287,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx match fulfill_obligation(scx, DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - scx.tcx().custom_coerce_unsized_kind(impl_def_id) + scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() } vtable => { bug!("invalid CoerceUnsized vtable: {:?}", vtable); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 3cdf9fc93ae60..47b41a75cf531 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -18,6 +18,7 @@ use rustc::traits::{self, ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::ParameterEnvironment; use rustc::ty::TypeFoldable; +use rustc::ty::adjustment::CoerceUnsizedInfo; use rustc::ty::subst::Subst; use rustc::ty::util::CopyImplementationError; use rustc::infer; @@ -159,11 +160,26 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - coerce_unsized_trait: DefId, + _: DefId, impl_did: DefId) { debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); + // Just compute this for the side-effects, in particular reporting + // errors; other parts of the code may demand it for the info of + // course. + if impl_did.is_local() { + let span = tcx.def_span(impl_did); + ty::queries::coerce_unsized_info::get(tcx, span, impl_did); + } +} + +pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_did: DefId) + -> CoerceUnsizedInfo { + debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); + let coerce_unsized_trait = tcx.lang_items.coerce_unsized_trait().unwrap(); + let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) { Ok(id) => id, Err(err) => { @@ -171,16 +187,14 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let impl_node_id = if let Some(n) = tcx.hir.as_local_node_id(impl_did) { - n - } else { - debug!("visit_implementation_of_coerce_unsized(): impl not \ - in this crate"); - return; - }; + // this provider should only get invoked for local def-ids + let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| { + bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did) + }); let source = tcx.item_type(impl_did); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); + assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.substs.type_at(1); debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, @@ -192,6 +206,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let target = target.subst(tcx, ¶m_env.free_substs); assert!(!source.has_escaping_regions()); + let err_info = CoerceUnsizedInfo { custom_kind: None }; + debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); @@ -234,7 +250,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, definition; expected {}, found {}", source_path, target_path); - return; + return err_info; } let fields = &def_a.struct_variant().fields; @@ -268,7 +284,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with one field \ being coerced, none found"); - return; + return err_info; } else if diff_fields.len() > 1 { let item = tcx.hir.expect_item(impl_node_id); let span = if let ItemImpl(.., Some(ref t), _, _) = item.node { @@ -295,7 +311,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .join(", "))); err.span_label(span, &format!("requires multiple coercions")); err.emit(); - return; + return err_info; } let (i, a, b) = diff_fields[0]; @@ -309,7 +325,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, E0376, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures"); - return; + return err_info; } }; @@ -331,8 +347,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id); - if let Some(kind) = kind { - tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind); + CoerceUnsizedInfo { + custom_kind: kind } - }); + }) } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 9ecf42daeaae5..6abd061e81f2a 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -102,9 +102,12 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d } pub fn provide(providers: &mut Providers) { + use self::builtin::coerce_unsized_info; + *providers = Providers { coherent_trait, coherent_inherent_impls, + coerce_unsized_info, ..*providers }; } From 8e6b10a6cb349deab30fa0fb507a8c73cae6ec68 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Mar 2017 16:43:54 -0400 Subject: [PATCH 229/662] move `check` to the top of the file, where I would expect to find it Top-down, top-down! --- src/librustc_typeck/coherence/inherent.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent.rs index e3b4ba9eb1b9e..9abf233de1f9e 100644 --- a/src/librustc_typeck/coherence/inherent.rs +++ b/src/librustc_typeck/coherence/inherent.rs @@ -19,6 +19,13 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; +pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, + &mut InherentCollect { tcx }); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, + &mut InherentOverlapChecker { tcx }); +} + struct InherentCollect<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } @@ -348,9 +355,3 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { } } -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, - &mut InherentCollect { tcx }); - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, - &mut InherentOverlapChecker { tcx }); -} From 8ffe4068a6d8ff79cfccc0244a96e728387bbeb6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 23 Mar 2017 19:26:38 +0200 Subject: [PATCH 230/662] keep the AST node-id when lowering ExprKind::Range When the Range expression is the root of a constant, its node-id is used for the def-id of the body, so it has to be preserved in the AST -> HIR lowering. Fixes #40749. --- src/librustc/hir/lowering.rs | 95 +++++++++++----------------- src/test/compile-fail/issue-40749.rs | 16 +++++ 2 files changed, 52 insertions(+), 59 deletions(-) create mode 100644 src/test/compile-fail/issue-40749.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99e1..6ca0c971ea497 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1900,57 +1900,45 @@ impl<'a> LoweringContext<'a> { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(this: &mut LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) - .collect::>(); - let unstable_span = this.allow_internal_unstable("...", ast_expr.span); - - if fields.len() == 0 { - this.expr_std_path(unstable_span, struct_path, - ast_expr.attrs.clone()) - } else { - let fields = fields.into_iter().map(|&(s, e)| { - let expr = P(this.lower_expr(&e)); - let unstable_span = this.allow_internal_unstable("...", e.span); - this.field(Symbol::intern(s), expr, unstable_span) - }).collect(); - let attrs = ast_expr.attrs.clone(); - - this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) - } - } - use syntax::ast::RangeLimits::*; - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(self, e, &["RangeFull"], &[]), - - (&Some(ref e1), &None, HalfOpen) => - make_struct(self, e, &["RangeFrom"], - &[("start", e1)]), - - (&None, &Some(ref e2), HalfOpen) => - make_struct(self, e, &["RangeTo"], - &[("end", e2)]), - - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(self, e, &["Range"], - &[("start", e1), ("end", e2)]), - - (&None, &Some(ref e2), Closed) => - make_struct(self, e, &["RangeToInclusive"], - &[("end", e2)]), - - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(self, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), + let (path, variant) = match (e1, e2, lims) { + (&None, &None, HalfOpen) => ("RangeFull", None), + (&Some(..), &None, HalfOpen) => ("RangeFrom", None), + (&None, &Some(..), HalfOpen) => ("RangeTo", None), + (&Some(..), &Some(..), HalfOpen) => ("Range", None), + (&None, &Some(..), Closed) => ("RangeToInclusive", None), + (&Some(..), &Some(..), Closed) => ("RangeInclusive", Some("NonEmpty")), + (_, &None, Closed) => + panic!(self.diagnostic().span_fatal( + e.span, "inclusive range with no end")), + }; - _ => panic!(self.diagnostic() - .span_fatal(e.span, "inclusive range with no end")), + let fields = + e1.iter().map(|e| ("start", e)).chain(e2.iter().map(|e| ("end", e))) + .map(|(s, e)| { + let expr = P(self.lower_expr(&e)); + let unstable_span = self.allow_internal_unstable("...", e.span); + self.field(Symbol::intern(s), expr, unstable_span) + }).collect::>(); + + let is_unit = fields.is_empty(); + let unstable_span = self.allow_internal_unstable("...", e.span); + let struct_path = + iter::once("ops").chain(iter::once(path)).chain(variant) + .collect::>(); + let struct_path = self.std_path(unstable_span, &struct_path, is_unit); + let struct_path = hir::QPath::Resolved(None, P(struct_path)); + + return hir::Expr { + id: self.lower_node_id(e.id), + node: if is_unit { + hir::ExprPath(struct_path) + } else { + hir::ExprStruct(struct_path, fields, None) + }, + span: unstable_span, + attrs: e.attrs.clone(), }; } ExprKind::Path(ref qself, ref path) => { @@ -2613,17 +2601,6 @@ impl<'a> LoweringContext<'a> { P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new())) } - fn expr_std_struct(&mut self, - span: Span, - components: &[&str], - fields: hir::HirVec, - e: Option>, - attrs: ThinVec) -> hir::Expr { - let path = self.std_path(span, components, false); - let qpath = hir::QPath::Resolved(None, P(path)); - self.expr(span, hir::ExprStruct(qpath, fields, e), attrs) - } - fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> hir::Expr { hir::Expr { id: self.next_id(), diff --git a/src/test/compile-fail/issue-40749.rs b/src/test/compile-fail/issue-40749.rs new file mode 100644 index 0000000000000..261ed49d10c1e --- /dev/null +++ b/src/test/compile-fail/issue-40749.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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; ..10]; + //~^ ERROR mismatched types + //~| expected type `usize` + //~| found type `std::ops::RangeTo<{integer}>` +} From a29ae3052aa9c84cecab226b9a1f1fee4e5b78d4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Mar 2017 18:35:16 -0400 Subject: [PATCH 231/662] convert inherent-impl-related things to on-demand queries There are now 3 queries: - inherent_impls(def-id): for a given type, get a `Rc>` with all its inherent impls. This internally uses `crate_inherent_impls`, doing some hacks to keep the current deps (which, btw, are not clearly correct). - crate_inherent_impls(crate): gathers up a map from types to `Rc>`, touching the entire krate, possibly generating errors. - crate_inherent_impls_overlap_check(crate): performs overlap checks between the inherent impls for a given type, generating errors. --- src/librustc/dep_graph/dep_node.rs | 2 - src/librustc/dep_graph/dep_tracking_map.rs | 15 -- src/librustc/middle/cstore.rs | 2 - src/librustc/ty/maps.rs | 26 ++- src/librustc/ty/mod.rs | 43 ++--- src/librustc_metadata/cstore_impl.rs | 7 +- src/librustc_typeck/check/method/probe.rs | 11 +- .../{inherent.rs => inherent_impls.rs} | 180 +++++++----------- .../coherence/inherent_impls_overlap.rs | 102 ++++++++++ src/librustc_typeck/coherence/mod.rs | 17 +- src/librustdoc/clean/inline.rs | 8 +- 11 files changed, 227 insertions(+), 186 deletions(-) rename src/librustc_typeck/coherence/{inherent.rs => inherent_impls.rs} (71%) create mode 100644 src/librustc_typeck/coherence/inherent_impls_overlap.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 399af258e9251..c4cbbc17d51df 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -74,7 +74,6 @@ pub enum DepNode { CoherenceCheckImpl(D), CoherenceOverlapCheck(D), CoherenceOverlapCheckSpecial(D), - CoherenceOverlapInherentCheck(D), CoherenceOrphanCheck(D), Variance, WfCheck(D), @@ -251,7 +250,6 @@ impl DepNode { CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial), - CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck), CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck), WfCheck(ref d) => op(d).map(WfCheck), TypeckItemType(ref d) => op(d).map(TypeckItemType), diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 0f3108df9a822..b6a2360211cac 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -81,21 +81,6 @@ impl DepTrackingMap { pub fn keys(&self) -> Vec { self.map.keys().cloned().collect() } - - /// Append `elem` to the vector stored for `k`, creating a new vector if needed. - /// This is considered a write to `k`. - /// - /// NOTE: Caution is required when using this method. You should - /// be sure that nobody is **reading from the vector** while you - /// are writing to it. Eventually, it'd be nice to remove this. - pub fn push(&mut self, k: M::Key, elem: E) - where M: DepTrackingMapConfig> - { - self.write(&k); - self.map.entry(k) - .or_insert(Vec::new()) - .push(elem); - } } impl MemoizationMap for RefCell> { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 225d6fc9bb2b2..50ec6f26d4b82 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -176,7 +176,6 @@ pub trait CrateStore { fn item_generics_cloned(&self, def: DefId) -> ty::Generics; fn item_attrs(&self, def_id: DefId) -> Vec; fn fn_arg_names(&self, did: DefId) -> Vec; - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; // trait info fn implementations_of_trait(&self, filter: Option) -> Vec; @@ -310,7 +309,6 @@ impl CrateStore for DummyCrateStore { { bug!("item_generics_cloned") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { vec![] } // trait info fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index d4214dc429ced..87fe27d92fca6 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -12,7 +12,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use middle::const_val::ConstVal; use mir; -use ty::{self, Ty, TyCtxt}; +use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; @@ -176,9 +176,15 @@ impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> { } } -impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> { +impl<'tcx> QueryDescription for queries::crate_inherent_impls<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("all inherent impls defined in crate `{:?}`", k) + } +} + +impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx> { fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("coherence checking all inherent impls") + format!("check for overlap between inherent impls defined in this crate") } } @@ -368,7 +374,7 @@ define_maps! { <'tcx> /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - pub inherent_impls: InherentImpls(DefId) -> Vec, + pub inherent_impls: InherentImpls(DefId) -> Rc>, /// Maps from the def-id of a function/method or const/static /// to its MIR. Mutation is done at an item granularity to @@ -400,7 +406,15 @@ define_maps! { <'tcx> pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), - pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (), + /// Gets a complete map from all types to their inherent impls. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + pub crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + + /// Checks all types in the krate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (), /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. @@ -413,7 +427,7 @@ fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { DepNode::CoherenceCheckTrait(def_id) } -fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode { +fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d140426995812..d19f2ba2fadb1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -31,7 +31,7 @@ use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; use util::common::MemoizationMap; -use util::nodemap::{NodeSet, FxHashMap}; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; @@ -2345,34 +2345,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } - /// Populates the type context with all the inherent implementations for - /// the given type if necessary. - pub fn populate_inherent_implementations_for_type_if_necessary(self, - span: Span, - type_id: DefId) { - if type_id.is_local() { - // Make sure coherence of inherent impls ran already. - ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE); - return - } - - // The type is not local, hence we are reading this out of - // metadata and don't need to track edges. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_types.borrow().contains(&type_id) { - return - } - - debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", - type_id); - - let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - - self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls); - self.populated_external_types.borrow_mut().insert(type_id); - } - /// Populates the type context with all the implementations for the given /// trait if necessary. pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) { @@ -2637,3 +2609,16 @@ pub fn provide(providers: &mut ty::maps::Providers) { ..*providers }; } + + +/// A map for the local crate mapping each type to a vector of its +/// inherent impls. This is not meant to be used outside of coherence; +/// rather, you should request the vector for a specific type via +/// `ty::queries::inherent_impls::get(def_id)` so as to minimize your +/// dependencies (constructing this map requires touching the entire +/// crate). +#[derive(Clone, Debug)] +pub struct CrateInherentImpls { + pub inherent_impls: DefIdMap>>, +} + diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 7cac201f14f76..9b781d28f88dc 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -109,6 +109,7 @@ provide! { <'tcx> tcx, def_id, cdata typeck_tables => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } + inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } } impl CrateStore for cstore::CStore { @@ -162,12 +163,6 @@ impl CrateStore for cstore::CStore { self.get_crate_data(did.krate).get_fn_arg_names(did.index) } - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec - { - self.dep_graph.read(DepNode::MetaData(def_id)); - self.get_crate_data(def_id.krate).get_inherent_implementations_for_type(def_id.index) - } - fn implementations_of_trait(&self, filter: Option) -> Vec { if let Some(def_id) = filter { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index dfa7ababca0bb..5b0418921563a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -479,14 +479,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - // Read the inherent implementation candidates for this type from the - // metadata if necessary. - self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id); - - if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) { - for &impl_def_id in impl_infos.iter() { - self.assemble_inherent_impl_probe(impl_def_id); - } + let impl_def_ids = ty::queries::inherent_impls::get(self.tcx, self.span, def_id); + for &impl_def_id in impl_def_ids.iter() { + self.assemble_inherent_impl_probe(impl_def_id); } } diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent_impls.rs similarity index 71% rename from src/librustc_typeck/coherence/inherent.rs rename to src/librustc_typeck/coherence/inherent_impls.rs index 9abf233de1f9e..3a39df505eb07 100644 --- a/src/librustc_typeck/coherence/inherent.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -8,26 +8,82 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! The code in this module gathers up all of the inherent impls in +//! the current crate and organizes them in a map. It winds up +//! touching the whole crate and thus must be recomputed completely +//! for any change, but it is very cheap to compute. In practice, most +//! code in the compiler never *directly* requests this map. Instead, +//! it requests the inherent impls specific to some type (via +//! `ty::queries::inherent_impls::get(def_id)`). That value, however, +//! is computed by selecting an idea from this table. + use rustc::dep_graph::DepNode; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::lint; -use rustc::traits::{self, Reveal}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, CrateInherentImpls, TyCtxt}; +use rustc::util::nodemap::DefIdMap; +use std::rc::Rc; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; + +/// On-demand query: yields a map containing all types mapped to their inherent impls. +pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + crate_num: CrateNum) + -> CrateInherentImpls { + assert_eq!(crate_num, LOCAL_CRATE); + + let krate = tcx.hir.krate(); + let mut collect = InherentCollect { + tcx, + impls_map: CrateInherentImpls { + inherent_impls: DefIdMap() + } + }; + krate.visit_all_item_likes(&mut collect); + collect.impls_map +} + +/// On-demand query: yields a vector of the inherent impls for a specific type. +pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty_def_id: DefId) + -> Rc> { + assert!(ty_def_id.is_local()); + + // NB. Until we adopt the red-green dep-tracking algorithm (see + // [the plan] for details on that), we do some hackery here to get + // the dependencies correct. Basically, we use a `with_ignore` to + // read the result we want. If we didn't have the `with_ignore`, + // we would wind up with a dependency on the entire crate, which + // we don't want. Then we go and add dependencies on all the impls + // in the result (which is what we wanted). + // + // The result is a graph with an edge from `Hir(I)` for every impl + // `I` defined on some type `T` to `CoherentInherentImpls(T)`, + // thus ensuring that if any of those impls change, the set of + // inherent impls is considered dirty. + // + // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4 + + let result = tcx.dep_graph.with_ignore(|| { + let crate_map = ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, ty_def_id.krate); + match crate_map.inherent_impls.get(&ty_def_id) { + Some(v) => v.clone(), + None => Rc::new(vec![]), + } + }); + + for &impl_def_id in &result[..] { + tcx.dep_graph.read(DepNode::Hir(impl_def_id)); + } -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, - &mut InherentCollect { tcx }); - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, - &mut InherentOverlapChecker { tcx }); + result } struct InherentCollect<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> + tcx: TyCtxt<'a, 'tcx, 'tcx>, + impls_map: CrateInherentImpls, } impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { @@ -216,25 +272,19 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { } impl<'a, 'tcx> InherentCollect<'a, 'tcx> { - fn check_def_id(&self, item: &hir::Item, def_id: DefId) { + fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) { if def_id.is_local() { // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. let impl_def_id = self.tcx.hir.local_def_id(item.id); + let mut rc_vec = self.impls_map.inherent_impls + .entry(def_id) + .or_insert_with(|| Rc::new(vec![])); - // Subtle: it'd be better to collect these into a local map - // and then write the vector only once all items are known, - // but that leads to degenerate dep-graphs. The problem is - // that the write of that big vector winds up having reads - // from *all* impls in the krate, since we've lost the - // precision basically. This would be ok in the firewall - // model so once we've made progess towards that we can modify - // the strategy here. In the meantime, using `push` is ok - // because we are doing this as a pre-pass before anyone - // actually reads from `inherent_impls` -- and we know this is - // true beacuse we hold the refcell lock. - self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id); + // At this point, there should not be any clones of the + // `Rc`, so we can still safely push into it in place: + Rc::get_mut(&mut rc_vec).unwrap().push(impl_def_id); } else { struct_span_err!(self.tcx.sess, item.span, @@ -273,85 +323,3 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> { } } -struct InherentOverlapChecker<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> -} - -impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { - fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { - #[derive(Copy, Clone, PartialEq)] - enum Namespace { - Type, - Value, - } - - let name_and_namespace = |def_id| { - let item = self.tcx.associated_item(def_id); - (item.name, match item.kind { - ty::AssociatedKind::Type => Namespace::Type, - ty::AssociatedKind::Const | - ty::AssociatedKind::Method => Namespace::Value, - }) - }; - - let impl_items1 = self.tcx.associated_item_def_ids(impl1); - let impl_items2 = self.tcx.associated_item_def_ids(impl2); - - for &item1 in &impl_items1[..] { - let (name, namespace) = name_and_namespace(item1); - - for &item2 in &impl_items2[..] { - if (name, namespace) == name_and_namespace(item2) { - let msg = format!("duplicate definitions with name `{}`", name); - let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); - self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, - node_id, - self.tcx.span_of_impl(item1).unwrap(), - msg); - } - } - } - } - - fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id)); - - let inherent_impls = self.tcx.maps.inherent_impls.borrow(); - let impls = match inherent_impls.get(&ty_def_id) { - Some(impls) => impls, - None => return, - }; - - for (i, &impl1_def_id) in impls.iter().enumerate() { - for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { - self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) - } - }); - } - } - } -} - -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { - fn visit_item(&mut self, item: &'v hir::Item) { - match item.node { - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemTrait(..) | - hir::ItemUnion(..) => { - let type_def_id = self.tcx.hir.local_def_id(item.id); - self.check_for_overlapping_inherent_impls(type_def_id); - } - _ => {} - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { - } - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { - } -} - diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs new file mode 100644 index 0000000000000..4b36072243c81 --- /dev/null +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -0,0 +1,102 @@ +// Copyright 2017 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 rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::lint; +use rustc::traits::{self, Reveal}; +use rustc::ty::{self, TyCtxt}; + +use syntax_pos::DUMMY_SP; + +pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + crate_num: CrateNum) { + assert_eq!(crate_num, LOCAL_CRATE); + let krate = tcx.hir.krate(); + krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx }); +} + +struct InherentOverlapChecker<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx> +} + +impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { + fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { + #[derive(Copy, Clone, PartialEq)] + enum Namespace { + Type, + Value, + } + + let name_and_namespace = |def_id| { + let item = self.tcx.associated_item(def_id); + (item.name, match item.kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + }) + }; + + let impl_items1 = self.tcx.associated_item_def_ids(impl1); + let impl_items2 = self.tcx.associated_item_def_ids(impl2); + + for &item1 in &impl_items1[..] { + let (name, namespace) = name_and_namespace(item1); + + for &item2 in &impl_items2[..] { + if (name, namespace) == name_and_namespace(item2) { + let msg = format!("duplicate definitions with name `{}`", name); + let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); + self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, + node_id, + self.tcx.span_of_impl(item1).unwrap(), + msg); + } + } + } + } + + fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { + let impls = ty::queries::inherent_impls::get(self.tcx, DUMMY_SP, ty_def_id); + + for (i, &impl1_def_id) in impls.iter().enumerate() { + for &impl2_def_id in &impls[(i + 1)..] { + self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { + self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) + } + }); + } + } + } +} + +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { + fn visit_item(&mut self, item: &'v hir::Item) { + match item.node { + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemTrait(..) | + hir::ItemUnion(..) => { + let type_def_id = self.tcx.hir.local_def_id(item.id); + self.check_for_overlapping_inherent_impls(type_def_id); + } + _ => {} + } + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } +} + diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 6abd061e81f2a..b3a7b612dd5b8 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -24,7 +24,8 @@ use syntax::ast; use syntax_pos::DUMMY_SP; mod builtin; -mod inherent; +mod inherent_impls; +mod inherent_impls_overlap; mod orphan; mod overlap; mod unsafety; @@ -103,10 +104,14 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d pub fn provide(providers: &mut Providers) { use self::builtin::coerce_unsized_info; + use self::inherent_impls::{crate_inherent_impls, inherent_impls}; + use self::inherent_impls_overlap::crate_inherent_impls_overlap_check; *providers = Providers { coherent_trait, - coherent_inherent_impls, + crate_inherent_impls, + inherent_impls, + crate_inherent_impls_overlap_check, coerce_unsized_info, ..*providers }; @@ -126,10 +131,6 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, builtin::check_trait(tcx, def_id); } -fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) { - inherent::check(tcx); -} - pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::Coherence); for &trait_def_id in tcx.hir.krate().trait_impls.keys() { @@ -140,5 +141,7 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { orphan::check(tcx); overlap::check_default_impls(tcx); - ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); + // these queries are executed for side-effects (error reporting): + ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); + ty::queries::crate_inherent_impls_overlap_check::get(tcx, DUMMY_SP, LOCAL_CRATE); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c4476483186c7..cc30fdf56fc34 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -232,14 +232,12 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; - tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did); let mut impls = Vec::new(); - if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) { - for &did in i.iter() { - build_impl(cx, did, &mut impls); - } + for &did in ty::queries::inherent_impls::get(tcx, DUMMY_SP, did).iter() { + build_impl(cx, did, &mut impls); } + // If this is the first time we've inlined something from another crate, then // we inline *all* impls from all the crates into this crate. Note that there's // currently no way for us to filter this based on type, and we likely need From 425c1a3a052d072dd53719a27454e905af8e954c Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:29:04 -0400 Subject: [PATCH 232/662] Add contribution instructions to stdlib docs --- src/libstd/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 064144dcd6818..c6b6d3ab5b0d9 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -94,6 +94,12 @@ //! compiler - but they are documented here the same). Like the prelude, the //! standard macros are imported by default into all crates. //! +//! # Contributing changes to the documentation +//! +//! The source for this documentation can be found on [github](https://github.com/rust-lang/rust/tree/master/src/libstd). +//! To contribute changes, you can search for nearby strings in github to find +//! relevant files, then submit pull-requests with your suggested changes. +//! //! # A Tour of The Rust Standard Library //! //! The rest of this crate documentation is dedicated to pointing out notable From 53d5082a2d08060ebca869cb8ee97c3ed3cf4ce9 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:42:39 -0400 Subject: [PATCH 233/662] requested changes --- src/libstd/io/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index dda9d6bca7977..60b211a746ff1 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -144,7 +144,8 @@ //! # Ok(()) //! # } //! ``` -//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main()`). +//! +//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main`). //! Instead, you can `match` on the return value to catch any possible errors: //! //! ``` From 04fbec1a0cb7467834bd264b80350b1cade8b4ca Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:43:09 -0400 Subject: [PATCH 234/662] newline for breathing room --- src/libstd/io/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 60b211a746ff1..773b0964b4269 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -150,6 +150,7 @@ //! //! ``` //! let mut input = String::new(); +//! //! match io::stdin().read_line(&mut input) { //! Err(why) => panic!("Failed to read input: {}", why.description()), //! Ok(_) => println!("You typed: {}", input.trim()), From 7665991e3e502a534803bd1ac94c16ffd557ed95 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:48:32 -0400 Subject: [PATCH 235/662] add link to contribution guidelines and IRC room --- src/libstd/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c6b6d3ab5b0d9..ab1167e20b1db 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -96,9 +96,13 @@ //! //! # Contributing changes to the documentation //! -//! The source for this documentation can be found on [github](https://github.com/rust-lang/rust/tree/master/src/libstd). -//! To contribute changes, you can search for nearby strings in github to find -//! relevant files, then submit pull-requests with your suggested changes. +//! Check out the rust contribution guidelines [here](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). +//! The source for this documentation can be found on [Github](https://github.com/rust-lang/rust/tree/master/src/libstd). +//! To contribute changes, make sure you read the guidelines first, then submit +//! pull-requests for your suggested changes. +//! +//! Contributions are appreciated! If you see a part of the docs that can be +//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust. //! //! # A Tour of The Rust Standard Library //! From a3a5ff98eba2f81ec76b18cce50f113f59181cce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Mar 2017 14:18:25 -0400 Subject: [PATCH 236/662] move `export_map` into the tcx --- src/librustc/middle/cstore.rs | 12 ++++++------ src/librustc/ty/context.rs | 6 +++++- src/librustc/ty/mod.rs | 2 +- src/librustc_driver/driver.rs | 6 +++--- src/librustc_metadata/cstore_impl.rs | 6 +++--- src/librustc_metadata/encoder.rs | 6 +----- src/librustc_privacy/lib.rs | 10 +++------- src/librustc_trans/base.rs | 4 +--- src/librustc_trans/context.rs | 12 ------------ src/librustdoc/core.rs | 6 ++---- src/librustdoc/visit_ast.rs | 2 +- 11 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 225d6fc9bb2b2..56bbc0480c30a 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -255,8 +255,8 @@ pub trait CrateStore { fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>; fn used_crate_source(&self, cnum: CrateNum) -> CrateSource; fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, reachable: &NodeSet) -> Vec; fn metadata_encoding_version(&self) -> &[u8]; @@ -412,10 +412,10 @@ impl CrateStore for DummyCrateStore { { vec![] } fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, - link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec { vec![] } + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + link_meta: &LinkMeta, + reachable: &NodeSet) -> Vec { vec![] } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5543223105b44..da56514ea82fb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -15,7 +15,7 @@ use session::Session; use lint; use middle; use hir::TraitMap; -use hir::def::Def; +use hir::def::{Def, ExportMap}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DisambiguatedDefPathData; @@ -416,6 +416,9 @@ pub struct GlobalCtxt<'tcx> { /// is relevant; generated by resolve. pub trait_map: TraitMap, + /// Export map produced by name resolution. + pub export_map: ExportMap, + pub named_region_map: resolve_lifetime::NamedRegionMap, pub region_maps: RegionMaps, @@ -698,6 +701,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { region_maps: region_maps, variance_computed: Cell::new(false), trait_map: resolutions.trait_map, + export_map: resolutions.export_map, fulfilled_predicates: RefCell::new(fulfilled_predicates), hir: hir, maps: maps::Maps::new(dep_graph, providers), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36d1ae74e9114..0bcfae1e54a69 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -110,7 +110,6 @@ mod sty; /// produced by the driver and fed to trans and later passes. #[derive(Clone)] pub struct CrateAnalysis { - pub export_map: ExportMap, pub access_levels: middle::privacy::AccessLevels, pub reachable: NodeSet, pub name: String, @@ -122,6 +121,7 @@ pub struct Resolutions { pub freevars: FreevarMap, pub trait_map: TraitMap, pub maybe_unused_trait_imports: NodeSet, + pub export_map: ExportMap, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d37553d7d660e..4947cafb52b3d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -807,7 +807,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, expanded_crate: krate, defs: resolver.definitions, analysis: ty::CrateAnalysis { - export_map: resolver.export_map, access_levels: AccessLevels::default(), reachable: NodeSet(), name: crate_name.to_string(), @@ -815,10 +814,11 @@ pub fn phase_2_configure_and_expand(sess: &Session, }, resolutions: Resolutions { freevars: resolver.freevars, + export_map: resolver.export_map, trait_map: resolver.trait_map, maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, }, - hir_forest: hir_forest + hir_forest: hir_forest, }) } @@ -932,7 +932,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, analysis.access_levels = time(time_passes, "privacy checking", || { - rustc_privacy::check_crate(tcx, &analysis.export_map) + rustc_privacy::check_crate(tcx) }); time(time_passes, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2a67b79eaa52e..17484138ad3a0 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -496,12 +496,12 @@ impl CrateStore for cstore::CStore { self.do_extern_mod_stmt_cnum(emod_id) } - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, reachable: &NodeSet) -> Vec { - encoder::encode_metadata(tcx, self, reexports, link_meta, reachable) + encoder::encode_metadata(tcx, self, link_meta, reachable) } fn metadata_encoding_version(&self) -> &[u8] diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 044ed529ef74c..a324c166e738d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -13,7 +13,6 @@ use index::Index; use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; -use rustc::hir::def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; use rustc::middle::dependency_format::Linkage; @@ -48,7 +47,6 @@ use super::index_builder::{FromId, IndexBuilder, Untracked}; pub struct EncodeContext<'a, 'tcx: 'a> { opaque: opaque::Encoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &'a def::ExportMap, link_meta: &'a LinkMeta, cstore: &'a cstore::CStore, exported_symbols: &'a NodeSet, @@ -306,7 +304,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = tcx.hir.local_def_id(id); let data = ModData { - reexports: match self.reexports.get(&id) { + reexports: match tcx.export_map.get(&id) { Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports), _ => LazySeq::empty(), }, @@ -1423,7 +1421,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, - reexports: &def::ExportMap, link_meta: &LinkMeta, exported_symbols: &NodeSet) -> Vec { @@ -1437,7 +1434,6 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut ecx = EncodeContext { opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, - reexports: reexports, link_meta: link_meta, cstore: cstore, exported_symbols: exported_symbols, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index e32ec25a7e8f7..6b33c7b7816f0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -27,7 +27,7 @@ extern crate syntax_pos; use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; -use rustc::hir::def::{self, Def}; +use rustc::hir::def::Def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; @@ -71,7 +71,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> { struct EmbargoVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - export_map: &'a def::ExportMap, // Accessibility levels for reachable nodes access_levels: AccessLevels, @@ -324,7 +323,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // This code is here instead of in visit_item so that the // crate module gets processed as well. if self.prev_level.is_some() { - if let Some(exports) = self.export_map.get(&id) { + if let Some(exports) = self.tcx.export_map.get(&id) { for export in exports { if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) { self.update(node_id, Some(AccessLevel::Exported)); @@ -1204,9 +1203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> fn visit_pat(&mut self, _: &'tcx hir::Pat) {} } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - export_map: &def::ExportMap) - -> AccessLevels { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AccessLevels { let _task = tcx.dep_graph.in_task(DepNode::Privacy); let krate = tcx.hir.krate(); @@ -1226,7 +1223,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { tcx: tcx, - export_map: export_map, access_levels: Default::default(), prev_level: Some(AccessLevel::Public), changed: false, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 80b563729f5ce..f7ca468fddaef 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -755,7 +755,6 @@ fn write_metadata(cx: &SharedCrateContext, let cstore = &cx.tcx().sess.cstore; let metadata = cstore.encode_metadata(cx.tcx(), - cx.export_map(), cx.link_meta(), exported_symbols); if kind == MetadataKind::Uncompressed { @@ -1056,7 +1055,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // particular items that will be processed. let krate = tcx.hir.krate(); - let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis; + let ty::CrateAnalysis { reachable, name, .. } = analysis; let exported_symbols = find_exported_symbols(tcx, reachable); let check_overflow = tcx.sess.overflow_checks(); @@ -1064,7 +1063,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let link_meta = link::build_link_meta(incremental_hashes_map, &name); let shared_ccx = SharedCrateContext::new(tcx, - export_map, link_meta.clone(), exported_symbols, check_overflow); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1c1395f1b7762..73602dc420b3f 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -14,7 +14,6 @@ use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir; -use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; use rustc::traits; use debuginfo; @@ -68,7 +67,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { metadata_llmod: ModuleRef, metadata_llcx: ContextRef, - export_map: ExportMap, exported_symbols: NodeSet, link_meta: LinkMeta, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -402,7 +400,6 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, - export_map: ExportMap, link_meta: LinkMeta, exported_symbols: NodeSet, check_overflow: bool) @@ -459,7 +456,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { SharedCrateContext { metadata_llmod: metadata_llmod, metadata_llcx: metadata_llcx, - export_map: export_map, exported_symbols: exported_symbols, link_meta: link_meta, empty_param_env: tcx.empty_parameter_environment(), @@ -499,10 +495,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { self.metadata_llcx } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { - &self.export_map - } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { &self.exported_symbols } @@ -702,10 +694,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { - &self.shared.export_map - } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { &self.shared.exported_symbols } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0a9db2c26464c..92aba1fc61de3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,7 @@ use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::hir::def_id::DefId; -use rustc::hir::def::{Def, ExportMap}; +use rustc::hir::def::Def; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt, GlobalArenas}; use rustc::hir::map as hir_map; @@ -64,7 +64,6 @@ pub struct DocContext<'a, 'tcx: 'a> { pub ty_substs: RefCell>, /// Table node id of lifetime parameter definition -> substituted lifetime pub lt_substs: RefCell>, - pub export_map: ExportMap, } impl<'a, 'tcx> DocContext<'a, 'tcx> { @@ -180,7 +179,7 @@ pub fn run_core(search_paths: SearchPaths, sess.fatal("Compilation failed, aborting rustdoc"); } - let ty::CrateAnalysis { access_levels, export_map, .. } = analysis; + let ty::CrateAnalysis { access_levels, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid @@ -198,7 +197,6 @@ pub fn run_core(search_paths: SearchPaths, renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), - export_map: export_map, }; debug!("crate: {:?}", tcx.hir.krate()); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4a909f8e2a972..2793307697852 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -198,7 +198,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.visit_item(item, None, &mut om); } self.inside_public_path = orig_inside_public_path; - if let Some(exports) = self.cx.export_map.get(&id) { + if let Some(exports) = self.cx.tcx.export_map.get(&id) { for export in exports { if let Def::Macro(def_id, ..) = export.def { if def_id.krate == LOCAL_CRATE { From e341d603fe7c35ce174bd2e54e47ed6941ea4b03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Feb 2017 07:57:59 -0800 Subject: [PATCH 237/662] Remove internal liblog This commit deletes the internal liblog in favor of the implementation that lives on crates.io. Similarly it's also setting a convention for adding crates to the compiler. The main restriction right now is that we want compiler implementation details to be unreachable from normal Rust code (e.g. requires a feature), and by default everything in the sysroot is reachable via `extern crate`. The proposal here is to require that crates pulled in have these lines in their `src/lib.rs`: #![cfg_attr(rustbuild, feature(staged_api, rustc_private))] #![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] This'll mean that by default they're not using these attributes but when compiled as part of the compiler they do a few things: * Mark themselves as entirely unstable via the `staged_api` feature and the `#![unstable]` attribute. * Allow usage of other unstable crates via `feature(rustc_private)` which is required if the crate relies on any other crates to compile (other than std). --- src/Cargo.lock | 53 +- src/liblog/Cargo.toml | 9 - src/liblog/directive.rs | 193 ------- src/liblog/lib.rs | 506 ------------------ src/liblog/macros.rs | 205 ------- src/librustc/Cargo.toml | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/ty/item_path.rs | 3 +- src/librustc_back/Cargo.toml | 2 +- src/librustc_borrowck/Cargo.toml | 2 +- src/librustc_const_eval/Cargo.toml | 2 +- src/librustc_data_structures/Cargo.toml | 2 +- src/librustc_driver/Cargo.toml | 3 +- src/librustc_driver/driver.rs | 4 +- src/librustc_driver/lib.rs | 2 + src/librustc_incremental/Cargo.toml | 2 +- src/librustc_lint/Cargo.toml | 2 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_mir/Cargo.toml | 2 +- src/librustc_passes/Cargo.toml | 4 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_save_analysis/Cargo.toml | 2 +- src/librustc_trans/Cargo.toml | 2 +- src/librustc_typeck/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 5 +- src/librustdoc/lib.rs | 2 + src/libsyntax/Cargo.toml | 2 +- src/libsyntax_ext/Cargo.toml | 2 +- .../auxiliary/logging_right_crate.rs | 18 - .../conditional-debug-macro-off.rs | 23 - .../logging-enabled-debug.rs | 24 - src/test/run-pass-fulldeps/logging-enabled.rs | 27 - .../run-pass-fulldeps/logging-right-crate.rs | 31 -- .../logging-separate-lines.rs | 40 -- src/test/run-pass-fulldeps/rust-log-filter.rs | 58 -- .../run-pass/conditional-debug-macro-on.rs | 2 - src/tools/compiletest/Cargo.toml | 2 +- 38 files changed, 54 insertions(+), 1194 deletions(-) delete mode 100644 src/liblog/Cargo.toml delete mode 100644 src/liblog/directive.rs delete mode 100644 src/liblog/lib.rs delete mode 100644 src/liblog/macros.rs delete mode 100644 src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs delete mode 100644 src/test/run-pass-fulldeps/conditional-debug-macro-off.rs delete mode 100644 src/test/run-pass-fulldeps/logging-enabled-debug.rs delete mode 100644 src/test/run-pass-fulldeps/logging-enabled.rs delete mode 100644 src/test/run-pass-fulldeps/logging-right-crate.rs delete mode 100644 src/test/run-pass-fulldeps/logging-separate-lines.rs delete mode 100644 src/test/run-pass-fulldeps/rust-log-filter.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 9ae894061a676..a0b47f4f0b2bb 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -147,7 +147,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -162,14 +162,6 @@ name = "dtoa" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.4.2" @@ -270,10 +262,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "linkchecker" version = "0.1.0" -[[package]] -name = "log" -version = "0.0.0" - [[package]] name = "log" version = "0.3.7" @@ -439,7 +427,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -479,7 +467,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -493,7 +481,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -508,7 +496,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -530,7 +518,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -539,8 +527,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -579,7 +568,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -591,7 +580,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -623,7 +612,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -642,7 +631,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -666,7 +655,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -705,7 +694,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -716,7 +705,7 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -730,7 +719,7 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -762,7 +751,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -780,8 +769,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -857,7 +847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -870,7 +860,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -996,7 +986,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml deleted file mode 100644 index 31a862478d034..0000000000000 --- a/src/liblog/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "log" -version = "0.0.0" - -[lib] -name = "log" -path = "lib.rs" -crate-type = ["dylib", "rlib"] diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs deleted file mode 100644 index eb50d6e6135ef..0000000000000 --- a/src/liblog/directive.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ascii::AsciiExt; -use std::cmp; - -#[derive(Debug, Clone)] -pub struct LogDirective { - pub name: Option, - pub level: u32, -} - -pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; - -/// Parse an individual log level that is either a number or a symbolic log level -fn parse_log_level(level: &str) -> Option { - level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) -} - -/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") -/// and return a vector with log directives. -/// -/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in -/// std::). Also supports string log levels of error, warn, info, and debug -pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { - let mut dirs = Vec::new(); - - let mut parts = spec.split('/'); - let mods = parts.next(); - let filter = parts.next(); - if parts.next().is_some() { - println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", - spec); - return (dirs, None); - } - if let Some(m) = mods { - for s in m.split(',') { - if s.is_empty() { - continue; - } - let mut parts = s.split('='); - let (log_level, name) = - match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), - } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; - } - } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - } - } - - (dirs, filter.map(str::to_owned)) -} - -#[cfg(test)] -mod tests { - use super::parse_logging_spec; - - #[test] - fn parse_logging_spec_valid() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_crate() { - // test parse_logging_spec with multiple = in specification - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_log_level() { - // test parse_logging_spec with 'noNumber' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_string_log_level() { - // test parse_logging_spec with 'warn' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::WARN); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_empty_log_level() { - // test parse_logging_spec with '' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_global() { - // test parse_logging_spec with no crate - let (dirs, filter) = parse_logging_spec("warn,crate2=4"); - assert_eq!(dirs.len(), 2); - assert_eq!(dirs[0].name, None); - assert_eq!(dirs[0].level, 2); - assert_eq!(dirs[1].name, Some("crate2".to_owned())); - assert_eq!(dirs[1].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_valid_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "abc"); - } - - #[test] - fn parse_logging_spec_invalid_crate_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c"); - } - - #[test] - fn parse_logging_spec_empty_with_filter() { - let (dirs, filter) = parse_logging_spec("crate1/a*c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate1".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c"); - } -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs deleted file mode 100644 index 057df647c7257..0000000000000 --- a/src/liblog/lib.rs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for program-wide and customizable logging -//! -//! # Examples -//! -//! ``` -//! # #![feature(rustc_private)] -//! #[macro_use] extern crate log; -//! -//! fn main() { -//! debug!("this is a debug {:?}", "message"); -//! error!("this is printed by default"); -//! -//! if log_enabled!(log::INFO) { -//! let x = 3 * 4; // expensive computation -//! info!("the answer was: {:?}", x); -//! } -//! } -//! ``` -//! -//! Assumes the binary is `main`: -//! -//! ```{.bash} -//! $ RUST_LOG=error ./main -//! ERROR:main: this is printed by default -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=debug ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! You can also set the log level on a per module basis: -//! -//! ```{.bash} -//! $ RUST_LOG=main=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! And enable all logging: -//! -//! ```{.bash} -//! $ RUST_LOG=main ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! # Logging Macros -//! -//! There are five macros that the logging subsystem uses: -//! -//! * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any -//! related `format!` arguments -//! * `debug!(...)` - a macro hard-wired to the log level of `DEBUG` -//! * `info!(...)` - a macro hard-wired to the log level of `INFO` -//! * `warn!(...)` - a macro hard-wired to the log level of `WARN` -//! * `error!(...)` - a macro hard-wired to the log level of `ERROR` -//! -//! All of these macros use the same style of syntax as the `format!` syntax -//! extension. Details about the syntax can be found in the documentation of -//! `std::fmt` along with the Rust tutorial/manual. -//! -//! If you want to check at runtime if a given logging level is enabled (e.g. if the -//! information you would want to log is expensive to produce), you can use the -//! following macro: -//! -//! * `log_enabled!(level)` - returns true if logging of the given level is enabled -//! -//! # Enabling logging -//! -//! Log levels are controlled on a per-module basis, and by default all logging is -//! disabled except for `error!` (a log level of 1). Logging is controlled via the -//! `RUST_LOG` environment variable. The value of this environment variable is a -//! comma-separated list of logging directives. A logging directive is of the form: -//! -//! ```text -//! path::to::module=log_level -//! ``` -//! -//! The path to the module is rooted in the name of the crate it was compiled for, -//! so if your program is contained in a file `hello.rs`, for example, to turn on -//! logging for this file you would use a value of `RUST_LOG=hello`. -//! Furthermore, this path is a prefix-search, so all modules nested in the -//! specified module will also have logging enabled. -//! -//! The actual `log_level` is optional to specify. If omitted, all logging will be -//! enabled. If specified, the it must be either a numeric in the range of 1-255, or -//! it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric -//! is specified, then all logging less than or equal to that numeral is enabled. -//! For example, if logging level 3 is active, error, warn, and info logs will be -//! printed, but debug will be omitted. -//! -//! As the log level for a module is optional, the module to enable logging for is -//! also optional. If only a `log_level` is provided, then the global log level for -//! all modules is set to this value. -//! -//! Some examples of valid values of `RUST_LOG` are: -//! -//! * `hello` turns on all logging for the 'hello' module -//! * `info` turns on all info logging -//! * `hello=debug` turns on debug logging for 'hello' -//! * `hello=3` turns on info logging for 'hello' -//! * `hello,std::option` turns on hello, and std's option logging -//! * `error,hello=warn` turn on global error logging and also warn for hello -//! -//! # Filtering results -//! -//! A RUST_LOG directive may include a string filter. The syntax is to append -//! `/` followed by a string. Each message is checked against the string and is -//! only logged if it contains the string. Note that the matching is done after -//! formatting the log string but before adding any logging meta-data. There is -//! a single filter for all modules. -//! -//! Some examples: -//! -//! * `hello/foo` turns on all logging for the 'hello' module where the log message -//! includes 'foo'. -//! * `info/f.o` turns on all info logging where the log message includes 'foo', -//! 'f1o', 'fao', etc. -//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log -//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. -//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also warn for -//! hello. In both cases the log message must include a single digit number -//! followed by 'scopes' -//! -//! # Performance and Side Effects -//! -//! Each of these macros will expand to code similar to: -//! -//! ```rust,ignore -//! if log_level <= my_module_log_level() { -//! ::log::log(log_level, format!(...)); -//! } -//! ``` -//! -//! What this means is that each of these macros are very cheap at runtime if -//! they're turned off (just a load and an integer comparison). This also means that -//! if logging is disabled, none of the components of the log will be executed. - -#![crate_name = "log"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `log` library instead", - issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![deny(warnings)] - -#![feature(staged_api)] - -use std::cell::RefCell; -use std::fmt; -use std::io::{self, Stderr}; -use std::io::prelude::*; -use std::mem; -use std::env; -use std::slice; -use std::sync::{Mutex, ONCE_INIT, Once}; - -use directive::LOG_LEVEL_NAMES; - -#[macro_use] -pub mod macros; - -mod directive; - -/// Maximum logging level of a module that can be specified. Common logging -/// levels are found in the DEBUG/INFO/WARN/ERROR constants. -pub const MAX_LOG_LEVEL: u32 = 255; - -/// The default logging level of a crate if no other is specified. -const DEFAULT_LOG_LEVEL: u32 = 1; - -static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; - -/// An unsafe constant that is the maximum logging level of any module -/// specified. This is the first line of defense to determining whether a -/// logging statement should be run. -static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; - -/// Debug log level -pub const DEBUG: u32 = 4; -/// Info log level -pub const INFO: u32 = 3; -/// Warn log level -pub const WARN: u32 = 2; -/// Error log level -pub const ERROR: u32 = 1; - -thread_local! { - static LOCAL_LOGGER: RefCell>> = { - RefCell::new(None) - } -} - -/// A trait used to represent an interface to a thread-local logger. Each thread -/// can have its own custom logger which can respond to logging messages -/// however it likes. -pub trait Logger { - /// Logs a single message described by the `record`. - fn log(&mut self, record: &LogRecord); -} - -struct DefaultLogger { - handle: Stderr, -} - -/// Wraps the log level with fmt implementations. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub struct LogLevel(pub u32); - -impl fmt::Display for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - match LOG_LEVEL_NAMES.get(level as usize - 1) { - Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt), - } - } -} - -impl Logger for DefaultLogger { - fn log(&mut self, record: &LogRecord) { - match writeln!(&mut self.handle, - "{}:{}: {}", - record.level, - record.module_path, - record.args) { - Err(e) => panic!("failed to log: {:?}", e), - Ok(()) => {} - } - } -} - -impl Drop for DefaultLogger { - fn drop(&mut self) { - // FIXME(#12628): is panicking the right thing to do? - match self.handle.flush() { - Err(e) => panic!("failed to flush a logger: {:?}", e), - Ok(()) => {} - } - } -} - -/// This function is called directly by the compiler when using the logging -/// macros. This function does not take into account whether the log level -/// specified is active or not, it will always log something if this method is -/// called. -/// -/// It is not recommended to call this function directly, rather it should be -/// invoked through the logging family of macros. -#[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { - // Test the literal string from args against the current filter, if there - // is one. - unsafe { - let filter = (*LOCK).lock().unwrap(); - if let Some(ref filter) = filter.1 { - if !args.to_string().contains(filter) { - return; - } - } - } - - // Completely remove the local logger from TLS in case anyone attempts to - // frob the slot while we're doing the logging. This will destroy any logger - // set during logging. - let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); - logger.log(&LogRecord { - level: LogLevel(level), - args: args, - file: loc.file, - module_path: loc.module_path, - line: loc.line, - }); - set_logger(logger); -} - -/// Getter for the global log level. This is a function so that it can be called -/// safely -#[doc(hidden)] -#[inline(always)] -pub fn log_level() -> u32 { - unsafe { LOG_LEVEL } -} - -/// Replaces the thread-local logger with the specified logger, returning the old -/// logger. -pub fn set_logger(logger: Box) -> Option> { - LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) -} - -/// A LogRecord is created by the logging macros, and passed as the only -/// argument to Loggers. -#[derive(Debug)] -pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. - pub module_path: &'a str, - - /// The LogLevel of this record. - pub level: LogLevel, - - /// The arguments from the log line. - pub args: fmt::Arguments<'a>, - - /// The file of where the LogRecord originated. - pub file: &'a str, - - /// The line number of where the LogRecord originated. - pub line: u32, -} - -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct LogLocation { - pub module_path: &'static str, - pub file: &'static str, - pub line: u32, -} - -/// Tests whether a given module's name is enabled for a particular level of -/// logging. This is the second layer of defense about determining whether a -/// module's log statement should be emitted or not. -#[doc(hidden)] -pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = ONCE_INIT; - INIT.call_once(init); - - // It's possible for many threads are in this function, only one of them - // will perform the global initialization, but all of them will need to check - // again to whether they should really be here or not. Hence, despite this - // check being expanded manually in the logging macro, this function checks - // the log level again. - if level > unsafe { LOG_LEVEL } { - return false; - } - - // This assertion should never get tripped unless we're in an at_exit - // handler after logging has been torn down and a logging attempt was made. - - unsafe { - let directives = (*LOCK).lock().unwrap(); - enabled(level, module, directives.0.iter()) - } -} - -fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { - // Search for the longest match, the vector is assumed to be pre-sorted. - for directive in iter.rev() { - match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {} - Some(..) | None => return level <= directive.level, - } - } - level <= DEFAULT_LOG_LEVEL -} - -/// Initialize logging for the current process. -/// -/// This is not threadsafe at all, so initialization is performed through a -/// `Once` primitive (and this function is called from that primitive). -fn init() { - let (mut directives, filter) = match env::var("RUST_LOG") { - Ok(spec) => directive::parse_logging_spec(&spec[..]), - Err(..) => (Vec::new(), None), - }; - - // Sort the provided directives by length of their name, this allows a - // little more efficient lookup at runtime. - directives.sort_by(|a, b| { - let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); - let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); - alen.cmp(&blen) - }); - - let max_level = { - let max = directives.iter().max_by_key(|d| d.level); - max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL) - }; - - unsafe { - LOG_LEVEL = max_level; - - assert!(LOCK.is_null()); - LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); - } -} - -#[cfg(test)] -mod tests { - use super::enabled; - use directive::LogDirective; - - #[test] - fn match_full_path() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(!enabled(3, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn no_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(!enabled(2, "crate3", dirs.iter())); - } - - #[test] - fn match_beginning() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(3, "crate2::mod1", dirs.iter())); - } - - #[test] - fn match_beginning_longest_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate2::mod".to_string()), - level: 4, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(4, "crate2::mod1", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn match_default() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } - - #[test] - fn zero_level() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 0, - }]; - assert!(!enabled(1, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } -} diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs deleted file mode 100644 index 803a2df9ccc8b..0000000000000 --- a/src/liblog/macros.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Logging macros - -/// The standard logging macro -/// -/// This macro will generically log over a provided level (of type u32) with a -/// format!-based argument list. See documentation in `std::fmt` for details on -/// how to use the syntax. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// log!(log::WARN, "this is a warning {}", "message"); -/// log!(log::DEBUG, "this is a debug message"); -/// log!(6, "this is a custom logging level: {level}", level=6); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=6 ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// 6:main: this is a custom logging level: 6 -/// ``` -#[macro_export] -macro_rules! log { - ($lvl:expr, $($arg:tt)+) => ({ - static LOC: ::log::LogLocation = ::log::LogLocation { - line: line!(), - file: file!(), - module_path: module_path!(), - }; - let lvl = $lvl; - if log_enabled!(lvl) { - ::log::log(lvl, &LOC, format_args!($($arg)+)) - } - }) -} - -/// A convenience macro for logging at the error log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let error = 3; -/// error!("the build has failed with error code: {}", error); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ERROR:main: the build has failed with error code: 3 -/// ``` -/// -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => (log!(::log::ERROR, $($arg)*)) -} - -/// A convenience macro for logging at the warning log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let code = 3; -/// warn!("you may like to know that a process exited with: {}", code); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: you may like to know that a process exited with: 3 -/// ``` -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => (log!(::log::WARN, $($arg)*)) -} - -/// A convenience macro for logging at the info log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let ret = 3; -/// info!("this function is about to return: {}", ret); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=info ./main -/// INFO:main: this function is about to return: 3 -/// ``` -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => (log!(::log::INFO, $($arg)*)) -} - -/// A convenience macro for logging at the debug log level. This macro will -/// be omitted at compile time in an optimized build unless `-C debug-assertions` -/// is passed to the compiler. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// debug!("x = {x}, y = {y}", x=10, y=20); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x = 10, y = 20 -/// ``` -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) }) -} - -/// A macro to test whether a log level is enabled for the current module. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// struct Point { x: i32, y: i32 } -/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } } -/// -/// fn main() { -/// if log_enabled!(log::DEBUG) { -/// let x = some_expensive_computation(); -/// debug!("x.x = {}, x.y = {}", x.x, x.y); -/// } -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x.x = 1, x.y = 2 -/// ``` -#[macro_export] -macro_rules! log_enabled { - ($lvl:expr) => ({ - let lvl = $lvl; - (lvl != ::log::DEBUG || cfg!(debug_assertions)) && - lvl <= ::log::log_level() && - ::log::mod_enabled(lvl, module_path!()) - }) -} diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 5d53c60ad7fdc..fa217acd9f9bf 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 583b3b848f30d..d7aa36b24f942 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -948,7 +948,7 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, intravisit::walk_crate(&mut collector, &forest.krate); let map = collector.map; - if log_enabled!(::log::DEBUG) { + if log_enabled!(::log::LogLevel::Debug) { // This only makes sense for ordered stores; note the // enumerate to count the number of entries. let (entries_less_1, _) = map.iter().filter(|&x| { diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 874e032bc4644..3869910529055 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -202,7 +202,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } else { // for local crates, check whether type info is // available; typeck might not have completed yet - self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) + self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) && + self.maps.ty.borrow().contains_key(&impl_def_id) }; if !use_types { diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml index 85e861b405a9f..730abc54568e1 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_back/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" [features] jemalloc = [] diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index d53318f176848..af99c0e938724 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 780b2c16a32ec..907410f74dca4 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d9871..343b1ed68b804 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index caa5c8b7e0058..5b5113caa8e8c 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = { version = "0.3", features = ["release_max_level_info"] } +env_logger = { version = "0.4", default-features = false } proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5d600270626cb..91f9a803f4a35 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -198,13 +198,13 @@ pub fn compile_input(sess: &Session, result?; - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); tcx.print_debug_stats(); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 62d7512655728..68b9f85721ad5 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate graphviz; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_back; @@ -1127,6 +1128,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { + env_logger::init().unwrap(); let result = run(|| run_compiler(&env::args().collect::>(), &mut RustcDefaultCalls, None, diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee752754504..7bf2efa4b885f 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -13,6 +13,6 @@ graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0ae1..c3c5461ff7c50 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6f7f03ca216b9..e8b906092730e 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index fcdb968dc0615..e1255110a83d1 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1058,7 +1058,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.inject_allocator_crate(); self.inject_panic_runtime(krate); - if log_enabled!(log::INFO) { + if log_enabled!(log::LogLevel::Info) { dump_crates(&self.cstore); } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 531be0b6ae9f5..6e42e02d5109b 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index cc710e0ac3563..d2560c2f8203f 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -9,10 +9,10 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file +rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 5ce4c74e735fd..0968ea31b754f 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } arena = { path = "../libarena" } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 06c5150fd13ad..07a5c266fc026 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index b5c67ad998b69..07dcb2fc29dc6 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -11,7 +11,7 @@ test = false [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index f08d26373e50e..07998aa4a30ea 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 93c0bd6d6d836..1c479ce1d0157 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,11 +11,13 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } +env_logger = { version = "0.4", default-features = false } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } -rustc_driver = { path = "../librustc_driver" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } @@ -24,7 +26,6 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 84f69cd35045c..8dd03f6edc4d5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -30,6 +30,7 @@ extern crate arena; extern crate getopts; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_const_eval; @@ -99,6 +100,7 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32_000_000; // 32MB + env_logger::init().unwrap(); let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b63f..97d37266130af 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 960db792a623e..bdcec26cb838b 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } diff --git a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs b/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs deleted file mode 100644 index db26b10fc67cb..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2013-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. - -#![feature(rustc_private)] - -#[macro_use] extern crate log; - -pub fn foo() { - fn death() -> isize { panic!() } - debug!("{}", (||{ death() })()); -} diff --git a/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs deleted file mode 100644 index c6beb5ba35875..0000000000000 --- a/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -// compile-flags: -C debug-assertions=no -// exec-env:RUST_LOG=conditional-debug-macro-off=4 - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - // only panics if println! evaluates its argument. - debug!("{:?}", { if true { panic!() } }); -} diff --git a/src/test/run-pass-fulldeps/logging-enabled-debug.rs b/src/test/run-pass-fulldeps/logging-enabled-debug.rs deleted file mode 100644 index 3ae4884ce47fc..0000000000000 --- a/src/test/run-pass-fulldeps/logging-enabled-debug.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2013-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. - -// compile-flags:-C debug-assertions=no -// exec-env:RUST_LOG=logging-enabled-debug=debug - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - if log_enabled!(log::DEBUG) { - panic!("what?! debugging?"); - } -} diff --git a/src/test/run-pass-fulldeps/logging-enabled.rs b/src/test/run-pass-fulldeps/logging-enabled.rs deleted file mode 100644 index 26261348020f8..0000000000000 --- a/src/test/run-pass-fulldeps/logging-enabled.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013-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. - -// exec-env:RUST_LOG=logging_enabled=info -// ignore-emscripten: FIXME(#31622) - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - if log_enabled!(log::DEBUG) { - panic!("what?! debugging?"); - } - if !log_enabled!(log::INFO) { - panic!("what?! no info?"); - } -} diff --git a/src/test/run-pass-fulldeps/logging-right-crate.rs b/src/test/run-pass-fulldeps/logging-right-crate.rs deleted file mode 100644 index 7caeeb401244b..0000000000000 --- a/src/test/run-pass-fulldeps/logging-right-crate.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013-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. - -// aux-build:logging_right_crate.rs -// exec-env:RUST_LOG=logging-right-crate=debug - -// This is a test for issue #3046 to make sure that when we monomorphize a -// function from one crate to another the right top-level logging name is -// preserved. -// -// It used to be the case that if logging were turned on for this crate, all -// monomorphized functions from other crates had logging turned on (their -// logging module names were all incorrect). This test ensures that this no -// longer happens by enabling logging for *this* crate and then invoking a -// function in an external crate which will panic when logging is enabled. - -// pretty-expanded FIXME #23616 - -extern crate logging_right_crate; - -pub fn main() { - // this function panicks if logging is turned on - logging_right_crate::foo::(); -} diff --git a/src/test/run-pass-fulldeps/logging-separate-lines.rs b/src/test/run-pass-fulldeps/logging-separate-lines.rs deleted file mode 100644 index 183a522bba749..0000000000000 --- a/src/test/run-pass-fulldeps/logging-separate-lines.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013-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. - -// ignore-windows -// exec-env:RUST_LOG=debug -// compile-flags:-C debug-assertions=y -// ignore-emscripten: FIXME(#31622) - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -use std::process::Command; -use std::env; -use std::str; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "child" { - debug!("foo"); - debug!("bar"); - return - } - - let p = Command::new(&args[0]) - .arg("child") - .output().unwrap(); - assert!(p.status.success()); - let mut lines = str::from_utf8(&p.stderr).unwrap().lines(); - assert!(lines.next().unwrap().contains("foo")); - assert!(lines.next().unwrap().contains("bar")); -} diff --git a/src/test/run-pass-fulldeps/rust-log-filter.rs b/src/test/run-pass-fulldeps/rust-log-filter.rs deleted file mode 100644 index 306d24e317754..0000000000000 --- a/src/test/run-pass-fulldeps/rust-log-filter.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// exec-env:RUST_LOG=rust_log_filter/foo -// ignore-emscripten no threads support - -#![allow(unknown_features)] -#![feature(box_syntax, std_misc, rustc_private)] - -#[macro_use] -extern crate log; - -use std::sync::mpsc::{channel, Sender, Receiver}; -use std::thread; - -pub struct ChannelLogger { - tx: Sender -} - -impl ChannelLogger { - pub fn new() -> (Box, Receiver) { - let (tx, rx) = channel(); - (box ChannelLogger { tx: tx }, rx) - } -} - -impl log::Logger for ChannelLogger { - fn log(&mut self, record: &log::LogRecord) { - self.tx.send(format!("{}", record.args)).unwrap(); - } -} - -pub fn main() { - let (logger, rx) = ChannelLogger::new(); - - let t = thread::spawn(move|| { - log::set_logger(logger); - - info!("foo"); - info!("bar"); - info!("foo bar"); - info!("bar foo"); - }); - - assert_eq!(rx.recv().unwrap(), "foo"); - assert_eq!(rx.recv().unwrap(), "foo bar"); - assert_eq!(rx.recv().unwrap(), "bar foo"); - assert!(rx.recv().is_err()); - - t.join(); -} diff --git a/src/test/run-pass/conditional-debug-macro-on.rs b/src/test/run-pass/conditional-debug-macro-on.rs index b335e20f91d93..7da33be7a57da 100644 --- a/src/test/run-pass/conditional-debug-macro-on.rs +++ b/src/test/run-pass/conditional-debug-macro-on.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// exec-env:RUST_LOG=conditional-debug-macro-on=4 - pub fn main() { // exits early if println! evaluates its arguments, otherwise it // will hit the panic. diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1fc98a78a7c47..7530b65a9b7c4 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -5,6 +5,6 @@ version = "0.0.0" [dependencies] log = "0.3" -env_logger = { version = "0.3.5", default-features = false } +env_logger = { version = "0.4", default-features = false } rustc-serialize = "0.3" filetime = "0.1" From 7bed84f17edf2e08e775773cc852895fa5e37b16 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 12:00:50 -0700 Subject: [PATCH 238/662] travis: See if OSX generates crash dumps I know for a fact we've had sccache segfault on various platforms and we've also historically had a lot of problems with the linker on OSX. Let's just poke around in the crash log directory to see if anything exists. If in the future we see a build we think segfaulted *and* there's contents here then we can add some bits that actually print out the logs. --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index b16957344ae1a..2b68df24ab0ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -153,9 +153,17 @@ after_failure: echo "#### Build failed; Disk usage after running script:"; df -h; du . | sort -nr | head -n100 + + # One of these is the linux sccache log, one is the OSX sccache log. Instead + # of worrying about what system we are just cat both. One of these commands + # will fail but that's ok, they'll both get executed. - cat obj/tmp/sccache.log - cat /tmp/sccache.log + # Random attempt at debugging currently. Just poking around in here to see if + # anything shows up. + - ls $HOME/Library/Logs/DiagnosticReports/ + # Save tagged docker images we created and load them if they're available before_cache: - docker history -q rust-ci | From 37fd1320bd3a61b51831ccd6f3a19c990a6b2b8d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 12:33:24 -0700 Subject: [PATCH 239/662] travis: Attempt to see if oom kills anything There's a suspicion that the OOM killer is killing sccache (maybe) so this adds some logging to test out that assumption to see if anything dies and is logged by `dmesg` --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2b68df24ab0ae..44e51e12874d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -164,6 +164,10 @@ after_failure: # anything shows up. - ls $HOME/Library/Logs/DiagnosticReports/ + # attempt to debug anything killed by the oom killer on linux, just to see if + # it happened + - dmesg | grep -i kill + # Save tagged docker images we created and load them if they're available before_cache: - docker history -q rust-ci | From c09083c3d1b077df9adf3d6b4048677a15ba666e Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Thu, 16 Mar 2017 00:11:44 -0400 Subject: [PATCH 240/662] Fix for #39596: sort Trait1 before Trait2. --- src/librustdoc/html/render.rs | 50 ++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 7b60d497932de..1f891177797dc 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1700,6 +1700,23 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) Ok(()) } +fn name_key(name: &str) -> (&str, u64, usize) { + // find number at end + let split = name.bytes().rposition(|b| b < b'0' || b'9' < b).map_or(0, |s| s + 1); + + // count leading zeroes + let after_zeroes = + name[split..].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra); + + // sort leading zeroes last + let num_zeroes = after_zeroes - split; + + match name[split..].parse() { + Ok(n) => (&name[..split], n, num_zeroes), + Err(_) => (name, 0, num_zeroes), + } +} + fn item_module(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, items: &[clean::Item]) -> fmt::Result { document(w, cx, item)?; @@ -1744,7 +1761,9 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less, _ => {} } - i1.name.cmp(&i2.name) + let lhs = i1.name.as_ref().map_or("", |s| &**s); + let rhs = i2.name.as_ref().map_or("", |s| &**s); + name_key(lhs).cmp(&name_key(rhs)) } indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2)); @@ -3198,3 +3217,32 @@ fn test_unique_id() { reset_ids(true); test(); } + +#[cfg(test)] +#[test] +fn test_name_key() { + assert_eq!(name_key("0"), ("", 0, 1)); + assert_eq!(name_key("123"), ("", 123, 0)); + assert_eq!(name_key("Fruit"), ("Fruit", 0, 0)); + assert_eq!(name_key("Fruit0"), ("Fruit", 0, 1)); + assert_eq!(name_key("Fruit0000"), ("Fruit", 0, 4)); + assert_eq!(name_key("Fruit01"), ("Fruit", 1, 1)); + assert_eq!(name_key("Fruit10"), ("Fruit", 10, 0)); + assert_eq!(name_key("Fruit123"), ("Fruit", 123, 0)); +} + +#[cfg(test)] +#[test] +fn test_name_sorting() { + let names = ["Apple", + "Banana", + "Fruit", "Fruit0", "Fruit00", + "Fruit1", "Fruit01", + "Fruit2", "Fruit02", + "Fruit20", + "Fruit100", + "Pear"]; + let mut sorted = names.to_owned(); + sorted.sort_by_key(|&s| name_key(s)); + assert_eq!(names, sorted); +} From bd52ff1cc3ff9ecce129d20ed56c61ec0b0c5653 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 24 Mar 2017 00:52:46 +0200 Subject: [PATCH 241/662] update LLVM with fix for PR32379 Fixes #40593. --- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- src/test/run-pass/auxiliary/llvm_pr32379.rs | 15 ++++++++++++++ src/test/run-pass/llvm-pr32379.rs | 23 +++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/auxiliary/llvm_pr32379.rs create mode 100644 src/test/run-pass/llvm-pr32379.rs diff --git a/src/llvm b/src/llvm index d5ef27a79661d..2e951c3ae354b 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit d5ef27a79661d4f0d57d7b7d2cdbe9204f790a4a +Subproject commit 2e951c3ae354bcbd2e50b30798e232949a926b75 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index be6d535dc732b..c8732e27b8252 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-03-19 +2017-03-23 diff --git a/src/test/run-pass/auxiliary/llvm_pr32379.rs b/src/test/run-pass/auxiliary/llvm_pr32379.rs new file mode 100644 index 0000000000000..a7b15bda33627 --- /dev/null +++ b/src/test/run-pass/auxiliary/llvm_pr32379.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +pub fn pr32379(mut data: u64, f1: bool, f2: bool) -> u64 { + if f1 { data &= !2; } + if f2 { data |= 2; } + data +} diff --git a/src/test/run-pass/llvm-pr32379.rs b/src/test/run-pass/llvm-pr32379.rs new file mode 100644 index 0000000000000..5625e81c0e63c --- /dev/null +++ b/src/test/run-pass/llvm-pr32379.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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_pr32379.rs + +// LLVM PR #32379 (https://bugs.llvm.org/show_bug.cgi?id=32379), which +// applies to upstream LLVM 3.9.1, is known to cause rustc itself to be +// miscompiled on ARM (Rust issue #40593). Because cross builds don't test +// our *compiler* on ARM, have a test for the miscompilation directly. + +extern crate llvm_pr32379; + +pub fn main() { + let val = llvm_pr32379::pr32379(2, false, false); + assert_eq!(val, 2); +} From 69c9d9b3b806148846459cd0e4e30f300686dd97 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Mar 2017 16:45:21 -0400 Subject: [PATCH 242/662] ignore reads of tracked state when there is no current task I realized that, even in the current system, such reads can't really do any harm. Because they are not part of a task, they will occur no matter what (only tasks can be skipped). If you leak the data you read into a task, that is bad, but that is equally bad if you are in a task. *Writes* to tracked state, on the other hand, should never occur except from within a task (and the task then records what things you read to compute it). Once we complete the shift to on-demand, these properties will hold by construction (because the on-demand struct enforces stateless tasks where leaks are impossible -- except by having shared mutable state in the tcx). --- src/librustc/dep_graph/edges.rs | 12 ++++++++---- src/librustc/dep_graph/shadow.rs | 10 ++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 8657a3e5a5878..5dbabcc923048 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -101,11 +101,15 @@ impl DepGraphEdges { } /// Indicates that the current task `C` reads `v` by adding an - /// edge from `v` to `C`. If there is no current task, panics. If - /// you want to suppress this edge, use `ignore`. + /// edge from `v` to `C`. If there is no current task, has no + /// effect. Note that *reading* from tracked state is harmless if + /// you are not in a task; what is bad is *writing* to tracked + /// state (and leaking data that you read into a tracked task). pub fn read(&mut self, v: DepNode) { - let source = self.make_node(v); - self.add_edge_from_current_node(|current| (source, current)) + if self.current_node().is_some() { + let source = self.make_node(v); + self.add_edge_from_current_node(|current| (source, current)) + } } /// Indicates that the current task `C` writes `v` by adding an diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index 5d4190a8ae1a3..bedb6ff2771f0 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -80,7 +80,13 @@ impl ShadowGraph { let mut stack = self.stack.borrow_mut(); match *message { - DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)), + // It is ok to READ shared state outside of a + // task. That can't do any harm (at least, the only + // way it can do harm is by leaking that data into a + // query or task, which would be a problem + // anyway). What would be bad is WRITING to that + // state. + DepMessage::Read(_) => { } DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), DepMessage::PushIgnore => stack.push(None), @@ -116,7 +122,7 @@ impl ShadowGraph { (None, None) => unreachable!(), // nothing on top of the stack - (None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n), + (None, Some(n)) | (Some(n), None) => bug!("write of {:?} but no current task", n), // this corresponds to an Ignore being top of the stack (Some(None), _) | (_, Some(None)) => (), From a9f6babcda1479f4e5566d1aadbf9a0d99aa3182 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Mar 2017 15:13:29 -0400 Subject: [PATCH 243/662] convert privacy access levels into a query --- src/librustc/dep_graph/dep_node.rs | 5 +++-- src/librustc/lint/context.rs | 8 +++++--- src/librustc/middle/dead.rs | 7 ++++--- src/librustc/middle/reachable.rs | 8 +++++--- src/librustc/middle/stability.rs | 5 +++-- src/librustc/ty/maps.rs | 10 ++++++++++ src/librustc/ty/mod.rs | 7 +++++-- src/librustc_driver/driver.rs | 20 ++++++++------------ src/librustc_privacy/lib.rs | 29 +++++++++++++++++++++++------ src/librustdoc/core.rs | 4 ++-- 10 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 399af258e9251..5ee9258852b0b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::CrateNum; use std::fmt::Debug; use std::sync::Arc; @@ -81,7 +82,7 @@ pub enum DepNode { TypeckItemType(D), UnusedTraitCheck, CheckConst(D), - Privacy, + PrivacyAccessLevels(CrateNum), IntrinsicCheck(D), MatchCheck(D), @@ -230,7 +231,7 @@ impl DepNode { CheckEntryFn => Some(CheckEntryFn), Variance => Some(Variance), UnusedTraitCheck => Some(UnusedTraitCheck), - Privacy => Some(Privacy), + PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), Reachability => Some(Reachability), DeadCheck => Some(DeadCheck), LateLintCheck => Some(LateLintCheck), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 843f3a53f33e5..d35f965e2ffd7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -44,9 +44,10 @@ use std::ops::Deref; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{DUMMY_SP, MultiSpan, Span}; use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; +use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -1231,10 +1232,11 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, /// Perform lint checking on a crate. /// /// Consumes the `lint_store` field of the `Session`. -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &AccessLevels) { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck); + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let krate = tcx.hir.krate(); // We want to own the lint store, so move it out of the session. diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index cc6d6e88dee4e..8926ff5c1fbbb 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -21,12 +21,13 @@ use hir::itemlikevisit::ItemLikeVisitor; use middle::privacy; use ty::{self, TyCtxt}; use hir::def::Def; -use hir::def_id::{DefId}; +use hir::def_id::{DefId, LOCAL_CRATE}; use lint; use util::nodemap::FxHashSet; use syntax::{ast, codemap}; use syntax::attr; +use syntax::codemap::DUMMY_SP; use syntax_pos; // Any local node that may call something in its body block should be @@ -592,9 +593,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels) { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::DeadCheck); + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 4ec43e368a60d..b0e39442af98c 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -27,7 +27,9 @@ use util::nodemap::{NodeSet, FxHashSet}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; +use syntax::codemap::DUMMY_SP; use hir; +use hir::def_id::LOCAL_CRATE; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; use hir::intravisit; @@ -359,11 +361,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels) - -> NodeSet { +pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { let _task = tcx.dep_graph.in_task(DepNode::Reachability); + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || *ty == config::CrateTypeProcMacro diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1fb5371402574..4115b4669f4b2 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -656,10 +656,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given the list of enabled features that were not language features (i.e. that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. -pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &AccessLevels) { +pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let sess = &tcx.sess; + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.hir.krate(); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ac8c38c7d5856..da4e58addd71b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -11,6 +11,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use middle::const_val::ConstVal; +use middle::privacy::AccessLevels; use mir; use ty::{self, Ty, TyCtxt}; @@ -189,6 +190,12 @@ impl<'tcx> QueryDescription for queries::mir_shims<'tcx> { } } +impl<'tcx> QueryDescription for queries::privacy_access_levels<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("privacy access levels") + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -406,6 +413,9 @@ define_maps! { <'tcx> /// other items, such as enum variant explicit discriminants. pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()>, + /// Performs the privacy check and computes "access levels". + pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0bcfae1e54a69..4283b10ec624f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -17,11 +17,11 @@ pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; -use middle; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; +use middle::privacy::AccessLevels; use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; @@ -108,9 +108,12 @@ mod sty; /// The complete set of all analyses described in this module. This is /// produced by the driver and fed to trans and later passes. +/// +/// NB: These contents are being migrated into queries using the +/// *on-demand* infrastructure. #[derive(Clone)] pub struct CrateAnalysis { - pub access_levels: middle::privacy::AccessLevels, + pub access_levels: Rc, pub reachable: NodeSet, pub name: String, pub glob_map: Option, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4947cafb52b3d..e8b9be4a903c3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -48,6 +48,7 @@ use std::fs; use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; +use std::rc::Rc; use syntax::{ast, diagnostics, visit}; use syntax::attr; use syntax::ext::base::ExtCtxt; @@ -807,7 +808,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, expanded_crate: krate, defs: resolver.definitions, analysis: ty::CrateAnalysis { - access_levels: AccessLevels::default(), + access_levels: Rc::new(AccessLevels::default()), reachable: NodeSet(), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, @@ -888,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut local_providers = ty::maps::Providers::default(); mir::provide(&mut local_providers); + rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); @@ -931,9 +933,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, || consts::check_crate(tcx)); analysis.access_levels = - time(time_passes, "privacy checking", || { - rustc_privacy::check_crate(tcx) - }); + time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx)); time(time_passes, "intrinsic checking", @@ -1000,19 +1000,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, analysis.reachable = time(time_passes, "reachability checking", - || reachable::find_reachable(tcx, &analysis.access_levels)); + || reachable::find_reachable(tcx)); - time(time_passes, "death checking", || { - middle::dead::check_crate(tcx, &analysis.access_levels); - }); + time(time_passes, "death checking", || middle::dead::check_crate(tcx)); time(time_passes, "unused lib feature checking", || { - stability::check_unused_or_stable_features(tcx, &analysis.access_levels) + stability::check_unused_or_stable_features(tcx) }); - time(time_passes, - "lint checking", - || lint::check_crate(tcx, &analysis.access_levels)); + time(time_passes, "lint checking", || lint::check_crate(tcx)); // The above three passes generate errors w/o aborting if sess.err_count() > 0 { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6b33c7b7816f0..64821f5d44bf4 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,6 +17,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] +#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -25,10 +26,9 @@ extern crate rustc; #[macro_use] extern crate syntax; extern crate syntax_pos; -use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; use rustc::hir::def::Def; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -36,12 +36,14 @@ use rustc::lint; use rustc::middle::privacy::{AccessLevel, AccessLevels}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::fold::TypeVisitor; +use rustc::ty::maps::Providers; use rustc::util::nodemap::NodeSet; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; use std::cmp; use std::mem::replace; +use std::rc::Rc; pub mod diagnostics; @@ -1203,8 +1205,23 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> fn visit_pat(&mut self, _: &'tcx hir::Pat) {} } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AccessLevels { - let _task = tcx.dep_graph.in_task(DepNode::Privacy); +pub fn provide(providers: &mut Providers) { + *providers = Providers { + privacy_access_levels, + ..*providers + }; +} + +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { + tcx.dep_graph.with_ignore(|| { // FIXME + ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE) + }) +} + +fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + krate: CrateNum) + -> Rc { + assert_eq!(krate, LOCAL_CRATE); let krate = tcx.hir.krate(); @@ -1266,7 +1283,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AccessLevels { krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); } - visitor.access_levels + Rc::new(visitor.access_levels) } __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 92aba1fc61de3..a47d5f9937a02 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -184,8 +184,8 @@ pub fn run_core(search_paths: SearchPaths, // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid let access_levels = AccessLevels { - map: access_levels.map.into_iter() - .map(|(k, v)| (tcx.hir.local_def_id(k), v)) + map: access_levels.map.iter() + .map(|(&k, &v)| (tcx.hir.local_def_id(k), v)) .collect() }; From b47035460f89fec11b9ab1348717e5ab61b16a67 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 16:22:29 -0700 Subject: [PATCH 244/662] Update cargo submodule I'm not really sure what we want the cadence here to be. We'll at the very least update the Cargo submodule right before all releases, but otherwise I figured we could just do it whenever needed or otherwise weekly (or something like that). In any case, I don't have a super strong particular reason to do this, it's just been a week or so since the release! --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index c995e9eb5acf3..4e95c6b41eca3 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c995e9eb5acf3976ae8674a0dc6d9e958053d9fd +Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 From 8a91e4d1238b40200724826cc7ef3f7893c6152b Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 24 Mar 2017 05:05:34 +0300 Subject: [PATCH 245/662] Document Cursor::new position is 0 ... even if contained `Vec` is not empty. E. g. for ``` let v = vec![10u8, 20]; let mut c = io::Cursor::new(v); c.write_all(b"aaaa").unwrap(); println!("{:?}", c.into_inner()); ``` result is ``` [97, 97, 97, 97] ``` and not ``` [10, 20, 97, 97, 97, 97] ``` --- src/libstd/io/cursor.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 60767ea478661..53347eb14db0d 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -89,6 +89,10 @@ pub struct Cursor { impl Cursor { /// Creates a new cursor wrapping the provided underlying I/O object. /// + /// Cursor initial position is `0` even if underlying object (e. + /// g. `Vec`) is not empty. So writing to cursor starts with + /// overwriting `Vec` content, not with appending to it. + /// /// # Examples /// /// ``` From 8fba638b08eb85cda1bd2a4e855f7f76727dfc52 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 18 Mar 2017 10:37:52 -0400 Subject: [PATCH 246/662] Rewrite `io::BufRead` doc examples to better demonstrate behaviors. Prior to this commit, most of the `BufRead` examples used `StdinLock` to demonstrate how certain `BufRead` methods worked. Using `StdinLock` is not ideal since: * Relying on run-time data means we can't show concrete examples of how these methods work up-front. The user is required to run them in order to see how they behave. * If the user tries to run an example in the playpen, it won't work because the playpen doesn't support user input to stdin. --- src/libstd/io/mod.rs | 137 ++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 53 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 850885a8c0f3a..5b628d51d1513 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1290,28 +1290,42 @@ pub trait BufRead: Read { /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read from standard input until we see an `a` byte. - /// /// [`fill_buf`]: #tymethod.fill_buf /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// # Examples /// - /// fn foo() -> io::Result<()> { - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = Vec::new(); + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the bytes in a byte slice + /// in hyphen delimited segments: /// - /// stdin.read_until(b'a', &mut buffer)?; + /// [`Cursor`]: struct.Cursor.html /// - /// println!("{:?}", buffer); - /// # Ok(()) - /// # } + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"lorem-ipsum"); + /// let mut buf = vec![]; + /// + /// // cursor is at 'l' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 6); + /// assert_eq!(buf, b"lorem-"); + /// buf.clear(); + /// + /// // cursor is at 'i' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 5); + /// assert_eq!(buf, b"ipsum"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, b""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { @@ -1337,28 +1351,36 @@ pub trait BufRead: Read { /// /// # Examples /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines`] method would be easier, of - /// course. + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the lines in a byte slice: /// - /// [`lines`]: #method.lines - /// [`read_until`]: #method.read_until + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = String::new(); - /// - /// while stdin.read_line(&mut buffer).unwrap() > 0 { - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.clear(); - /// } + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"foo\nbar"); + /// let mut buf = String::new(); + /// + /// // cursor is at 'f' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 4); + /// assert_eq!(buf, "foo\n"); + /// buf.clear(); + /// + /// // cursor is at 'b' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 3); + /// assert_eq!(buf, "bar"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, ""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_line(&mut self, buf: &mut String) -> Result { @@ -1378,24 +1400,28 @@ pub trait BufRead: Read { /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read some input from standard input, splitting on commas. - /// /// [`io::Result`]: type.Result.html /// [`Vec`]: ../vec/struct.Vec.html /// [`read_until`]: #method.read_until /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all hyphen delimited + /// segments in a byte slice + /// + /// [`Cursor`]: struct.Cursor.html + /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); + /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor"); /// - /// for content in stdin.lock().split(b',') { - /// println!("{:?}", content.unwrap()); - /// } + /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap()); + /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec())); + /// assert_eq!(split_iter.next(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn split(self, byte: u8) -> Split where Self: Sized { @@ -1413,17 +1439,22 @@ pub trait BufRead: Read { /// /// # Examples /// - /// A locked standard input implements `BufRead`: + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all the lines in a byte + /// slice. + /// + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); /// - /// for line in stdin.lock().lines() { - /// println!("{}", line.unwrap()); - /// } + /// let mut lines_iter = cursor.lines().map(|l| l.unwrap()); + /// assert_eq!(lines_iter.next(), Some(String::from("lorem"))); + /// assert_eq!(lines_iter.next(), Some(String::from("ipsum"))); + /// assert_eq!(lines_iter.next(), Some(String::from("dolor"))); + /// assert_eq!(lines_iter.next(), None); /// ``` /// /// # Errors From f97b3f08cde6dff89c8c236fce2479725d7f909e Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 24 Mar 2017 06:18:23 +0300 Subject: [PATCH 247/662] Unnecessary iteration in BTreeMap::drop `IntoIter::drop` already iterates. --- src/libcollections/btree/map.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index bed216ba3d111..dcacef4f0f0d5 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -141,8 +141,7 @@ pub struct BTreeMap { unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { fn drop(&mut self) { unsafe { - for _ in ptr::read(self).into_iter() { - } + drop(ptr::read(self).into_iter()); } } } From 9b0a4a4e97c4977aae45934d2138d8db27b16843 Mon Sep 17 00:00:00 2001 From: Petr Zemek Date: Fri, 24 Mar 2017 09:42:21 +0100 Subject: [PATCH 248/662] Fix formatting in the docs for std::process::Command::envs(). An empty line between the "Basic usage:" text and the example is required to properly format the code. Without the empty line, the example is not formatted as code. --- src/libstd/process.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7a85e58866236..b57a9883afe31 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -437,6 +437,7 @@ impl Command { /// # Examples /// /// Basic usage: + /// /// ```no_run /// use std::process::{Command, Stdio}; /// use std::env; From 432673a8ddbe5b62c8a15b7bc0141cf9a303866a Mon Sep 17 00:00:00 2001 From: Petr Zemek Date: Fri, 24 Mar 2017 15:47:45 +0100 Subject: [PATCH 249/662] Add a missing feature attribute to the example for std::process::Command::envs(). The person who originally wrote the example forgot to include this attribute. This caused Travis CI to fail on commit 9b0a4a4e97 (#40794), which just fixed formatting in the description of std::process::Command::envs(). --- src/libstd/process.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index b57a9883afe31..d46cf7a26daf0 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -439,6 +439,8 @@ impl Command { /// Basic usage: /// /// ```no_run + /// #![feature(command_envs)] + /// /// use std::process::{Command, Stdio}; /// use std::env; /// use std::collections::HashMap; From b0d9afbc04483a8c19f15e13e3a61ce11892536d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Mar 2017 16:09:01 +0100 Subject: [PATCH 250/662] Represent function pointers in mir-constants as a Value instead of Item --- src/librustc/mir/mod.rs | 14 ++++----- src/librustc_mir/build/scope.rs | 6 ++-- src/librustc_mir/hair/cx/expr.rs | 33 +++++++++++--------- src/librustc_mir/hair/cx/mod.rs | 5 ++- src/librustc_mir/shim.rs | 5 ++- src/librustc_mir/transform/qualify_consts.rs | 5 --- src/librustc_mir/transform/type_check.rs | 5 ++- src/librustc_mir/util/elaborate_drops.rs | 6 ++-- src/librustc_trans/mir/analyze.rs | 7 +++-- src/librustc_trans/mir/constant.rs | 15 +++++---- 10 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9fdb866577699..01dc7f51e29d9 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -983,16 +983,16 @@ impl<'tcx> Debug for Operand<'tcx> { } impl<'tcx> Operand<'tcx> { - pub fn item<'a>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - span: Span) - -> Self - { + pub fn function_handle<'a>( + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + span: Span, + ) -> Self { Operand::Constant(Constant { span: span, ty: tcx.item_type(def_id).subst(tcx, substs), - literal: Literal::Item { def_id, substs } + literal: Literal::Value { value: ConstVal::Function(def_id, substs) }, }) } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 1de5b9218564f..dd4190a412dac 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -89,6 +89,7 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder, CFG}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; +use rustc::middle::const_val::ConstVal; use rustc::ty::subst::{Kind, Subst}; use rustc::ty::{Ty, TyCtxt}; use rustc::mir::*; @@ -784,9 +785,8 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, func: Operand::Constant(Constant { span: data.span, ty: tcx.item_type(free_func).subst(tcx, substs), - literal: Literal::Item { - def_id: free_func, - substs: substs + literal: Literal::Value { + value: ConstVal::Function(free_func, substs), } }), args: vec![Operand::Consume(data.value.clone())], diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index da58a1ed1f49b..44858a98e36f9 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -714,9 +714,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty: callee.ty, span: expr.span, kind: ExprKind::Literal { - literal: Literal::Item { - def_id: callee.def_id, - substs: callee.substs, + literal: Literal::Value { + value: ConstVal::Function(callee.def_id, callee.substs), }, }, } @@ -743,14 +742,24 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, -> ExprKind<'tcx> { let substs = cx.tables().node_id_item_substs(expr.id) .unwrap_or_else(|| cx.tcx.intern_substs(&[])); - let def_id = match def { + match def { // A regular function, constructor function or a constant. Def::Fn(def_id) | Def::Method(def_id) | Def::StructCtor(def_id, CtorKind::Fn) | - Def::VariantCtor(def_id, CtorKind::Fn) | + Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { + literal: Literal::Value { + value: ConstVal::Function(def_id, substs), + }, + }, + Def::Const(def_id) | - Def::AssociatedConst(def_id) => def_id, + Def::AssociatedConst(def_id) => ExprKind::Literal { + literal: Literal::Item { + def_id: def_id, + substs: substs, + }, + }, Def::StructCtor(def_id, CtorKind::Const) | Def::VariantCtor(def_id, CtorKind::Const) => { @@ -758,7 +767,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. ty::TyAdt(adt_def, substs) => { - return ExprKind::Adt { + ExprKind::Adt { adt_def: adt_def, variant_index: adt_def.variant_index_with_id(def_id), substs: substs, @@ -770,17 +779,11 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - Def::Static(node_id, _) => return ExprKind::StaticRef { id: node_id }, + Def::Static(node_id, _) => ExprKind::StaticRef { id: node_id }, - Def::Local(..) | Def::Upvar(..) => return convert_var(cx, expr, def), + Def::Local(..) | Def::Upvar(..) => convert_var(cx, expr, def), _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def), - }; - ExprKind::Literal { - literal: Literal::Item { - def_id: def_id, - substs: substs, - }, } } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index c555ce1ab9c42..3eef5d83b8ba0 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -132,9 +132,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let method_ty = self.tcx.item_type(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, - Literal::Item { - def_id: item.def_id, - substs: substs, + Literal::Value { + value: ConstVal::Function(item.def_id, substs), }); } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 26d5b7fd38ab0..63d20be88feee 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -12,6 +12,7 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer; use rustc::middle::region::ROOT_CODE_EXTENT; +use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::ty::{self, Ty}; @@ -335,7 +336,9 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, Operand::Constant(Constant { span: span, ty: tcx.item_type(def_id).subst(tcx, param_env.free_substs), - literal: Literal::Item { def_id, substs: param_env.free_substs }, + literal: Literal::Value { + value: ConstVal::Function(def_id, param_env.free_substs), + }, }), vec![rcvr] ) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index e998665e03536..ba42804c9262f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -568,11 +568,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { }); } Operand::Constant(ref constant) => { - // Only functions and methods can have these types. - if let ty::TyFnDef(..) = constant.ty.sty { - return; - } - if let Literal::Item { def_id, substs } = constant.literal { // Don't peek inside generic (associated) constants. if substs.types().next().is_some() { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f98bb73c504dc..3d604affbfea9 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -15,6 +15,7 @@ use rustc::infer::{self, InferCtxt, InferOk}; use rustc::traits::{self, Reveal}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, Ty, TyCtxt, TypeVariants}; +use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::mir::tcx::LvalueTy; use rustc::mir::transform::{MirPass, MirSource, Pass}; @@ -526,7 +527,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { match operand { &Operand::Constant(Constant { - literal: Literal::Item { def_id, .. }, .. + literal: Literal::Value { + value: ConstVal::Function(def_id, _), .. + }, .. }) => { Some(def_id) == self.tcx().lang_items.box_free_fn() } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index d0f142ad7d7a8..ccbc6700d89c1 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -525,8 +525,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }], terminator: Some(Terminator { kind: TerminatorKind::Call { - func: Operand::item(tcx, drop_fn.def_id, substs, - self.source_info.span), + func: Operand::function_handle(tcx, drop_fn.def_id, substs, + self.source_info.span), args: vec![Operand::Consume(Lvalue::Local(ref_lvalue))], destination: Some((unit_temp, succ)), cleanup: unwind, @@ -629,7 +629,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let substs = tcx.mk_substs(iter::once(Kind::from(ty))); let call = TerminatorKind::Call { - func: Operand::item(tcx, free_func, substs, self.source_info.span), + func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), args: vec![Operand::Consume(self.lvalue.clone())], destination: Some((unit_temp, target)), cleanup: None diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2c3b479c7dd0f..a3968650043ba 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -13,7 +13,8 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc::mir::{self, Location, TerminatorKind}; +use rustc::middle::const_val::ConstVal; +use rustc::mir::{self, Location, TerminatorKind, Literal}; use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; @@ -109,7 +110,9 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(mir::Constant { - literal: mir::Literal::Item { def_id, .. }, .. + literal: Literal::Value { + value: ConstVal::Function(def_id, _), .. + }, .. }), ref args, .. } if Some(def_id) == self.cx.ccx.tcx().lang_items.box_free_fn() => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 107b0982af982..5d7f71848f828 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -101,9 +101,12 @@ impl<'tcx> Const<'tcx> { ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), ConstVal::Struct(_) | ConstVal::Tuple(_) | - ConstVal::Array(..) | ConstVal::Repeat(..) | + ConstVal::Array(..) | ConstVal::Repeat(..) => { + bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) + } ConstVal::Function(..) => { - bug!("MIR must not use `{:?}` (which refers to a local ID)", cv) + let llty = type_of::type_of(ccx, ty); + return Const::new(C_null(llty), ty); } ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), }; @@ -476,8 +479,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let ty = self.monomorphize(&constant.ty); match constant.literal.clone() { mir::Literal::Item { def_id, substs } => { - // Shortcut for zero-sized types, including function item - // types, which would not work with MirConstContext. + // Shortcut for zero-sized types + // which would not work with MirConstContext. if common::type_is_zero_size(self.ccx, ty) { let llty = type_of::type_of(self.ccx, ty); return Ok(Const::new(C_null(llty), ty)); @@ -924,8 +927,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let ty = self.monomorphize(&constant.ty); let result = match constant.literal.clone() { mir::Literal::Item { def_id, substs } => { - // Shortcut for zero-sized types, including function item - // types, which would not work with MirConstContext. + // Shortcut for zero-sized types + // which would not work with MirConstContext. if common::type_is_zero_size(bcx.ccx, ty) { let llty = type_of::type_of(bcx.ccx, ty); return Const::new(C_null(llty), ty); From 9c918464e186c7b19550004a771104589c0952d2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 17 Mar 2017 17:47:09 +0100 Subject: [PATCH 251/662] Remove zst hacks --- src/librustc_trans/mir/constant.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 5d7f71848f828..dbd928194c032 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -479,13 +479,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let ty = self.monomorphize(&constant.ty); match constant.literal.clone() { mir::Literal::Item { def_id, substs } => { - // Shortcut for zero-sized types - // which would not work with MirConstContext. - if common::type_is_zero_size(self.ccx, ty) { - let llty = type_of::type_of(self.ccx, ty); - return Ok(Const::new(C_null(llty), ty)); - } - let substs = self.monomorphize(&substs); MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new()) } @@ -927,13 +920,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let ty = self.monomorphize(&constant.ty); let result = match constant.literal.clone() { mir::Literal::Item { def_id, substs } => { - // Shortcut for zero-sized types - // which would not work with MirConstContext. - if common::type_is_zero_size(bcx.ccx, ty) { - let llty = type_of::type_of(bcx.ccx, ty); - return Const::new(C_null(llty), ty); - } - let substs = self.monomorphize(&substs); MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new()) } From 03949f5b5caa330375bb33d7b91b5fc24bd8c92e Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Fri, 24 Mar 2017 17:47:23 +0100 Subject: [PATCH 252/662] issue #40793 Correcting the two mistakes in the README.md --- src/librustc_borrowck/borrowck/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 5cfbd59d33368..29b007a7499c3 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -347,7 +347,7 @@ ALIASABLE(*LV, MQ) // M-Deref-Unique ALIASABLE(LV, MQ) ``` -### Checking mutability of immutable pointer types +### Checking aliasability of immutable pointer types Immutable pointer types like `&T` are aliasable, and hence can only be borrowed immutably: @@ -357,7 +357,7 @@ ALIASABLE(*LV, imm) // M-Deref-Borrowed-Imm TYPE(LV) = &Ty ``` -### Checking mutability of mutable pointer types +### Checking aliasability of mutable pointer types `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: From e6e8c919613615d2e296e5a4adbe81c57c0dbce9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 15:46:40 -0700 Subject: [PATCH 253/662] appveyor: Upgrade MinGW toolchains we use In debugging #40546 I was able to reproduce locally finally using the literal toolchain that the bots were using. I reproduced the error maybe 4 in 10 builds. I also have the 6.3.0 toolchain installed through `pacman` which has yet to have a failed build. When attempting to reproduce the bug with the toolchain that this commit switches to I was unable to reproduce anything after a few builds. I have no idea what the original problem was, but I'm hoping that it was just some random bug fixed somewhere along the way. I don't currently know of a technical reason to stick to the 4.9.2 toolchains we were previously using. Historcal 5.3.* toolchains would cause llvm to segfault (maybe a miscompile?) but this seems to have been fixed recently. To me if it passes CI then I think we're good. Closes #40546 --- appveyor.yml | 16 ++++++++-------- src/test/run-pass/issue-16671.rs | 27 +++++++-------------------- src/tools/compiletest/src/procsrv.rs | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0e7ebf12a2a91..146b0ba1b3d02 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,14 +45,14 @@ environment: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -70,15 +70,15 @@ environment: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 DEPLOY: 1 diff --git a/src/test/run-pass/issue-16671.rs b/src/test/run-pass/issue-16671.rs index 2be04551cb92f..71a19d9819054 100644 --- a/src/test/run-pass/issue-16671.rs +++ b/src/test/run-pass/issue-16671.rs @@ -8,26 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// DON'T REENABLE THIS UNLESS YOU'VE ACTUALLY FIXED THE UNDERLYING ISSUE -// ignore-android seems to block forever +#![deny(warnings)] -// ignore-emscripten no threads support +fn foo(_f: F) { } -#![forbid(warnings)] - -// Pretty printing tests complain about `use std::predule::*` -#![allow(unused_imports)] - -// A var moved into a proc, that has a mutable loan path should -// not trigger a misleading unused_mut warning. - -use std::io::prelude::*; -use std::thread; - -pub fn main() { - let mut stdin = std::io::stdin(); - thread::spawn(move|| { - let mut v = Vec::new(); - let _ = stdin.read_to_end(&mut v); - }).join().ok().unwrap(); +fn main() { + let mut var = Vec::new();; + foo(move|| { + var.push(1); + }); } diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index 7e4f40af9cea6..f55667f93c031 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -57,9 +57,26 @@ pub fn run(lib_path: &str, let mut cmd = Command::new(prog); cmd.args(args) - .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()); + + // Why oh why do we sometimes make a pipe and sometimes inherit the stdin + // stream, well that's an excellent question! In theory it should suffice to + // always create a pipe here and be done with it. Unfortunately though + // there's apparently something odd with the gdb that comes with gcc 6.3.0 + // on MinGW. Tracked at rust-lang/rust#40184 when stdin is piped here + // (unconditionally) then all gdb tests will fail on MinGW when using gcc + // 6.3.0. WHen using an inherited stdin though they happen to all work! + // + // As to why this fixes the issue, well, I have no idea. If you can remove + // this branch and unconditionally use `piped` and it gets past @bors please + // feel free to send a PR! + if input.is_some() || !cfg!(windows) { + cmd.stdin(Stdio::piped()); + } else { + cmd.stdin(Stdio::inherit()); + } + add_target_env(&mut cmd, lib_path, aux_path); for (key, val) in env { cmd.env(&key, &val); From 3b0add459c49efab85dd617d236aa5b0d9687aa2 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Fri, 24 Mar 2017 21:16:00 +0100 Subject: [PATCH 254/662] Update CONTRIBUTING.md Changed link to documentation issues from A-docs to T-doc as this has just been migrated. Added a link to the documentation style guidelines. --- CONTRIBUTING.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f921fb2c94233..651fffb585add 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -311,9 +311,11 @@ To save @bors some work, and to get small changes through more quickly, when the other rollup-eligible patches too, and they'll get tested and merged at the same time. -To find documentation-related issues, sort by the [A-docs label][adocs]. +To find documentation-related issues, sort by the [T-doc label][tdoc]. +You can find documentation style guidelines in [RFC 1574][rfc1574]. -[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs +[tdoc]: https://github.com/rust-lang/rust/issues?q=is%3Aopen%20is%3Aissue%20label%3AT-doc +[rfc1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text In many cases, you don't need a full `./x.py doc`. You can use `rustdoc` directly to check small fixes. For example, `rustdoc src/doc/reference.md` will render From 7643ccd29ca708059cef446d2ef4446559bb4518 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Fri, 24 Mar 2017 21:28:59 +0100 Subject: [PATCH 255/662] Split paragraph in CONTRIBUTING.md --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 651fffb585add..0314a5dfd8d02 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -312,9 +312,11 @@ the other rollup-eligible patches too, and they'll get tested and merged at the same time. To find documentation-related issues, sort by the [T-doc label][tdoc]. -You can find documentation style guidelines in [RFC 1574][rfc1574]. [tdoc]: https://github.com/rust-lang/rust/issues?q=is%3Aopen%20is%3Aissue%20label%3AT-doc + +You can find documentation style guidelines in [RFC 1574][rfc1574]. + [rfc1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text In many cases, you don't need a full `./x.py doc`. You can use `rustdoc` directly From 64e9af47f4e517208fc1dd950340a0c046ad87b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 11 Mar 2017 10:58:19 +0000 Subject: [PATCH 256/662] Allow declarative macros 2.0 and `use` macro imports to shadow builtin macros. --- src/librustc_resolve/lib.rs | 36 ++++--- src/librustc_resolve/macros.rs | 102 +++++++++++------- src/librustc_resolve/resolve_imports.rs | 12 ++- .../imports/shadow_builtin_macros.rs | 72 +++++++++++++ 4 files changed, 163 insertions(+), 59 deletions(-) create mode 100644 src/test/compile-fail/imports/shadow_builtin_macros.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f832e0f9a4811..be8513c94d03d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -75,7 +75,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; -use macros::{InvocationData, LegacyBinding, LegacyScope}; +use macros::{InvocationData, LegacyBinding, LegacyScope, MacroBinding}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -2566,6 +2566,7 @@ impl<'a> Resolver<'a> { self.resolve_ident_in_module(module, ident, ns, false, record_used) } else if opt_ns == Some(MacroNS) { self.resolve_lexical_macro_path_segment(ident, ns, record_used) + .map(MacroBinding::binding) } else { match self.resolve_ident_in_lexical_scope(ident, ns, record_used) { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), @@ -3223,7 +3224,7 @@ impl<'a> Resolver<'a> { }; let msg1 = format!("`{}` could refer to the name {} here", name, participle(b1)); let msg2 = format!("`{}` could also refer to the name {} here", name, participle(b2)); - let note = if !lexical && b1.is_glob_import() { + let note = if b1.expansion == Mark::root() || !lexical && b1.is_glob_import() { format!("consider adding an explicit import of `{}` to disambiguate", name) } else if let Def::Macro(..) = b1.def() { format!("macro-expanded {} do not shadow", @@ -3243,11 +3244,15 @@ impl<'a> Resolver<'a> { let msg = format!("`{}` is ambiguous", name); self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg); } else { - self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) - .span_note(b1.span, &msg1) - .span_note(b2.span, &msg2) - .note(¬e) - .emit(); + let mut err = + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)); + err.span_note(b1.span, &msg1); + match b2.def() { + Def::Macro(..) if b2.span == DUMMY_SP => + err.note(&format!("`{}` is also a builtin macro", name)), + _ => err.span_note(b2.span, &msg2), + }; + err.note(¬e).emit(); } } @@ -3361,14 +3366,13 @@ impl<'a> Resolver<'a> { if self.proc_macro_enabled { return; } for attr in attrs { - let name = unwrap_or!(attr.name(), continue); - let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| { - let ident = Ident::with_empty_ctxt(name); - self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok() - }); - - if let Some(binding) = maybe_binding { - if let SyntaxExtension::AttrProcMacro(..) = *binding.get_macro(self) { + if attr.path.segments.len() > 1 { + continue + } + let ident = attr.path.segments[0].identifier; + let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None); + if let Ok(binding) = result { + if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) { attr::mark_known(attr); let msg = "attribute procedural macros are experimental"; @@ -3376,7 +3380,7 @@ impl<'a> Resolver<'a> { feature_err(&self.session.parse_sess, feature, attr.span, GateIssue::Language, msg) - .span_note(binding.span, "procedural macro imported here") + .span_note(binding.span(), "procedural macro imported here") .emit(); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 99fc1c142f681..9af921a84459e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -81,11 +81,29 @@ pub struct LegacyBinding<'a> { pub span: Span, } +#[derive(Copy, Clone)] pub enum MacroBinding<'a> { Legacy(&'a LegacyBinding<'a>), + Builtin(&'a NameBinding<'a>), Modern(&'a NameBinding<'a>), } +impl<'a> MacroBinding<'a> { + pub fn span(self) -> Span { + match self { + MacroBinding::Legacy(binding) => binding.span, + MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding.span, + } + } + + pub fn binding(self) -> &'a NameBinding<'a> { + match self { + MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding, + MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"), + } + } +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -378,18 +396,18 @@ impl<'a> Resolver<'a> { } let name = path[0].name; - let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)), - Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()), - None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { - Ok(binding) => Ok(binding.def_ignoring_ambiguity()), - Err(Determinacy::Undetermined) if !force => - return Err(Determinacy::Undetermined), + let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, name, false); + let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { + Ok(Def::Macro(binding.def_id, MacroKind::Bang)) + } else { + match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { + Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), + Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { self.found_unresolved_macro = true; Err(Determinacy::Determined) } - }, + } }; self.current_module.legacy_macro_resolutions.borrow_mut() @@ -403,42 +421,56 @@ impl<'a> Resolver<'a> { ident: Ident, ns: Namespace, record_used: Option) - -> Result<&'a NameBinding<'a>, Determinacy> { - let mut module = self.current_module; - let mut potential_expanded_shadower: Option<&NameBinding> = None; + -> Result, Determinacy> { + let mut module = Some(self.current_module); + let mut potential_illegal_shadower = Err(Determinacy::Determined); + let determinacy = + if record_used.is_some() { Determinacy::Determined } else { Determinacy::Undetermined }; loop { - // Since expanded macros may not shadow the lexical scope (enforced below), - // we can ignore unresolved invocations (indicated by the penultimate argument). - match self.resolve_ident_in_module(module, ident, ns, true, record_used) { + let result = if let Some(module) = module { + // Since expanded macros may not shadow the lexical scope and + // globs may not shadow builtin macros (both enforced below), + // we resolve with restricted shadowing (indicated by the penultimate argument). + self.resolve_ident_in_module(module, ident, ns, true, record_used) + .map(MacroBinding::Modern) + } else { + self.builtin_macros.get(&ident.name).cloned().ok_or(determinacy) + .map(MacroBinding::Builtin) + }; + + match result.map(MacroBinding::binding) { Ok(binding) => { let span = match record_used { Some(span) => span, - None => return Ok(binding), + None => return result, }; - match potential_expanded_shadower { - Some(shadower) if shadower.def() != binding.def() => { + if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower { + if shadower.def() != binding.def() { let name = ident.name; self.ambiguity_errors.push(AmbiguityError { span: span, name: name, b1: shadower, b2: binding, lexical: true, legacy: false, }); - return Ok(shadower); + return potential_illegal_shadower; } - _ if binding.expansion == Mark::root() => return Ok(binding), - _ => potential_expanded_shadower = Some(binding), + } + if binding.expansion != Mark::root() || + (binding.is_glob_import() && module.unwrap().def().is_some()) { + potential_illegal_shadower = result; + } else { + return result; } }, Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), Err(Determinacy::Determined) => {} } - match module.kind { - ModuleKind::Block(..) => module = module.parent.unwrap(), - ModuleKind::Def(..) => return match potential_expanded_shadower { - Some(binding) => Ok(binding), - None if record_used.is_some() => Err(Determinacy::Determined), - None => Err(Determinacy::Undetermined), + module = match module { + Some(module) => match module.kind { + ModuleKind::Block(..) => module.parent, + ModuleKind::Def(..) => None, }, + None => return potential_illegal_shadower, } } } @@ -492,7 +524,7 @@ impl<'a> Resolver<'a> { if !self.use_extern_macros { self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP); } - MacroBinding::Modern(binding) + MacroBinding::Builtin(binding) } else { return None; }; @@ -524,21 +556,15 @@ impl<'a> Resolver<'a> { let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true); let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span)); match (legacy_resolution, resolution) { - (Some(legacy_resolution), Ok(resolution)) => { - let (legacy_span, participle) = match legacy_resolution { - MacroBinding::Modern(binding) - if binding.def() == resolution.def() => continue, - MacroBinding::Modern(binding) => (binding.span, "imported"), - MacroBinding::Legacy(binding) => (binding.span, "defined"), - }; - let msg1 = format!("`{}` could refer to the macro {} here", ident, participle); + (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => { + let msg1 = format!("`{}` could refer to the macro defined here", ident); let msg2 = format!("`{}` could also refer to the macro imported here", ident); self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident)) - .span_note(legacy_span, &msg1) - .span_note(resolution.span, &msg2) + .span_note(legacy_binding.span, &msg1) + .span_note(binding.span, &msg2) .emit(); }, - (Some(MacroBinding::Modern(binding)), Err(_)) => { + (Some(MacroBinding::Builtin(binding)), Ok(MacroBinding::Builtin(_))) => { self.record_use(ident, MacroNS, binding, span); self.err_if_macro_use_proc_macro(ident.name, span, binding); }, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2f4ac12cd7363..43654c8ce6f68 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -145,7 +145,7 @@ impl<'a> Resolver<'a> { module: Module<'a>, ident: Ident, ns: Namespace, - ignore_unresolved_invocations: bool, + restricted_shadowing: bool, record_used: Option) -> Result<&'a NameBinding<'a>, Determinacy> { self.populate_module_if_necessary(module); @@ -158,9 +158,8 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.binding { if let Some(shadowed_glob) = resolution.shadows_glob { let name = ident.name; - // If we ignore unresolved invocations, we must forbid - // expanded shadowing to avoid time travel. - if ignore_unresolved_invocations && + // Forbid expanded shadowing to avoid time travel. + if restricted_shadowing && binding.expansion != Mark::root() && ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing binding.def() != shadowed_glob.def() { @@ -215,7 +214,7 @@ impl<'a> Resolver<'a> { } let no_unresolved_invocations = - ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty(); + restricted_shadowing || module.unresolved_invocations.borrow().is_empty(); match resolution.binding { // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`). Some(binding) if no_unresolved_invocations || ns == MacroNS => @@ -225,6 +224,9 @@ impl<'a> Resolver<'a> { } // Check if the globs are determined + if restricted_shadowing && module.def().is_some() { + return Err(Determined); + } for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { if let Some(module) = directive.imported_module.get() { diff --git a/src/test/compile-fail/imports/shadow_builtin_macros.rs b/src/test/compile-fail/imports/shadow_builtin_macros.rs new file mode 100644 index 0000000000000..2b3ba1b4aa7a7 --- /dev/null +++ b/src/test/compile-fail/imports/shadow_builtin_macros.rs @@ -0,0 +1,72 @@ +// Copyright 2017 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:two_macros.rs + +#![feature(use_extern_macros)] + +mod foo { + extern crate two_macros; + pub use self::two_macros::m as panic; +} + +mod m1 { + use foo::panic; // ok + fn f() { panic!(); } +} + +mod m2 { + use foo::*; //~ NOTE `panic` could refer to the name imported here + fn f() { panic!(); } //~ ERROR ambiguous + //~| NOTE `panic` is also a builtin macro + //~| NOTE consider adding an explicit import of `panic` to disambiguate +} + +mod m3 { + ::two_macros::m!(use foo::panic;); //~ NOTE `panic` could refer to the name imported here + //~| NOTE in this expansion + fn f() { panic!(); } //~ ERROR ambiguous + //~| NOTE `panic` is also a builtin macro + //~| NOTE macro-expanded macro imports do not shadow +} + +mod m4 { + macro_rules! panic { () => {} } // ok + panic!(); +} + +mod m5 { + macro_rules! m { () => { + macro_rules! panic { () => {} } //~ ERROR `panic` is already in scope + //~| NOTE macro-expanded `macro_rules!`s may not shadow existing macros + } } + m!(); //~ NOTE in this expansion + //~| NOTE in this expansion + panic!(); +} + +#[macro_use(n)] //~ NOTE `n` could also refer to the name imported here +extern crate two_macros; +mod bar { + pub use two_macros::m as n; +} + +mod m6 { + use bar::n; // ok + n!(); +} + +mod m7 { + use bar::*; //~ NOTE `n` could refer to the name imported here + n!(); //~ ERROR ambiguous + //~| NOTE consider adding an explicit import of `n` to disambiguate +} + +fn main() {} From d64d3814c4a23fcb8440959bec77090fbbb25d7d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 01:39:47 +0000 Subject: [PATCH 257/662] Rename `builtin` => `global`. --- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 8 +++--- src/librustc_resolve/macros.rs | 30 ++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c33d5b9b6e16b..86e0d0039d1a7 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -539,7 +539,7 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { - if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing { + if self.global_macros.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index be8513c94d03d..879d8816488b2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1174,7 +1174,7 @@ pub struct Resolver<'a> { crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, - builtin_macros: FxHashMap>, + global_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, macro_defs: FxHashMap, @@ -1372,7 +1372,7 @@ impl<'a> Resolver<'a> { crate_loader: crate_loader, macro_names: FxHashSet(), - builtin_macros: FxHashMap(), + global_macros: FxHashMap(), lexical_macro_resolutions: Vec::new(), macro_map: FxHashMap(), macro_exports: Vec::new(), @@ -2429,9 +2429,9 @@ impl<'a> Resolver<'a> { }; } } - let is_builtin = self.builtin_macros.get(&path[0].name).cloned() + let is_global = self.global_macros.get(&path[0].name).cloned() .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false); - if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) { + if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].name)) { // Return some dummy definition, it's enough for error reporting. return Some( PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 9af921a84459e..3d6c6896549a4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -84,7 +84,7 @@ pub struct LegacyBinding<'a> { #[derive(Copy, Clone)] pub enum MacroBinding<'a> { Legacy(&'a LegacyBinding<'a>), - Builtin(&'a NameBinding<'a>), + Global(&'a NameBinding<'a>), Modern(&'a NameBinding<'a>), } @@ -92,13 +92,13 @@ impl<'a> MacroBinding<'a> { pub fn span(self) -> Span { match self { MacroBinding::Legacy(binding) => binding.span, - MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding.span, + MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding.span, } } pub fn binding(self) -> &'a NameBinding<'a> { match self { - MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding, + MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding, MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"), } } @@ -189,7 +189,7 @@ impl<'a> base::Resolver for Resolver<'a> { vis: ty::Visibility::Invisible, expansion: Mark::root(), }); - self.builtin_macros.insert(ident.name, binding); + self.global_macros.insert(ident.name, binding); } fn resolve_imports(&mut self) { @@ -207,7 +207,7 @@ impl<'a> base::Resolver for Resolver<'a> { attr::mark_known(&attrs[i]); } - match self.builtin_macros.get(&name).cloned() { + match self.global_macros.get(&name).cloned() { Some(binding) => match *binding.get_macro(self) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -239,7 +239,7 @@ impl<'a> base::Resolver for Resolver<'a> { } let trait_name = traits[j].segments[0].identifier.name; let legacy_name = Symbol::intern(&format!("derive_{}", trait_name)); - if !self.builtin_macros.contains_key(&legacy_name) { + if !self.global_macros.contains_key(&legacy_name) { continue } let span = traits.remove(j).span; @@ -429,13 +429,13 @@ impl<'a> Resolver<'a> { loop { let result = if let Some(module) = module { // Since expanded macros may not shadow the lexical scope and - // globs may not shadow builtin macros (both enforced below), + // globs may not shadow global macros (both enforced below), // we resolve with restricted shadowing (indicated by the penultimate argument). self.resolve_ident_in_module(module, ident, ns, true, record_used) .map(MacroBinding::Modern) } else { - self.builtin_macros.get(&ident.name).cloned().ok_or(determinacy) - .map(MacroBinding::Builtin) + self.global_macros.get(&ident.name).cloned().ok_or(determinacy) + .map(MacroBinding::Global) }; match result.map(MacroBinding::binding) { @@ -520,11 +520,11 @@ impl<'a> Resolver<'a> { let binding = if let Some(binding) = binding { MacroBinding::Legacy(binding) - } else if let Some(binding) = self.builtin_macros.get(&name).cloned() { + } else if let Some(binding) = self.global_macros.get(&name).cloned() { if !self.use_extern_macros { self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP); } - MacroBinding::Builtin(binding) + MacroBinding::Global(binding) } else { return None; }; @@ -564,7 +564,7 @@ impl<'a> Resolver<'a> { .span_note(binding.span, &msg2) .emit(); }, - (Some(MacroBinding::Builtin(binding)), Ok(MacroBinding::Builtin(_))) => { + (Some(MacroBinding::Global(binding)), Ok(MacroBinding::Global(_))) => { self.record_use(ident, MacroNS, binding, span); self.err_if_macro_use_proc_macro(ident.name, span, binding); }, @@ -593,11 +593,11 @@ impl<'a> Resolver<'a> { find_best_match_for_name(self.macro_names.iter(), name, None) } else { None - // Then check builtin macros. + // Then check global macros. }.or_else(|| { // FIXME: get_macro needs an &mut Resolver, can we do it without cloning? - let builtin_macros = self.builtin_macros.clone(); - let names = builtin_macros.iter().filter_map(|(name, binding)| { + let global_macros = self.global_macros.clone(); + let names = global_macros.iter().filter_map(|(name, binding)| { if binding.get_macro(self).kind() == kind { Some(name) } else { From 2c816f7fb6772fe0b77af04da9355aab6c2d3fb2 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 25 Mar 2017 00:27:47 +0100 Subject: [PATCH 258/662] Optimize insertion sort This change slightly changes the main iteration loop so that LLVM can optimize it more efficiently. Benchmark: name before ns/iter after ns/iter diff ns/iter diff % slice::sort_unstable_small_ascending 39 (2051 MB/s) 38 (2105 MB/s) -1 -2.56% slice::sort_unstable_small_big_random 579 (2210 MB/s) 575 (2226 MB/s) -4 -0.69% slice::sort_unstable_small_descending 80 (1000 MB/s) 70 (1142 MB/s) -10 -12.50% slice::sort_unstable_small_random 396 (202 MB/s) 386 -10 -2.53% --- src/libcore/slice/sort.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index d13d537d99301..307e4974d9769 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -152,8 +152,8 @@ fn partial_insertion_sort(v: &mut [T], is_less: &mut F) -> bool fn insertion_sort(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool { - for i in 2..v.len()+1 { - shift_tail(&mut v[..i], is_less); + for i in 1..v.len() { + shift_tail(&mut v[..i+1], is_less); } } From e7949d0013bb8b45c884b173ca22c20e6899d612 Mon Sep 17 00:00:00 2001 From: Adam Ransom Date: Tue, 21 Mar 2017 21:38:32 +0900 Subject: [PATCH 259/662] Warn when using a `'static` lifetime bound Previously a `'static` lifetime bound would result in an `undeclared lifetime` error when compiling, even though it could be considered valid. However, it is unnecessary to use it as a lifetime bound so we present the user with a warning instead and suggest using the `'static` lifetime directly, in place of the lifetime parameter. --- src/librustc/middle/resolve_lifetime.rs | 14 ++++++++++++-- src/test/compile-fail/static-lifetime-bound.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/static-lifetime-bound.rs diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 10ee760a6a615..5094e28475b26 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -29,7 +29,7 @@ use syntax::ast; use syntax::attr; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax_pos::Span; +use syntax_pos::{mk_sp, Span}; use errors::DiagnosticBuilder; use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap}; use rustc_back::slice; @@ -1464,7 +1464,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); for bound in &lifetime_i.bounds { - self.resolve_lifetime_ref(bound); + if !bound.is_static() { + self.resolve_lifetime_ref(bound); + } else { + self.insert_lifetime(bound, Region::Static); + let full_span = mk_sp(lifetime_i.lifetime.span.lo, bound.span.hi); + self.sess.struct_span_warn(full_span, + &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) + .help(&format!("you can use the `'static` lifetime directly, in place \ + of `{}`", lifetime_i.lifetime.name)) + .emit(); + } } } } diff --git a/src/test/compile-fail/static-lifetime-bound.rs b/src/test/compile-fail/static-lifetime-bound.rs new file mode 100644 index 0000000000000..38534ab0a3687 --- /dev/null +++ b/src/test/compile-fail/static-lifetime-bound.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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 f<'a: 'static>(_: &'a i32) {} //~WARN unnecessary lifetime parameter `'a` + +fn main() { + let x = 0; + f(&x); //~ERROR does not live long enough +} From bff332e0a22ce71f329202fc635693079e791bb5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Mar 2017 19:00:35 -0700 Subject: [PATCH 260/662] travis: Update sccache again Looks like the last version was built with mio 0.6.5 which now has known bugs against it. This build includes mio 0.6.6 --- .travis.yml | 2 +- appveyor.yml | 4 ++-- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/cross/Dockerfile | 2 +- src/ci/docker/dist-android/Dockerfile | 2 +- src/ci/docker/dist-arm-linux/Dockerfile | 2 +- src/ci/docker/dist-armv7-aarch64-linux/Dockerfile | 2 +- src/ci/docker/dist-freebsd/Dockerfile | 2 +- src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 2 +- src/ci/docker/dist-mips-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- src/ci/docker/dist-s390x-linux-netbsd/Dockerfile | 2 +- src/ci/docker/dist-x86-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-musl/Dockerfile | 2 +- src/ci/docker/emscripten/Dockerfile | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 2 +- src/ci/docker/i686-gnu/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-debug/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-distcheck/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-incremental/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-nopt/Dockerfile | 2 +- src/ci/docker/x86_64-gnu/Dockerfile | 2 +- 28 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1faf860a3004f..148b59e8c64eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp diff --git a/appveyor.yml b/appveyor.yml index c33e07fb17e5f..0f4d053b6cfeb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-pc-windows-msvc - - mv 2017-03-22-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-pc-windows-msvc + - mv 2017-03-24-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index a5126cb3c3f23..933562c79e582 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 9e7abb8b36e35..8dc02ab522c21 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 2785d2135f864..44d6863bf0bbd 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 6cdb5cfca74ba..7facc52390ff4 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile index ed9b4a5929188..369e5a7dffe2a 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-freebsd/Dockerfile index 332a1fa73a4d5..633f58ea474b4 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-freebsd/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index dcb9aa905f14e..ed37a9e842e22 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index 2051396988589..d88ec7aab3464 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 3123e69e7e1df..938c53ae48837 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 52db932dcdc38..45de8100b4f27 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index fca931596853b..c1e5e863ae06c 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 17a4734aba7d1..7413c327323e5 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -67,7 +67,7 @@ COPY build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index c2877b081d5d7..4180006690fc9 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -66,7 +66,7 @@ RUN ./build-netbsd-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 100b6dcf9937e..18c7a4d2b3e7f 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -76,7 +76,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 7ebd34ee904bc..085aa35165990 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 630b122c9359a..77cf54a19a7fd 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index b9f47731eee75..c84cf56e4e858 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index e4a9c5b258fe6..f4bb9083b8582 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 104361830e1cd..68184c65cf17f 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1575efdb4cb70..6320a806fc301 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 94847712094d1..180f53ec33f31 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 542b4f90b119f..4500fc0f642de 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index 4d9b218c7654c..ad1227fa581f9 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index 04358ff97484a..f124020180571 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index dddeb82e6bfb2..fa9707d1a7352 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index 393bcf023ea5b..e5d89034dbe42 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ From 29a052d2d807dcb9f1d45878a3083af7a993263d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 25 Mar 2017 04:04:13 +0000 Subject: [PATCH 261/662] Fix ICE with nested macros in certain situations. --- src/libsyntax/ext/placeholders.rs | 2 +- src/test/run-pass/issue-40770.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-40770.rs diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f0e328a551d5f..2d0994a7b78fb 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -106,8 +106,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_item(&mut self, item: P) -> SmallVector> { match item.node { - ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {} ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), + ast::ItemKind::MacroDef(_) => return SmallVector::one(item), _ => {} } diff --git a/src/test/run-pass/issue-40770.rs b/src/test/run-pass/issue-40770.rs new file mode 100644 index 0000000000000..599d0b273e3f1 --- /dev/null +++ b/src/test/run-pass/issue-40770.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { + ($e:expr) => { + macro_rules! n { () => { $e } } + } +} + +fn main() { + m!(foo!()); +} From 57009caabd2a45a6efa4d36149feec39ab0a0658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 23:00:21 -0700 Subject: [PATCH 262/662] Identify missing item category in `impl`s ```rust struct S; impl S { pub hello_method(&self) { println!("Hello"); } } fn main() { S.hello_method(); } ``` ```rust error: can't qualify macro invocation with `pub` --> file.rs:3:4 | 3 | pub hello_method(&self) { | ^^^- - expected `!` here for a macro invocation | | | did you mean to write `fn` here for a method declaration? | = help: try adjusting the macro to put `pub` inside the invocation ``` --- src/libsyntax/parse/parser.rs | 62 ++++++++++++++++----- src/test/ui/did_you_mean/issue-40006.rs | 21 +++++++ src/test/ui/did_you_mean/issue-40006.stderr | 12 ++++ 3 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-40006.rs create mode 100644 src/test/ui/did_you_mean/issue-40006.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c0421..a19339f8cc1c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } @@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); + // Before complaining about trying to set a macro as `pub`, + // check if `!` comes after the path. + let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span.lo; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + let bang_err = self.expect(&token::Not); + if let Err(mut err) = err { + if let Err(mut bang_err) = bang_err { + // Given this code `pub path(`, it seems like this is not setting the + // visibility of a macro invocation, but rather a mistyped method declaration. + // Keep the macro diagnostic, but also provide a hint that `fn` might be + // missing. Don't complain about the missing `!` as a separate diagnostic, add + // label in the appropriate place as part of one unified diagnostic. + // + // x | pub path(&self) { + // | ^^^- - expected `!` here for a macro invocation + // | | + // | did you mean to write `fn` here for a method declaration? + + bang_err.cancel(); + err.span_label(self.span, &"expected `!` here for a macro invocation"); + // pub path( + // ^^ `sp` below will point to this + let sp = mk_sp(prev_span.hi, self.prev_span.lo); + err.span_label(sp, + &"did you mean to write `fn` here for a method declaration?"); + } + return Err(err); + } else if let Err(bang_err) = bang_err { + return Err(bang_err); + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs new file mode 100644 index 0000000000000..cf75929bae20c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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 S; + +impl S { + pub hello_method(&self) { + println!("Hello"); + } +} + +fn main() { + S.hello_method(); +} diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr new file mode 100644 index 0000000000000..93a0c58f91a57 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -0,0 +1,12 @@ +error: can't qualify macro invocation with `pub` + --> $DIR/issue-40006.rs:14:5 + | +14 | pub hello_method(&self) { + | ^^^- - expected `!` here for a macro invocation + | | + | did you mean to write `fn` here for a method declaration? + | + = help: try adjusting the macro to put `pub` inside the invocation + +error: aborting due to previous error + From 03eca713816ee00ecacde27cc655dc199c6bff40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 19:14:58 -0700 Subject: [PATCH 263/662] Point at last valid token on failed `expect_one_of` ```rust error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | 25 | foo() | - expected one of `.`, `;`, `?`, `}`, or an operator after this ... 29 | } else { | ^ unexpected token ``` --- src/libsyntax/parse/parser.rs | 28 +++++++++---------- src/test/compile-fail/issue-10636-2.rs | 2 ++ .../compile-fail/macro-incomplete-parse.rs | 2 ++ src/test/parse-fail/bounds-obj-parens.rs | 4 ++- src/test/parse-fail/match-refactor-to-expr.rs | 4 ++- .../parse-fail/trailing-plus-in-bounds.rs | 4 ++- .../ui/resolve/token-error-correct-3.stderr | 9 ++++-- .../ui/resolve/token-error-correct.stderr | 4 ++- 8 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c0421..6379015055b60 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -548,20 +548,20 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - Err(self.fatal( - &(if expected.len() > 1 { - (format!("expected one of {}, found `{}`", - expect, - actual)) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", - actual)) - } else { - (format!("expected {}, found `{}`", - expect, - actual)) - })[..] - )) + let (msg_exp, label_exp) = if expected.len() > 1 { + (format!("expected one of {}, found `{}`", expect, actual), + format!("expected one of {} after this", expect)) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + "unexpected token after this".to_string()) + } else { + (format!("expected {}, found `{}`", expect, actual), + format!("expected {} after this", expect)) + }; + let mut err = self.fatal(&msg_exp); + err.span_label(self.prev_span, &label_exp); + err.span_label(self.span, &"unexpected token"); + Err(err) } } diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/compile-fail/issue-10636-2.rs index beaf9e5059fa2..93759123618fb 100644 --- a/src/test/compile-fail/issue-10636-2.rs +++ b/src/test/compile-fail/issue-10636-2.rs @@ -14,5 +14,7 @@ pub fn trace_option(option: Option) { option.map(|some| 42; //~ NOTE: unclosed delimiter //~^ ERROR: expected one of + //~| NOTE: expected one of + //~| NOTE: unexpected token } //~ ERROR: incorrect close delimiter //~^ ERROR: expected expression, found `)` diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs index c2ac99d1f6a2d..682664df98109 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/compile-fail/macro-incomplete-parse.rs @@ -20,6 +20,8 @@ macro_rules! ignored_item { macro_rules! ignored_expr { () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator after this + //~| NOTE unexpected token 2 ) } diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/parse-fail/bounds-obj-parens.rs index ad59d4a52d74c..02c119cf727fe 100644 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ b/src/test/parse-fail/bounds-obj-parens.rs @@ -12,4 +12,6 @@ type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 37b66601e7092..7bb1c40118a4d 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,9 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` + //~^ NOTE expected one of `.`, `?`, `{`, or an operator after this + ; //~ NOTE unexpected token + //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` println!("{}", foo) } diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 4a2e6d5bdcd9c..2bb2c97790c12 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -16,4 +16,6 @@ fn main() { let x: Box = box 3 as Box; // Trailing `+` is OK } -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e3688957502..2e0edf0c4b8d1 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,13 +14,18 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | ^ + | -^ unexpected token + | | + | expected one of `,`, `.`, `?`, or an operator after this error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | +25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types + | - expected one of `.`, `;`, `?`, `}`, or an operator after this +... 29 | } else { //~ ERROR: incorrect close delimiter: `}` - | ^ + | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:21:13 diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 248a923efaf36..36f298a456a60 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,7 +32,9 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | ^ + | -^ unexpected token + | | + | expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator after this error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 From 8b92255b64989ea0e7da00a2fa94fe4358a9d7a6 Mon Sep 17 00:00:00 2001 From: Phil Ellison Date: Sat, 25 Mar 2017 09:03:22 +0000 Subject: [PATCH 264/662] Don't stutter in operator descriptions #29365 --- src/libcore/ops.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 686cc21eba1a0..d203b68c0dfd5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -196,7 +196,7 @@ pub trait Drop { fn drop(&mut self); } -/// The `Add` trait is used to specify the functionality of `+`. +/// The addition operator `+`. /// /// # Examples /// @@ -269,7 +269,7 @@ macro_rules! add_impl { add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Sub` trait is used to specify the functionality of `-`. +/// The subtraction operator `-`. /// /// # Examples /// @@ -342,7 +342,7 @@ macro_rules! sub_impl { sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Mul` trait is used to specify the functionality of `*`. +/// The multiplication operator `*`. /// /// # Examples /// @@ -464,7 +464,7 @@ macro_rules! mul_impl { mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Div` trait is used to specify the functionality of `/`. +/// The division operator `/`. /// /// # Examples /// @@ -609,7 +609,7 @@ macro_rules! div_impl_float { div_impl_float! { f32 f64 } -/// The `Rem` trait is used to specify the functionality of `%`. +/// The remainder operator `%`. /// /// # Examples /// @@ -689,7 +689,7 @@ macro_rules! rem_impl_float { rem_impl_float! { f32 f64 } -/// The `Neg` trait is used to specify the functionality of unary `-`. +/// The unary negation operator `-`. /// /// # Examples /// @@ -768,7 +768,7 @@ macro_rules! neg_impl_unsigned { // neg_impl_unsigned! { usize u8 u16 u32 u64 } neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Not` trait is used to specify the functionality of unary `!`. +/// The unary logical negation operator `!`. /// /// # Examples /// @@ -826,7 +826,7 @@ macro_rules! not_impl { not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitAnd` trait is used to specify the functionality of `&`. +/// The bitwise AND operator `&`. /// /// # Examples /// @@ -909,7 +909,7 @@ macro_rules! bitand_impl { bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitOr` trait is used to specify the functionality of `|`. +/// The bitwise OR operator `|`. /// /// # Examples /// @@ -992,7 +992,7 @@ macro_rules! bitor_impl { bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitXor` trait is used to specify the functionality of `^`. +/// The bitwise XOR operator `^`. /// /// # Examples /// @@ -1078,7 +1078,7 @@ macro_rules! bitxor_impl { bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `Shl` trait is used to specify the functionality of `<<`. +/// The left shift operator `<<`. /// /// # Examples /// @@ -1181,7 +1181,7 @@ macro_rules! shl_impl_all { shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } -/// The `Shr` trait is used to specify the functionality of `>>`. +/// The right shift operator `>>`. /// /// # Examples /// @@ -1284,7 +1284,7 @@ macro_rules! shr_impl_all { shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } -/// The `AddAssign` trait is used to specify the functionality of `+=`. +/// The addition assignment operator `+=`. /// /// # Examples /// @@ -1340,7 +1340,7 @@ macro_rules! add_assign_impl { add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `SubAssign` trait is used to specify the functionality of `-=`. +/// The subtraction assignment operator `-=`. /// /// # Examples /// @@ -1396,7 +1396,7 @@ macro_rules! sub_assign_impl { sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `MulAssign` trait is used to specify the functionality of `*=`. +/// The multiplication assignment operator `*=`. /// /// # Examples /// @@ -1441,7 +1441,7 @@ macro_rules! mul_assign_impl { mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `DivAssign` trait is used to specify the functionality of `/=`. +/// The division assignment operator `/=`. /// /// # Examples /// @@ -1485,7 +1485,7 @@ macro_rules! div_assign_impl { div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `RemAssign` trait is used to specify the functionality of `%=`. +/// The remainder assignment operator `%=`. /// /// # Examples /// @@ -1529,7 +1529,7 @@ macro_rules! rem_assign_impl { rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `BitAndAssign` trait is used to specify the functionality of `&=`. +/// The bitwise AND assignment operator `&=`. /// /// # Examples /// @@ -1615,7 +1615,7 @@ macro_rules! bitand_assign_impl { bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitOrAssign` trait is used to specify the functionality of `|=`. +/// The bitwise OR assignment operator `|=`. /// /// # Examples /// @@ -1659,7 +1659,7 @@ macro_rules! bitor_assign_impl { bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitXorAssign` trait is used to specify the functionality of `^=`. +/// The bitwise XOR assignment operator `^=`. /// /// # Examples /// @@ -1703,7 +1703,7 @@ macro_rules! bitxor_assign_impl { bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `ShlAssign` trait is used to specify the functionality of `<<=`. +/// The left shift assignment operator `<<=`. /// /// # Examples /// @@ -1768,7 +1768,7 @@ macro_rules! shl_assign_impl_all { shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } -/// The `ShrAssign` trait is used to specify the functionality of `>>=`. +/// The right shift assignment operator `>>=`. /// /// # Examples /// From 779d2f3044ee858fad70a95b8ac156105682883d Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 06:25:08 -0400 Subject: [PATCH 265/662] Link ParseBoolError to from_str method of bool --- src/libcore/str/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index dfb6936da6bda..2ef0eb0cdcfbd 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -101,7 +101,9 @@ impl FromStr for bool { } } -/// An error returned when parsing a `bool` from a string fails. +/// An error returned when parsing a `bool` using [`from_str`] fails +/// +/// [`from_str`]: ../../std/primitive.bool.html#method.from_str #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseBoolError { _priv: () } From 5d9d652e0f746d7db9542f95115d5820fefeedaa Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 25 Mar 2017 16:21:08 +0530 Subject: [PATCH 266/662] Fix typo in dec2flt/algorithm.rs --- src/libcore/num/dec2flt/algorithm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 604bc7c10dea0..60dab943a3acf 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -141,7 +141,7 @@ pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Opt /// /// It rounds ``f`` to a float with 64 bit significand and multiplies it by the best approximation /// of `10^e` (in the same floating point format). This is often enough to get the correct result. -/// However, when the result is close to halfway between two adjecent (ordinary) floats, the +/// However, when the result is close to halfway between two adjacent (ordinary) floats, the /// compound rounding error from multiplying two approximation means the result may be off by a /// few bits. When this happens, the iterative Algorithm R fixes things up. /// @@ -392,7 +392,7 @@ fn underflow(x: Big, v: Big, rem: Big) -> T { // // Therefore, when the rounded-off bits are != 0.5 ULP, they decide the rounding // on their own. When they are equal and the remainder is non-zero, the value still - // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainer + // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainder // is zero, we have a half-to-even situation. let bits = x.bit_length(); let lsb = bits - T::sig_bits() as usize; From 6344d087279e0cab9936c31e11e427694529c8f1 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 7 Mar 2017 10:17:55 -0300 Subject: [PATCH 267/662] Update libc to 0.2.21 --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 64d954c6a76e8..05a2d197356ef 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 64d954c6a76e896fbf7ed5c17e77c40e388abe84 +Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f From a7add43389d435bda8769cb73ac6636237633836 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 16 Mar 2017 16:07:56 -0300 Subject: [PATCH 268/662] Fix c_char (u8 -> i8) definition for i686-linux-android --- src/libstd/os/raw.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 68d4ca900195c..c34491941d690 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -14,22 +14,24 @@ use fmt; -#[cfg(any(target_os = "android", - target_os = "emscripten", +#[cfg(any(target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[cfg(not(any(target_os = "android", - target_os = "emscripten", +#[cfg(not(any(target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; From b45c631382a0bb831dc038973288e3f6d91cb07a Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Fri, 17 Mar 2017 08:06:23 -0300 Subject: [PATCH 269/662] Fix libc::bind call on aarch64-linux-android --- src/libstd/sys/unix/ext/net.rs | 4 ++-- src/libstd/sys_common/net.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 55118829eee9f..d688f2fa50451 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -641,7 +641,7 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(*inner.as_inner(), 128))?; Ok(UnixListener(inner)) @@ -920,7 +920,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; Ok(socket) } diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 3cdeb51194575..9239c18e59717 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -339,7 +339,7 @@ impl TcpListener { // Bind our new socket let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?; + cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; // Start listening cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; @@ -430,7 +430,7 @@ impl UdpSocket { let sock = Socket::new(addr, c::SOCK_DGRAM)?; let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?; + cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; Ok(UdpSocket { inner: sock }) } From ca85c400dae365c9ade87bbd100ddfe3ecd3822a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 25 Mar 2017 15:01:25 +0300 Subject: [PATCH 270/662] travis: try to fix the build on emscripten The emsdk-portable .tar.gz now extracts to emsdk-portable instead of emsdk_portable. Handle that. --- src/ci/docker/emscripten/build-emscripten.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index 88bf583007ce5..b9aa197f85e0d 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -29,7 +29,20 @@ exit 1 } curl https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ - tar xzf - + tar xzf - + +# Some versions of the EMSDK archive have their contents in .emsdk-portable +# and others in emsdk_portable. Make sure the EMSDK ends up in a fixed path. +if [ -d emsdk-portable ]; then + mv emsdk-portable emsdk_portable +fi + +if [ ! -d emsdk_portable ]; then + echo "ERROR: Invalid emsdk archive. Dumping working directory." >&2 + ls -l + exit 1 +fi + source emsdk_portable/emsdk_env.sh hide_output emsdk update hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit From 33a6a07d586437e8d4894dc35413a21ee5cfba54 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 11:56:52 -0400 Subject: [PATCH 271/662] FromStr implementation example --- src/libcore/str/mod.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index dfb6936da6bda..bc5df6810a9d9 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -35,6 +35,39 @@ pub mod pattern; /// [`from_str`]: #tymethod.from_str /// [`str`]: ../../std/primitive.str.html /// [`parse`]: ../../std/primitive.str.html#method.parse +/// +/// # Examples +/// +/// Basic implementation of `FromStr` on an example `Point` type: +/// +/// ``` +/// use std::str::FromStr; +/// use std::num::ParseIntError; +/// +/// #[derive(Debug, PartialEq)] +/// struct Point { +/// x: i32, +/// y: i32 +/// } +/// +/// impl FromStr for Point { +/// type Err = ParseIntError; +/// +/// fn from_str(s: &str) -> Result { +/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) +/// .split(",") +/// .collect(); +/// +/// let x_fromstr = try!(coords[0].parse::()); +/// let y_fromstr = try!(coords[1].parse::()); +/// +/// Ok(Point { x: x_fromstr, y: y_fromstr }) +/// } +/// } +/// +/// let p = Point::from_str("(1,2)"); +/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. From 935d84a272a8b637e13c54b18a1571994e962e5c Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 25 Mar 2017 17:22:07 +0100 Subject: [PATCH 272/662] fix permissions of emsdk_portable --- src/ci/docker/emscripten/build-emscripten.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index b9aa197f85e0d..e39767357ad63 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -43,6 +43,10 @@ if [ ! -d emsdk_portable ]; then exit 1 fi +# Some versions of the EMSDK set the permissions of the root directory to +# 0700. Ensure the directory is readable by all users. +chmod 755 emsdk_portable + source emsdk_portable/emsdk_env.sh hide_output emsdk update hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit From 64cd0bebab1a9023dc5a4bbc38f9e6820629fbb9 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 12:22:23 -0400 Subject: [PATCH 273/662] Remove trailing whitespace --- src/libcore/str/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index bc5df6810a9d9..ae08a3d0a9a7d 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -43,28 +43,28 @@ pub mod pattern; /// ``` /// use std::str::FromStr; /// use std::num::ParseIntError; -/// +/// /// #[derive(Debug, PartialEq)] /// struct Point { /// x: i32, /// y: i32 /// } -/// +/// /// impl FromStr for Point { /// type Err = ParseIntError; -/// +/// /// fn from_str(s: &str) -> Result { /// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) /// .split(",") /// .collect(); -/// +/// /// let x_fromstr = try!(coords[0].parse::()); /// let y_fromstr = try!(coords[1].parse::()); -/// +/// /// Ok(Point { x: x_fromstr, y: y_fromstr }) /// } /// } -/// +/// /// let p = Point::from_str("(1,2)"); /// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) /// ``` From fb5e63fc475996ee5c65fb1b8686b8db17eb1e63 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 14:41:37 -0400 Subject: [PATCH 274/662] Change `try!` to `?` --- src/libcore/str/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index ae08a3d0a9a7d..f3c3994ef3150 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -58,8 +58,8 @@ pub mod pattern; /// .split(",") /// .collect(); /// -/// let x_fromstr = try!(coords[0].parse::()); -/// let y_fromstr = try!(coords[1].parse::()); +/// let x_fromstr = coords[0].parse::()?; +/// let y_fromstr = coords[1].parse::()?; /// /// Ok(Point { x: x_fromstr, y: y_fromstr }) /// } From 2e14bfe0d7ce376a42bdc4c7eb964fd91aad3c32 Mon Sep 17 00:00:00 2001 From: projektir Date: Sat, 25 Mar 2017 15:33:44 -0400 Subject: [PATCH 275/662] rustdoc to accept `#` at the start of a markdown file #40560 --- src/librustdoc/markdown.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index c67e2fdc2b027..5fadda030a4b4 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -28,20 +28,22 @@ use html::markdown; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; use test::{TestOptions, Collector}; -/// Separate any lines at the start of the file that begin with `%`. +/// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { let mut metadata = Vec::new(); let mut count = 0; + for line in s.lines() { - if line.starts_with("%") { - // remove % + if line.starts_with("# ") || line.starts_with("%") { + // trim the whitespace after the symbol metadata.push(line[1..].trim_left()); count += line.len() + 1; } else { return (metadata, &s[count..]); } } - // if we're here, then all lines were metadata % lines. + + // if we're here, then all lines were metadata `# ` or `%` lines. (metadata, "") } @@ -83,7 +85,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, if metadata.is_empty() { let _ = writeln!( &mut io::stderr(), - "rustdoc: invalid markdown file: expecting initial line with `% ...TITLE...`" + "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`" ); return 5; } From 6341a8b0e5155abf4bf338d3df7f6d2971f83adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 23:40:24 -0700 Subject: [PATCH 276/662] Clarify suggetion for field used as method Instead of ``` error: no method named `src_addr` found for type `&wire::ipv4::Repr` in the current scope --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ | note: did you mean to write `self.src_addr`? --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ ``` present ``` error: no method named `src_addr` found for type `&wire::ipv4::Repr` in the current scope --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ `src_addr` is a field, not a method | = help: did you mean to write `self.src_addr` instead of `self.src_addr(...)`? ``` --- src/librustc_typeck/check/method/suggest.rs | 26 ++++++++------ src/test/compile-fail/issue-18343.rs | 6 ++-- src/test/compile-fail/issue-2392.rs | 39 ++++++++++++++------- src/test/compile-fail/issue-32128.rs | 6 ++-- src/test/compile-fail/issue-33784.rs | 9 +++-- 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6ce50d91124d4..b458c1af71d06 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -197,17 +197,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = field.ty(tcx, substs); if self.is_fn_ty(&field_ty, span) { - err.span_note(span, - &format!("use `({0}.{1})(...)` if you \ - meant to call the function \ - stored in the `{1}` field", - expr_string, - item_name)); + err.help(&format!("use `({0}.{1})(...)` if you \ + meant to call the function \ + stored in the `{1}` field", + expr_string, + item_name)); + err.span_label(span, + &format!("`{}` is a field storing a \ + function, not a method", + item_name)); } else { - err.span_note(span, - &format!("did you mean to write `{0}.{1}`?", - expr_string, - item_name)); + err.help(&format!("did you mean to write `{0}.{1}` \ + instead of `{0}.{1}(...)`?", + expr_string, + item_name)); + err.span_label(span, + &format!("`{}` is a field, not a method", + item_name)); } break; } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 4601db9dba0fc..a095bb4812610 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -14,6 +14,8 @@ struct Obj where F: FnMut() -> u32 { fn main() { let o = Obj { closure: || 42 }; - o.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + o.closure(); + //~^ ERROR no method named `closure` found + //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method } diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs index 805725dd749f5..12389f885364d 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/compile-fail/issue-2392.rs @@ -48,45 +48,58 @@ fn main() { let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored + //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method - o_closure.not_closure(); //~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `o_closure.not_closure`? + o_closure.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE `not_closure` is a field, not a method + //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored + //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE `boxed_closure` is a field storing a function, not a method let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE `boxed_closure` is a field storing a function, not a method // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored + //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method - w.wrap.not_closure();//~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `w.wrap.not_closure`? + w.wrap.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE `not_closure` is a field, not a method + //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? check_expression().closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored + //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method } impl FuncContainerOuter { fn run(&self) { unsafe { (*self.container).f1(1); //~ ERROR no method named `f1` found - //~^ NOTE use `((*self.container).f1)(...)` + //~^ HELP use `((*self.container).f1)(...)` + //~| NOTE `f1` is a field storing a function, not a method (*self.container).f2(1); //~ ERROR no method named `f2` found - //~^ NOTE use `((*self.container).f2)(...)` + //~^ HELP use `((*self.container).f2)(...)` + //~| NOTE `f2` is a field storing a function, not a method (*self.container).f3(1); //~ ERROR no method named `f3` found - //~^ NOTE use `((*self.container).f3)(...)` + //~^ HELP use `((*self.container).f3)(...)` + //~| NOTE `f3` is a field storing a function, not a method } } } diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/compile-fail/issue-32128.rs index fe7e66a2116eb..74fbb33296e4b 100644 --- a/src/test/compile-fail/issue-32128.rs +++ b/src/test/compile-fail/issue-32128.rs @@ -19,7 +19,9 @@ fn main() { }) }; - demo.example(1); //~ ERROR no method named `example` - //~^ NOTE use `(demo.example)(...)` + demo.example(1); + //~^ ERROR no method named `example` + //~| HELP use `(demo.example)(...)` + //~| NOTE `example` is a field storing a function, not a method // (demo.example)(1); } diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/compile-fail/issue-33784.rs index 4229be29473db..03c84fc57befe 100644 --- a/src/test/compile-fail/issue-33784.rs +++ b/src/test/compile-fail/issue-33784.rs @@ -35,12 +35,15 @@ fn main() { let o = Obj { fn_ptr: empty, closure: || 42 }; let p = &o; p.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~^ HELP use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method let q = &p; q.fn_ptr(); //~ ERROR no method named `fn_ptr` found - //~^ NOTE use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~^ HELP use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~| NOTE `fn_ptr` is a field storing a function, not a method let r = D(C { c_fn_ptr: empty }); let s = &r; s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found - //~^ NOTE use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~^ HELP use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~| NOTE `c_fn_ptr` is a field storing a function, not a method } From 24be89980e2e89404075fe463edae0f5db369251 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Sat, 25 Mar 2017 17:15:26 -0300 Subject: [PATCH 277/662] Avoid using libc::sigemptyset on Android --- src/libstd/sys/unix/process/process_common.rs | 16 +++++++++++++++- src/libstd/sys/unix/process/process_unix.rs | 11 ++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 5f1a6c2f74651..e9f41009064ca 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -417,12 +417,26 @@ mod tests { } } + // Android with api less than 21 define sig* functions inline, so it is not + // available for dynamic link. Implementing sigemptyset and sigaddset allow us + // to support older Android version (independent of libc version). + // The following implementations are based on https://git.io/vSkNf + #[cfg(not(target_os = "android"))] extern { + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] + fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; } + #[cfg(target_os = "android")] + unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { + libc::memset(set as *mut _, 0, mem::size_of::()); + return 0; + } + #[cfg(target_os = "android")] unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { use slice; @@ -450,7 +464,7 @@ mod tests { let mut set: libc::sigset_t = mem::uninitialized(); let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + t!(cvt(sigemptyset(&mut set))); t!(cvt(sigaddset(&mut set, libc::SIGINT))); t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index a213273aac8fd..edd322ca6fa07 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -193,7 +193,16 @@ impl Command { // need to clean things up now to avoid confusing the program // we're about to run. let mut set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + if cfg!(target_os = "android") { + // Implementing sigemptyset allow us to support older Android + // versions. See the comment about Android and sig* functions in + // process_common.rs + libc::memset(&mut set as *mut _ as *mut _, + 0, + mem::size_of::()); + } else { + t!(cvt(libc::sigemptyset(&mut set))); + } t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, ptr::null_mut()))); let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); From 1d59c67942ea682d0de4bb847d6da38d6417e07d Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Sat, 25 Mar 2017 17:19:36 -0400 Subject: [PATCH 278/662] Update ChildStderr docs to be clearer Before the docs only had a line about where it was found and that it was a handle to stderr. This commit changes it so that the summary second line is removed and that it's a bit clearer about what can be done with it. Part of \#29370 --- src/libstd/process.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7a85e58866236..265228281f853 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -233,8 +233,9 @@ impl fmt::Debug for ChildStdout { } } -/// A handle to a child process's stderr. This struct is used in the [`stderr`] -/// field on [`Child`]. +/// A handle to a child process's stderr. It can be used to +/// read any errors that the child process has output while +/// running. /// /// [`Child`]: struct.Child.html /// [`stderr`]: struct.Child.html#structfield.stderr From 78ae8feebbf9a2c70d42780d0c646cbbc1f2cdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 25 Mar 2017 15:36:59 -0700 Subject: [PATCH 279/662] Improve wording and spans for unexpected token * Point at where the token was expected instead of the last token successfuly parsed. * Only show `unexpected token` if the next char and the unexpected token don't have the same span. * Change some cfail and pfail tests to ui test. * Don't show all possible tokens in span label if they are more than 6. --- src/libsyntax/parse/parser.rs | 25 +++++++++++---- src/libsyntax_pos/lib.rs | 6 ++++ src/test/parse-fail/match-refactor-to-expr.rs | 2 +- .../ui/resolve/token-error-correct-3.stderr | 6 ++-- .../ui/resolve/token-error-correct.stderr | 4 +-- .../token}/bounds-obj-parens.rs | 0 src/test/ui/token/bounds-obj-parens.stderr | 7 +++++ .../token}/issue-10636-2.rs | 0 src/test/ui/token/issue-10636-2.stderr | 27 ++++++++++++++++ .../token}/macro-incomplete-parse.rs | 2 +- .../ui/token/macro-incomplete-parse.stderr | 31 +++++++++++++++++++ .../token}/trailing-plus-in-bounds.rs | 0 .../ui/token/trailing-plus-in-bounds.stderr | 7 +++++ 13 files changed, 102 insertions(+), 15 deletions(-) rename src/test/{parse-fail => ui/token}/bounds-obj-parens.rs (100%) create mode 100644 src/test/ui/token/bounds-obj-parens.stderr rename src/test/{compile-fail => ui/token}/issue-10636-2.rs (100%) create mode 100644 src/test/ui/token/issue-10636-2.stderr rename src/test/{compile-fail => ui/token}/macro-incomplete-parse.rs (98%) create mode 100644 src/test/ui/token/macro-incomplete-parse.stderr rename src/test/{parse-fail => ui/token}/trailing-plus-in-bounds.rs (100%) create mode 100644 src/test/ui/token/trailing-plus-in-bounds.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6379015055b60..4076368c180b6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -548,19 +548,32 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - let (msg_exp, label_exp) = if expected.len() > 1 { + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; (format!("expected one of {}, found `{}`", expect, actual), - format!("expected one of {} after this", expect)) + (self.prev_span.next_point(), format!("expected one of {} here", short_expect))) } else if expected.is_empty() { (format!("unexpected token: `{}`", actual), - "unexpected token after this".to_string()) + (self.prev_span, "unexpected token after this".to_string())) } else { (format!("expected {}, found `{}`", expect, actual), - format!("expected {} after this", expect)) + (self.prev_span.next_point(), format!("expected {} here", expect))) }; let mut err = self.fatal(&msg_exp); - err.span_label(self.prev_span, &label_exp); - err.span_label(self.span, &"unexpected token"); + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + err.span_label(sp, &label_exp); + if label_sp != self.span { + err.span_label(self.span, &"unexpected token"); + } Err(err) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3808923e7728f..07494ff904e95 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -79,6 +79,12 @@ impl Span { Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} } + /// Returns a new span representing the next character after the end-point of this span + pub fn next_point(self) -> Span { + let lo = BytePos(cmp::max(self.hi.0, self.lo.0 + 1)); + Span { lo: lo, hi: lo, expn_id: self.expn_id} + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.source_equal(&DUMMY_SP) { other } else { self } diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 7bb1c40118a4d..e2fee1d189591 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,7 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - //~^ NOTE expected one of `.`, `?`, `{`, or an operator after this + //~^ NOTE expected one of `.`, `?`, `{`, or an operator here ; //~ NOTE unexpected token //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 2e0edf0c4b8d1..bf7db67e72850 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,15 +14,13 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | -^ unexpected token - | | - | expected one of `,`, `.`, `?`, or an operator after this + | ^ expected one of `,`, `.`, `?`, or an operator here error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | 25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - | - expected one of `.`, `;`, `?`, `}`, or an operator after this + | - expected one of `.`, `;`, `?`, `}`, or an operator here ... 29 | } else { //~ ERROR: incorrect close delimiter: `}` | ^ unexpected token diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 36f298a456a60..226fa6469bc74 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,9 +32,7 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | -^ unexpected token - | | - | expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator after this + | ^ expected one of 18 possible tokens here error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/ui/token/bounds-obj-parens.rs similarity index 100% rename from src/test/parse-fail/bounds-obj-parens.rs rename to src/test/ui/token/bounds-obj-parens.rs diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr new file mode 100644 index 0000000000000..ebee363f278e2 --- /dev/null +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -0,0 +1,7 @@ +error: expected one of `!` or `::`, found `` + --> $DIR/bounds-obj-parens.rs:15:1 + | +15 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/ui/token/issue-10636-2.rs similarity index 100% rename from src/test/compile-fail/issue-10636-2.rs rename to src/test/ui/token/issue-10636-2.rs diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr new file mode 100644 index 0000000000000..183ad30c4ef47 --- /dev/null +++ b/src/test/ui/token/issue-10636-2.stderr @@ -0,0 +1,27 @@ +error: incorrect close delimiter: `}` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + | +note: unclosed delimiter + --> $DIR/issue-10636-2.rs:15:15 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ + +error: expected one of `,`, `.`, `?`, or an operator, found `;` + --> $DIR/issue-10636-2.rs:15:25 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ expected one of `,`, `.`, `?`, or an operator here + +error: expected expression, found `)` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + +error: main function not found + +error: aborting due to 4 previous errors diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs similarity index 98% rename from src/test/compile-fail/macro-incomplete-parse.rs rename to src/test/ui/token/macro-incomplete-parse.rs index 682664df98109..47374fc3c6085 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/ui/token/macro-incomplete-parse.rs @@ -20,7 +20,7 @@ macro_rules! ignored_item { macro_rules! ignored_expr { () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator after this + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator here //~| NOTE unexpected token 2 ) } diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr new file mode 100644 index 0000000000000..bea00a6444c47 --- /dev/null +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -0,0 +1,31 @@ +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:17:9 + | +17 | , //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context + --> $DIR/macro-incomplete-parse.rs:32:1 + | +32 | ignored_item!(); //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/macro-incomplete-parse.rs:22:14 + | +22 | () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + | ^ expected one of `.`, `;`, `?`, `}`, or an operator here + +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:29:14 + | +29 | () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context + --> $DIR/macro-incomplete-parse.rs:37:9 + | +37 | ignored_pat!() => (), //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/ui/token/trailing-plus-in-bounds.rs similarity index 100% rename from src/test/parse-fail/trailing-plus-in-bounds.rs rename to src/test/ui/token/trailing-plus-in-bounds.rs diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr new file mode 100644 index 0000000000000..74caf8f5c2b36 --- /dev/null +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -0,0 +1,7 @@ +error: expected one of `!` or `::`, found `` + --> ../../src/test/ui/token/trailing-plus-in-bounds.rs:19:1 + | +19 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error From 53b70953c3e628794debf38acfad90f21bc74a7e Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 25 Mar 2017 15:46:13 -0700 Subject: [PATCH 280/662] char::to_uppercase doc typo: s/lowercase/uppercase/ --- src/libstd_unicode/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index b980300126e4b..e612be52e779b 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -846,7 +846,7 @@ impl char { /// will be returned back by the iterator. /// /// This performs complex unconditional mappings with no tailoring: it maps - /// one Unicode character to its lowercase equivalent according to the + /// one Unicode character to its uppercase equivalent according to the /// [Unicode database] and the additional complex mappings /// [`SpecialCasing.txt`]. Conditional mappings (based on context or /// language) are not considered here. From 188299e04a0c065f7b8f536e40d0a8826b1ae833 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 25 Mar 2017 15:58:35 -0700 Subject: [PATCH 281/662] char::to_uppercase doc typo: use the 'an' article. --- src/libstd_unicode/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index e612be52e779b..92e5369758b4e 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -842,7 +842,7 @@ impl char { /// Returns an iterator that yields the uppercase equivalent of a `char` /// as one or more `char`s. /// - /// If a character does not have a uppercase equivalent, the same character + /// If a character does not have an uppercase equivalent, the same character /// will be returned back by the iterator. /// /// This performs complex unconditional mappings with no tailoring: it maps From 7e0f7a50ab649fb70773af35e78ca73b5123f52e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 26 Mar 2017 14:15:47 +0300 Subject: [PATCH 282/662] store a copy of the Issue32230 info within TypeError The data can't be looked up from the region variable directly, because the region variable might have been destroyed at the end of a snapshot. Fixes #40000. Fixes #40743. --- src/librustc/infer/error_reporting/mod.rs | 42 ++++++++++------------- src/librustc/infer/higher_ranked/mod.rs | 18 ++++++++-- src/librustc/ty/error.rs | 14 ++++---- src/librustc/ty/structural_impls.rs | 10 +++--- src/test/compile-fail/issue-40000.rs | 21 ++++++++++++ 5 files changed, 69 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/issue-40000.rs diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 21139c8dde2a4..9fa2bc8a2a7a9 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -426,30 +426,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("note_issue_32330: terr={:?}", terr); match *terr { - TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) | - TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => { - match self.region_vars.var_origin(vid) { - RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 { - fn_def_id, - region_name - })) => { - diag.note( - &format!("lifetime parameter `{0}` declared on fn `{1}` \ - appears only in the return type, \ - but here is required to be higher-ranked, \ - which means that `{0}` must appear in both \ - argument and return types", - region_name, - self.tcx.item_path_str(fn_def_id))); - diag.note( - &format!("this error is the result of a recent bug fix; \ - for more information, see issue #33685 \ - ")); - } - _ => { } - } + TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) | + TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) => { + diag.note( + &format!("lifetime parameter `{0}` declared on fn `{1}` \ + appears only in the return type, \ + but here is required to be higher-ranked, \ + which means that `{0}` must appear in both \ + argument and return types", + region_name, + self.tcx.item_path_str(fn_def_id))); + diag.note( + &format!("this error is the result of a recent bug fix; \ + for more information, see issue #33685 \ + ")); } - _ => { } + _ => {} } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index e919f025409c5..e3ffc99c0e967 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -15,6 +15,7 @@ use super::{CombinedSnapshot, InferCtxt, LateBoundRegion, HigherRankedType, + RegionVariableOrigin, SubregionOrigin, SkolemizationMap}; use super::combine::CombineFields; @@ -656,14 +657,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { skol_br, tainted_region); + let issue_32330 = if let &ty::ReVar(vid) = tainted_region { + match self.region_vars.var_origin(vid) { + RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => { + issue_32330.map(Box::new) + } + _ => None + } + } else { + None + }; + if overly_polymorphic { debug!("Overly polymorphic!"); return Err(TypeError::RegionsOverlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } else { debug!("Not as polymorphic!"); return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5a696446b4bb6..73d9c8b00ae47 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -39,8 +39,8 @@ pub enum TypeError<'tcx> { RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), RegionsNotSame(&'tcx Region, &'tcx Region), RegionsNoOverlap(&'tcx Region, &'tcx Region), - RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region), - RegionsOverlyPolymorphic(BoundRegion, &'tcx Region), + RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region, Option>), + RegionsOverlyPolymorphic(BoundRegion, &'tcx Region, Option>), Sorts(ExpectedFound>), IntMismatch(ExpectedFound), FloatMismatch(ExpectedFound), @@ -116,11 +116,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { RegionsNoOverlap(..) => { write!(f, "lifetimes do not intersect") } - RegionsInsufficientlyPolymorphic(br, _) => { + RegionsInsufficientlyPolymorphic(br, _, _) => { write!(f, "expected bound lifetime parameter {}, \ found concrete lifetime", br) } - RegionsOverlyPolymorphic(br, _) => { + RegionsOverlyPolymorphic(br, _, _) => { write!(f, "expected concrete lifetime, \ found bound lifetime parameter {}", br) } @@ -253,15 +253,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.note_and_explain_region(db, "...does not overlap ", region2, ""); } - RegionsInsufficientlyPolymorphic(_, conc_region) => { + RegionsInsufficientlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "concrete lifetime that was found is ", conc_region, ""); } - RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => { + RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { // don't bother to print out the message below for // inference variables, it's not very illuminating. } - RegionsOverlyPolymorphic(_, conc_region) => { + RegionsOverlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "expected concrete lifetime is ", conc_region, ""); } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 49824e8a738d7..9126600e3f653 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -293,11 +293,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsNoOverlap(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b)) } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) + RegionsInsufficientlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c)) } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) + RegionsOverlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c)) } IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), diff --git a/src/test/compile-fail/issue-40000.rs b/src/test/compile-fail/issue-40000.rs new file mode 100644 index 0000000000000..9be114ebcb6e0 --- /dev/null +++ b/src/test/compile-fail/issue-40000.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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(closure_to_fn_coercion)] + +fn main() { + let bar: fn(&mut u32) = |_| {}; //~ ERROR mismatched types + //~| expected concrete lifetime, found bound lifetime parameter + + fn foo(x: Box) {} + let bar = Box::new(|x: &i32| {}) as Box; + foo(bar); //~ ERROR mismatched types + //~| expected concrete lifetime, found bound lifetime parameter +} From 6e6dec0cab0731c4c32f6592f02c02cf4fd03a8d Mon Sep 17 00:00:00 2001 From: aStoate Date: Sun, 26 Mar 2017 21:47:22 +1030 Subject: [PATCH 283/662] change string references in asciiext r? @steveklabnik --- src/libstd/ascii.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index af21d6d906eb5..ba2b059f8284b 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -17,7 +17,7 @@ use mem; use ops::Range; use iter::FusedIterator; -/// Extension methods for ASCII-subset only operations on string slices. +/// Extension methods for ASCII-subset only operations. /// /// Be aware that operations on seemingly non-ASCII characters can sometimes /// have unexpected results. Consider this example: @@ -54,19 +54,21 @@ pub trait AsciiExt { /// /// let ascii = 'a'; /// let utf8 = '❤'; + /// let int_ascii = 97; /// /// assert!(ascii.is_ascii()); /// assert!(!utf8.is_ascii()); + /// assert!(int_ascii.is_ascii()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; - /// Makes a copy of the string in ASCII upper case. + /// Makes a copy of the value in it's ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To uppercase the string in-place, use [`make_ascii_uppercase`]. + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. /// /// To uppercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_uppercase`]. @@ -78,9 +80,11 @@ pub trait AsciiExt { /// /// let ascii = 'a'; /// let utf8 = '❤'; + /// let int_ascii = 97; /// /// assert_eq!('A', ascii.to_ascii_uppercase()); /// assert_eq!('❤', utf8.to_ascii_uppercase()); + /// assert_eq!(65, int_ascii.to_ascii_uppercase()); /// ``` /// /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase @@ -88,12 +92,12 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_uppercase(&self) -> Self::Owned; - /// Makes a copy of the string in ASCII lower case. + /// Makes a copy of the value in it's ASCII lower case equivalent. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To lowercase the string in-place, use [`make_ascii_lowercase`]. + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. /// /// To lowercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_lowercase`]. @@ -105,9 +109,11 @@ pub trait AsciiExt { /// /// let ascii = 'A'; /// let utf8 = '❤'; + /// let int_ascii = 65; /// /// assert_eq!('a', ascii.to_ascii_lowercase()); /// assert_eq!('❤', utf8.to_ascii_lowercase()); + /// assert_eq!(97, int_ascii.to_ascii_lowercase()); /// ``` /// /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase @@ -115,10 +121,10 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_lowercase(&self) -> Self::Owned; - /// Checks that two strings are an ASCII case-insensitive match. + /// Checks that two values are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporary strings. + /// but without allocating and copying temporaries. /// /// # Examples /// @@ -142,7 +148,7 @@ pub trait AsciiExt { /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To return a new uppercased string without modifying the existing one, use + /// To return a new uppercased value without modifying the existing one, use /// [`to_ascii_uppercase`]. /// /// # Examples @@ -166,7 +172,7 @@ pub trait AsciiExt { /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To return a new lowercased string without modifying the existing one, use + /// To return a new lowercased value without modifying the existing one, use /// [`to_ascii_lowercase`]. /// /// # Examples From 169facfc288586b7635652abace56d56da2a6f99 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 17:11:08 +0100 Subject: [PATCH 284/662] added missing links in std::net TCP docs part of #29363 --- src/libstd/net/tcp.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index a07972468e68a..8a21f17dc49fb 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -83,11 +83,15 @@ impl TcpStream { /// Opens a TCP connection to a remote host. /// /// `addr` is an address of the remote host. Anything which implements - /// `ToSocketAddrs` trait can be supplied for the address; see this trait + /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait /// documentation for concrete examples. - /// In case `ToSocketAddrs::to_socket_addrs()` returns more than one entry, + /// In case [`ToSocketAddrs::to_socket_addrs()`] returns more than one entry, /// then the first valid and reachable address is used. /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// [`ToSocketAddrs::to_socket_addrs()`]: + /// ../../std/net/trait.ToSocketAddrs.html#tymethod.to_socket_addrs + /// /// # Examples /// /// ```no_run @@ -494,11 +498,14 @@ impl TcpListener { /// /// Binding with a port number of 0 will request that the OS assigns a port /// to this listener. The port allocated can be queried via the - /// `local_addr` method. + /// [`local_addr`] method. /// - /// The address type can be any implementor of `ToSocketAddrs` trait. See + /// The address type can be any implementor of [`ToSocketAddrs`] trait. See /// its documentation for concrete examples. /// + /// [`local_addr`]: #method.local_addr + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// /// # Examples /// /// ```no_run @@ -529,10 +536,12 @@ impl TcpListener { /// Creates a new independently owned handle to the underlying socket. /// - /// The returned `TcpListener` is a reference to the same socket that this + /// The returned [`TcpListener`] is a reference to the same socket that this /// object references. Both handles can be used to accept incoming /// connections and options set on one listener will affect the other. /// + /// [`TcpListener`]: ../../std/net/struct.TcpListener.html + /// /// # Examples /// /// ```no_run @@ -549,9 +558,11 @@ impl TcpListener { /// Accept a new incoming connection from this listener. /// /// This function will block the calling thread until a new TCP connection - /// is established. When established, the corresponding `TcpStream` and the + /// is established. When established, the corresponding [`TcpStream`] and the /// remote peer's address will be returned. /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// /// # Examples /// /// ```no_run From 76d08eda7d228ed475bf190253b8fd7ebfe667db Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 14:30:03 +0200 Subject: [PATCH 285/662] Update std::net:Incoming's docs to use standard iterator boilerplate Part of #29363 --- src/libstd/net/tcp.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 8a21f17dc49fb..c6cf748d981c7 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -65,16 +65,14 @@ pub struct TcpStream(net_imp::TcpStream); #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); -/// An infinite iterator over the connections from a `TcpListener`. -/// -/// This iterator will infinitely yield [`Some`] of the accepted connections. It -/// is equivalent to calling `accept` in a loop. +/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. /// /// This `struct` is created by the [`incoming`] method on [`TcpListener`]. +/// See its documentation for more. /// -/// [`Some`]: ../../std/option/enum.Option.html#variant.Some -/// [`incoming`]: struct.TcpListener.html#method.incoming -/// [`TcpListener`]: struct.TcpListener.html +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Incoming<'a> { listener: &'a TcpListener } @@ -583,10 +581,12 @@ impl TcpListener { /// listener. /// /// The returned iterator will never return [`None`] and will also not yield - /// the peer's [`SocketAddr`] structure. + /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to + /// calling [`accept`] in a loop. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// [`accept`]: #method.accept /// /// # Examples /// From 0df7398558cb7d8fbf5d191d7e07a601a4a30702 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 17:27:00 +0100 Subject: [PATCH 286/662] std::net docs: changed occurences of "RFC" to say "IETF RFC" part of #29363 --- src/libstd/net/ip.rs | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 24e0e6f3fa659..44dc689a30f4c 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -296,9 +296,9 @@ impl Ipv4Addr { /// Returns true if this is a loopback address (127.0.0.0/8). /// - /// This property is defined by [RFC 1122]. + /// This property is defined by [IETF RFC 1122]. /// - /// [RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 /// /// # Examples /// @@ -315,13 +315,13 @@ impl Ipv4Addr { /// Returns true if this is a private address. /// - /// The private address ranges are defined in [RFC 1918] and include: + /// The private address ranges are defined in [IETF RFC 1918] and include: /// /// - 10.0.0.0/8 /// - 172.16.0.0/12 /// - 192.168.0.0/16 /// - /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// # Examples /// @@ -348,9 +348,9 @@ impl Ipv4Addr { /// Returns true if the address is link-local (169.254.0.0/16). /// - /// This property is defined by [RFC 3927]. + /// This property is defined by [IETF RFC 3927]. /// - /// [RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 /// /// # Examples /// @@ -403,9 +403,9 @@ impl Ipv4Addr { /// Returns true if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, - /// and is defined by [RFC 5771]. + /// and is defined by [IETF RFC 5771]. /// - /// [RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 /// /// # Examples /// @@ -423,9 +423,9 @@ impl Ipv4Addr { /// Returns true if this is a broadcast address (255.255.255.255). /// - /// A broadcast address has all octets set to 255 as defined in [RFC 919]. + /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// - /// [RFC 919]: https://tools.ietf.org/html/rfc919 + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// /// # Examples /// @@ -443,13 +443,13 @@ impl Ipv4Addr { /// Returns true if this address is in a range designated for documentation. /// - /// This is defined in [RFC 5737]: + /// This is defined in [IETF RFC 5737]: /// /// - 192.0.2.0/24 (TEST-NET-1) /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) /// - /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// # Examples /// @@ -719,9 +719,9 @@ impl Ipv6Addr { /// Returns true for the special 'unspecified' address (::). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// @@ -738,9 +738,9 @@ impl Ipv6Addr { /// Returns true if this is a loopback address (::1). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// @@ -786,9 +786,9 @@ impl Ipv6Addr { /// Returns true if this is a unique local address (fc00::/7). /// - /// This property is defined in [RFC 4193]. + /// This property is defined in [IETF RFC 4193]. /// - /// [RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 /// /// # Examples /// @@ -809,9 +809,9 @@ impl Ipv6Addr { /// Returns true if the address is unicast and link-local (fe80::/10). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// @@ -853,9 +853,9 @@ impl Ipv6Addr { /// Returns true if this is an address reserved for documentation /// (2001:db8::/32). /// - /// This property is defined in [RFC 3849]. + /// This property is defined in [IETF RFC 3849]. /// - /// [RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 /// /// # Examples /// @@ -939,9 +939,9 @@ impl Ipv6Addr { /// Returns true if this is a multicast address (ff00::/8). /// - /// This property is defined by [RFC 4291]. + /// This property is defined by [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// # Examples /// /// ``` From df5830a4ece5eae8451e7b3d4f77b8af92a9f9fc Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 18:28:12 +0100 Subject: [PATCH 287/662] Added links throughout std::net::ToSocketAddrs' documentation Part of #29363 In the section about the default implementations of ToSocketAddrs, I moved the bulletpoint of SocketAddrV4 & SocketAddrV6 to the one stating that SocketAddr is constructed trivially, as this is what's actually the case --- src/libstd/net/addr.rs | 52 ++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 84c4acb8d9247..ea78843aa8c0c 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -559,37 +559,51 @@ impl hash::Hash for SocketAddrV6 { } /// A trait for objects which can be converted or resolved to one or more -/// `SocketAddr` values. +/// [`SocketAddr`] values. /// /// This trait is used for generic address resolution when constructing network /// objects. By default it is implemented for the following types: /// -/// * `SocketAddr`, `SocketAddrV4`, `SocketAddrV6` - `to_socket_addrs` is -/// identity function. +/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// -/// * `(IpvNAddr, u16)` - `to_socket_addrs` constructs `SocketAddr` trivially. +/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, +/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: +/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(&str, u16)` - the string should be either a string representation of an -/// IP address expected by `FromStr` implementation for `IpvNAddr` or a host +/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation +/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. /// -/// * `&str` - the string should be either a string representation of a -/// `SocketAddr` as expected by its `FromStr` implementation or a string like -/// `:` pair where `` is a `u16` value. +/// * [`&str`]: the string should be either a string representation of a +/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like +/// `:` pair where `` is a [`u16`] value. /// -/// This trait allows constructing network objects like `TcpStream` or -/// `UdpSocket` easily with values of various types for the bind/connection +/// This trait allows constructing network objects like [`TcpStream`] or +/// [`UdpSocket`] easily with values of various types for the bind/connection /// address. It is needed because sometimes one type is more appropriate than /// the other: for simple uses a string like `"localhost:12345"` is much nicer -/// than manual construction of the corresponding `SocketAddr`, but sometimes -/// `SocketAddr` value is *the* main source of the address, and converting it to +/// than manual construction of the corresponding [`SocketAddr`], but sometimes +/// [`SocketAddr`] value is *the* main source of the address, and converting it to /// some other type (e.g. a string) just for it to be converted back to -/// `SocketAddr` in constructor methods is pointless. +/// [`SocketAddr`] in constructor methods is pointless. /// /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// -/// Some examples: +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// [`&str`]: ../../std/primitive.str.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// [`to_socket_addrs`]: #tymethod.to_socket_addrs +/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html +/// [`u16`]: ../../std/primitive.u16.html +/// +/// # Examples /// /// ```no_run /// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr}; @@ -622,7 +636,7 @@ pub trait ToSocketAddrs { #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved `SocketAddr`s. + /// Converts this object to an iterator of resolved [`SocketAddr`]s. /// /// The returned iterator may not actually yield any values depending on the /// outcome of any resolution performed. @@ -630,9 +644,13 @@ pub trait ToSocketAddrs { /// Note that this function may block the current thread while resolution is /// performed. /// + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// /// # Errors /// - /// Any errors encountered during resolution will be returned as an `Err`. + /// Any errors encountered during resolution will be returned as an [`Err`]. + /// + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[stable(feature = "rust1", since = "1.0.0")] fn to_socket_addrs(&self) -> io::Result; } From 0d5baba70d3adbb2a8ea436c6c89f21c1c6927b8 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 19:23:13 +0100 Subject: [PATCH 288/662] Added links to std::net::AddrParseError's documentation Additionally changed the summary sentence to be more consistent with most of the other FromStr implementations' error types. --- src/libstd/net/parser.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index d86711c10ac79..7d7c67ff3f9f7 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -368,7 +368,19 @@ impl FromStr for SocketAddr { } } -/// An error returned when parsing an IP address or a socket address. +/// An error which can be returned when parsing an IP address or a socket address. +/// +/// This error is used as the error type for the [`FromStr`] implementation for +/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and +/// [`SocketAddrV6`]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddrParseError(()); From 347b70901cdabcd78d2b0229c13c31b334b00617 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 14:25:31 +0200 Subject: [PATCH 289/662] Expanded and added links to std::net::{IpAddr,Ipv4Addr,Ipv6Addr} docs Part of #29363 Expanded top-level documentation & linked to relevant IETF RFCs. Added a bunch of links (to true/false/Ipv4Addr/etc.) throughout the docs. --- src/libstd/net/ip.rs | 202 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 160 insertions(+), 42 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 44dc689a30f4c..3e58a335470ae 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -21,44 +21,99 @@ use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; -/// An IP address, either an IPv4 or IPv6 address. +/// Either an IPv4 address or an IPv6 address. /// -/// # Examples +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. /// -/// Constructing an IPv4 address: +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html /// -/// ``` -/// use std::net::{IpAddr, Ipv4Addr}; +/// # Examples /// -/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); /// ``` +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// -/// Constructing an IPv6 address: +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// -/// ``` -/// use std::net::{IpAddr, Ipv6Addr}; +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); /// -/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] pub enum IpAddr { - /// Representation of an IPv4 address. + /// An IPv4 address. #[stable(feature = "ip_addr", since = "1.7.0")] V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), - /// Representation of an IPv6 address. + /// An IPv6 address. #[stable(feature = "ip_addr", since = "1.7.0")] V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), } -/// Representation of an IPv4 address. +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { inner: c::in_addr, } -/// Representation of an IPv6 address. +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { @@ -78,10 +133,14 @@ pub enum Ipv6MulticastScope { } impl IpAddr { - /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and + /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -99,10 +158,14 @@ impl IpAddr { } } - /// Returns true if this is a loopback address ([IPv4], [IPv6]). + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and + /// [`Ipv6Addr::is_loopback`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -120,10 +183,14 @@ impl IpAddr { } } - /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and + /// [`Ipv6Addr::is_global`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -145,10 +212,14 @@ impl IpAddr { } } - /// Returns true if this is a multicast address ([IPv4], [IPv6]). + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and + /// [`Ipv6Addr::is_multicast`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -166,10 +237,14 @@ impl IpAddr { } } - /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and + /// [`Ipv6Addr::is_documentation`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -191,7 +266,13 @@ impl IpAddr { } } - /// Returns true if this address is a valid IPv4 address, false if it's a valid IPv6 address. + /// Returns [`true`] if this address is an [IPv4 address] and [`false`] if it's an + /// [IPv6 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 + /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -212,7 +293,13 @@ impl IpAddr { } } - /// Returns true if this address is a valid IPv6 address, false if it's a valid IPv4 address. + /// Returns [`true`] if this address is an [IPv6 address] and [`false`] if it's an + /// [IPv4 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 + /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -274,12 +361,13 @@ impl Ipv4Addr { [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } - /// Returns true for the special 'unspecified' address (0.0.0.0). + /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). /// /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -294,11 +382,12 @@ impl Ipv4Addr { self.inner.s_addr == 0 } - /// Returns true if this is a loopback address (127.0.0.0/8). + /// Returns [`true`] if this is a loopback address (127.0.0.0/8). /// /// This property is defined by [IETF RFC 1122]. /// /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -313,7 +402,7 @@ impl Ipv4Addr { self.octets()[0] == 127 } - /// Returns true if this is a private address. + /// Returns [`true`] if this is a private address. /// /// The private address ranges are defined in [IETF RFC 1918] and include: /// @@ -322,6 +411,7 @@ impl Ipv4Addr { /// - 192.168.0.0/16 /// /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -346,11 +436,12 @@ impl Ipv4Addr { } } - /// Returns true if the address is link-local (169.254.0.0/16). + /// Returns [`true`] if the address is link-local (169.254.0.0/16). /// /// This property is defined by [IETF RFC 3927]. /// /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -366,7 +457,7 @@ impl Ipv4Addr { self.octets()[0] == 169 && self.octets()[1] == 254 } - /// Returns true if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally routable. /// See [iana-ipv4-special-registry][ipv4-sr]. /// /// The following return false: @@ -379,6 +470,7 @@ impl Ipv4Addr { /// - the unspecified address (0.0.0.0) /// /// [ipv4-sr]: http://goo.gl/RaZ7lg + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -400,12 +492,13 @@ impl Ipv4Addr { !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() } - /// Returns true if this is a multicast address (224.0.0.0/4). + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, /// and is defined by [IETF RFC 5771]. /// /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -421,11 +514,12 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Returns true if this is a broadcast address (255.255.255.255). + /// Returns [`true`] if this is a broadcast address (255.255.255.255). /// /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -441,7 +535,7 @@ impl Ipv4Addr { self.octets()[2] == 255 && self.octets()[3] == 255 } - /// Returns true if this address is in a range designated for documentation. + /// Returns [`true`] if this address is in a range designated for documentation. /// /// This is defined in [IETF RFC 5737]: /// @@ -450,6 +544,7 @@ impl Ipv4Addr { /// - 203.0.113.0/24 (TEST-NET-3) /// /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -471,10 +566,12 @@ impl Ipv4Addr { } } - /// Converts this address to an IPv4-compatible IPv6 address. + /// Converts this address to an IPv4-compatible [IPv6 address]. /// /// a.b.c.d becomes ::a.b.c.d /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// /// # Examples /// /// ``` @@ -490,10 +587,12 @@ impl Ipv4Addr { ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) } - /// Converts this address to an IPv4-mapped IPv6 address. + /// Converts this address to an IPv4-mapped [IPv6 address]. /// /// a.b.c.d becomes ::ffff:a.b.c.d /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// /// # Examples /// /// ``` @@ -717,11 +816,12 @@ impl Ipv6Addr { ] } - /// Returns true for the special 'unspecified' address (::). + /// Returns [`true`] for the special 'unspecified' address (::). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -736,11 +836,12 @@ impl Ipv6Addr { self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] } - /// Returns true if this is a loopback address (::1). + /// Returns [`true`] if this is a loopback address (::1). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -755,14 +856,17 @@ impl Ipv6Addr { self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] } - /// Returns true if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally routable. /// - /// The following return false: + /// The following return [`false`]: /// /// - the loopback address /// - link-local, site-local, and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -784,11 +888,12 @@ impl Ipv6Addr { } } - /// Returns true if this is a unique local address (fc00::/7). + /// Returns [`true`] if this is a unique local address (fc00::/7). /// /// This property is defined in [IETF RFC 4193]. /// /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -807,11 +912,12 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns true if the address is unicast and link-local (fe80::/10). + /// Returns [`true`] if the address is unicast and link-local (fe80::/10). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -830,9 +936,11 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfe80 } - /// Returns true if this is a deprecated unicast site-local address + /// Returns [`true`] if this is a deprecated unicast site-local address /// (fec0::/10). /// + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -850,12 +958,13 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfec0 } - /// Returns true if this is an address reserved for documentation + /// Returns [`true`] if this is an address reserved for documentation /// (2001:db8::/32). /// /// This property is defined in [IETF RFC 3849]. /// /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -874,7 +983,7 @@ impl Ipv6Addr { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } - /// Returns true if the address is a globally routable unicast address. + /// Returns [`true`] if the address is a globally routable unicast address. /// /// The following return false: /// @@ -885,6 +994,8 @@ impl Ipv6Addr { /// - the unspecified address /// - the address range reserved for documentation /// + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -937,11 +1048,13 @@ impl Ipv6Addr { } } - /// Returns true if this is a multicast address (ff00::/8). + /// Returns [`true`] if this is a multicast address (ff00::/8). /// /// This property is defined by [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -955,11 +1068,16 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } - /// Converts this address to an IPv4 address. Returns None if this address is + /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is /// neither IPv4-compatible or IPv4-mapped. /// /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// /// ``` /// use std::net::{Ipv4Addr, Ipv6Addr}; /// From be713fa4bf12cf87a799dddfd29ab095a548fd01 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 01:01:32 +0100 Subject: [PATCH 290/662] Removed link in std::net::ToSocketAddr's summary sentence Relative links in trait methods don't resolve in e.g. std/primitive.tuple.html :( --- src/libstd/net/addr.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ea78843aa8c0c..0b63a5a5c1431 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -636,7 +636,7 @@ pub trait ToSocketAddrs { #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved [`SocketAddr`]s. + /// Converts this object to an iterator of resolved `SocketAddr`s. /// /// The returned iterator may not actually yield any values depending on the /// outcome of any resolution performed. @@ -644,8 +644,6 @@ pub trait ToSocketAddrs { /// Note that this function may block the current thread while resolution is /// performed. /// - /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html - /// /// # Errors /// /// Any errors encountered during resolution will be returned as an [`Err`]. From 6f0c742b001e7861099e1048c4f0cd08f0528774 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 14:13:37 +0200 Subject: [PATCH 291/662] Expanded and added links to std::net::{SocketAddr,SocketAddrV4,SocketAddrV6} docs Part of #29363 Changed summary sentences of SocketAddr and IpAddr for consistency Linked to SocketAddrV4 and SocketAddrV6 from SocketAddr, moving explaination there Expanded top-level docs for SocketAddrV4 and SocketAddrV6, linking to some relevant IETF RFCs, and linking back to SocketAddr Changed some of the method summaries to third person as per RFC 1574; added links to IETF RFCs where appropriate --- src/libstd/net/addr.rs | 114 ++++++++++++++++++++++++++++++++--------- src/libstd/net/ip.rs | 2 +- 2 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 0b63a5a5c1431..6584531a92a2a 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -20,15 +20,17 @@ use vec; use iter; use slice; -/// Representation of a socket address for networking applications. +/// An internet socket address, either IPv4 or IPv6. /// -/// A socket address can either represent the IPv4 or IPv6 protocol and is -/// paired with at least a port number as well. Each protocol may have more -/// specific information about the address available to it as well. +/// This enum can contain either an [`SocketAddrV4`] or an [`SocketAddrV6`]. see their +/// respective documentation for more details. +/// +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SocketAddr { - /// An IPv4 socket address which is a (ip, port) combination. + /// An IPv4 socket address. #[stable(feature = "rust1", since = "1.0.0")] V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), /// An IPv6 socket address. @@ -36,18 +38,39 @@ pub enum SocketAddr { V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6), } -/// An IPv4 socket address which is a (ip, port) combination. +/// An IPv4 socket address. +/// +/// IPv4 socket addresses consist of an [IPv4 address] and a 16-bit port number, as +/// stated in [IETF RFC 793]. +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV4 { inner: c::sockaddr_in } /// An IPv6 socket address. +/// +/// IPv6 socket addresses consist of an [Ipv6 address], a 16-bit port number, as well +/// as fields containing the traffic class, the flow label, and a scope identifier +/// (see [IETF RFC 2553, Section 3.3] for more details). +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 +/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV6 { inner: c::sockaddr_in6 } impl SocketAddr { - /// Creates a new socket address from the (ip, port) pair. + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: ../../std/net/enum.IpAddr.html /// /// # Examples /// @@ -84,7 +107,7 @@ impl SocketAddr { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -123,7 +146,7 @@ impl SocketAddr { } } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -142,8 +165,14 @@ impl SocketAddr { } } - /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address, - /// false if it's a valid IPv6 address. + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv4 address] and [`false`] if it's an [IPv6 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 + /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -164,8 +193,14 @@ impl SocketAddr { } } - /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address, - /// false if it's a valid IPv4 address. + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv6 address] and [`false`] if it's an [IPv4 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 + /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -189,7 +224,9 @@ impl SocketAddr { } impl SocketAddrV4 { - /// Creates a new socket address from the (ip, port) pair. + /// Creates a new socket address from an [IPv4 address] and a port number. + /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// /// # Examples /// @@ -227,7 +264,7 @@ impl SocketAddrV4 { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -258,7 +295,7 @@ impl SocketAddrV4 { ntoh(self.inner.sin_port) } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -276,8 +313,14 @@ impl SocketAddrV4 { } impl SocketAddrV6 { - /// Creates a new socket address from the ip/port/flowinfo/scope_id - /// components. + /// Creates a new socket address from an [IPv6 address], a 16-bit port number, + /// and the `flowinfo` and `scope_id` fields. + /// + /// For more information on the meaning and layout of the `flowinfo` and `scope_id` + /// parameters, see [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// /// # Examples /// @@ -318,7 +361,7 @@ impl SocketAddrV6 { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -349,7 +392,7 @@ impl SocketAddrV6 { ntoh(self.inner.sin6_port) } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -365,8 +408,17 @@ impl SocketAddrV6 { self.inner.sin6_port = hton(new_port); } - /// Returns the flow information associated with this address, - /// corresponding to the `sin6_flowinfo` field in C. + /// Returns the flow information associated with this address. + /// + /// This information corresponds to the `sin6_flowinfo` field in C, as specified in + /// [IETF RFC 2553, Section 3.3]. It combines information about the flow label and + /// the traffic class as specified in [IETF RFC 2460], respectively [Section 6] and + /// [Section 7]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 + /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 + /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 /// /// # Examples /// @@ -381,7 +433,11 @@ impl SocketAddrV6 { self.inner.sin6_flowinfo } - /// Change the flow information associated with this socket address. + /// Changes the flow information associated with this socket address. + /// + /// See the [`flowinfo`] method's documentation for more details. + /// + /// [`flowinfo`]: #method.flowinfo /// /// # Examples /// @@ -397,8 +453,12 @@ impl SocketAddrV6 { self.inner.sin6_flowinfo = new_flowinfo; } - /// Returns the scope ID associated with this address, - /// corresponding to the `sin6_scope_id` field in C. + /// Returns the scope ID associated with this address. + /// + /// This information corresponds to the `sin6_scope_id` field in C, as specified in + /// [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// /// # Examples /// @@ -415,6 +475,10 @@ impl SocketAddrV6 { /// Change the scope ID associated with this socket address. /// + /// See the [`scope_id`] method's documentation for more details. + /// + /// [`scope_id`]: #method.scope_id + /// /// # Examples /// /// ``` diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 3e58a335470ae..85803ff0501d4 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -21,7 +21,7 @@ use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; -/// Either an IPv4 address or an IPv6 address. +/// An IP address, either IPv4 or IPv6. /// /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// respective documentation for more details. From 1a9c8baed55547593610eb935c9cceccec40fdb4 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 15:43:25 +0200 Subject: [PATCH 292/662] Added examples to std::net::{SocketAddr, SocketAddrV4, SocketAddrV6} docs --- src/libstd/net/addr.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 6584531a92a2a..ccfd2a1dfb153 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -27,6 +27,18 @@ use slice; /// /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +/// +/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.port(), 8080); +/// assert_eq!(socket.is_ipv4(), true); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SocketAddr { @@ -48,6 +60,18 @@ pub enum SocketAddr { /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, SocketAddrV4}; +/// +/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV4 { inner: c::sockaddr_in } @@ -63,6 +87,18 @@ pub struct SocketAddrV4 { inner: c::sockaddr_in } /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv6Addr, SocketAddrV6}; +/// +/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); +/// +/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV6 { inner: c::sockaddr_in6 } From ad816f81748e6314b428a91352b0eb536f7fffc5 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 16:12:27 +0200 Subject: [PATCH 293/662] Added links to std::net::Shutdown docs and made them more consistent Part of #29363 --- src/libstd/net/mod.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index b0d2e3e4687b4..e4593cf381772 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -43,17 +43,30 @@ mod test; #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Shutdown { - /// Indicates that the reading portion of this stream/socket should be shut - /// down. All currently blocked and future reads will return `Ok(0)`. + /// The reading portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [reads] will return [`Ok(0)`]. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [reads]: ../../std/io/trait.Read.html + /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok #[stable(feature = "rust1", since = "1.0.0")] Read, - /// Indicates that the writing portion of this stream/socket should be shut - /// down. All currently blocked and future writes will return an error. + /// The writing portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [writes] will return an error. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [writes]: ../../std/io/trait.Write.html #[stable(feature = "rust1", since = "1.0.0")] Write, - /// Shut down both the reading and writing portions of this stream. + /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. + /// + /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information. /// - /// See `Shutdown::Read` and `Shutdown::Write` for more information. + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [`Shutdown::Read`]: #variant.Read + /// [`Shutdown::Write`]: #variant.Write #[stable(feature = "rust1", since = "1.0.0")] Both, } From 597bcec379bec40641eb6a4637ebbec69e184582 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 17:06:39 +0200 Subject: [PATCH 294/662] Expanded top-level docs for std::net{TcpListener,TcpStream,UdpSocket} Part of #29363 --- src/libstd/net/tcp.rs | 37 +++++++++++++++++++++++++++++++++---- src/libstd/net/udp.rs | 30 +++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index c6cf748d981c7..cf119720e5a17 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -17,10 +17,25 @@ use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; -/// A structure which represents a TCP stream between a local socket and a -/// remote socket. +/// A TCP stream between a local and a remote socket. /// -/// The socket will be closed when the value is dropped. +/// After creating a `TcpStream` by either [`connect`]ing to a remote host or +/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted +/// by [reading] and [writing] to it. +/// +/// The connection will be closed when the value is dropped. The reading and writing +/// portions of the connection can also be shut down individually with the [`shutdown`] +/// method. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`connect`]: #method.connect +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [reading]: ../../std/io/trait.Read.html +/// [`shutdown`]: #method.shutdown +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [writing]: ../../std/io/trait.Write.html /// /// # Examples /// @@ -39,7 +54,21 @@ use time::Duration; #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpStream(net_imp::TcpStream); -/// A structure representing a socket server. +/// A TCP socket server, listening for connections. +/// +/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens +/// for incoming TCP connections. These can be accepted by calling [`accept`] or by +/// iterating over the [`Incoming`] iterator returned by [`incoming`]. +/// +/// The socket will be closed when the value is dropped. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: #method.accept +/// [`bind`]: #method.bind +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`Incoming`]: ../../std/net/struct.Incoming.html +/// [`incoming`]: #method.incoming /// /// # Examples /// diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 1ebce93934840..cdf04f7f1a484 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -15,11 +15,29 @@ use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; -/// A User Datagram Protocol socket. +/// A UDP socket. /// -/// This is an implementation of a bound UDP socket. This supports both IPv4 and -/// IPv6 addresses, and there is no corresponding notion of a server because UDP -/// is a datagram protocol. +/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be +/// [sent to] and [received from] any other socket address. +/// +/// Although UDP is a connectionless protocol, this implementation provides an interface +/// to set an address where data should be sent and received from. After setting a remote +/// address with [`connect`], data can be sent to and received from that address with +/// [`send`] and [`recv`]. +/// +/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is +/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP +/// primitives. +/// +/// [`bind`]: #method.bind +/// [`connect`]: #method.connect +/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768 +/// [`recv`]: #method.recv +/// [received from]: #method.recv_from +/// [`send`]: #method.send +/// [sent to]: #method.send_to +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples /// @@ -582,9 +600,11 @@ impl UdpSocket { /// Receives data on the socket from the remote address to which it is /// connected. /// - /// The `connect` method will connect this socket to a remote address. This + /// The [`connect`] method will connect this socket to a remote address. This /// method will fail if the socket is not connected. /// + /// [`connect`]: #method.connect + /// /// # Examples /// /// ```no_run From 577677d55d7ca793b3845577939d99a97e112691 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 17:27:40 +0200 Subject: [PATCH 295/662] Expanded std::net module docs Part of #29363 --- src/libstd/net/mod.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index e4593cf381772..3b4808fee2515 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -9,6 +9,32 @@ // except according to those terms. //! Networking primitives for TCP/UDP communication. +//! +//! This module provides networking functionality for the Transmission Control and User +//! Datagram Protocols, as well as types for IP and socket addresses. +//! +//! # Organization +//! +//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP +//! * [`UdpSocket`] provides functionality for communication over UDP +//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and +//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses +//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] +//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses +//! * [`ToSocketAddr`] is a trait that used for generic address resolution interacting +//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] +//! * Other types are return or parameter types for various methods in this module +//! +//! [`IpAddr`]: ../../std/net/enum.IpAddr.html +//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +//! [`TcpListener`]: ../../std/net/struct.TcpListener.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`ToSocketAddr`]: ../../std/net/trait.ToSocketAddr.html +//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html #![stable(feature = "rust1", since = "1.0.0")] From c2601fd358769cbecae479e8d32521f6e5d5c633 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 18:06:22 +0200 Subject: [PATCH 296/662] fix trailing whitespace --- src/libstd/net/ip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 85803ff0501d4..2a1f959b35d03 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -99,7 +99,7 @@ pub struct Ipv4Addr { /// # Textual representation /// /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent -/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// an IPv6 address in text, but in general, each segments is written in hexadecimal /// notation, and segments are separated by `:`. For more information, see /// [IETF RFC 5952]. /// From 2cf686f2cdd6446a3cd47df0305ead40fabe85df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sun, 26 Mar 2017 18:54:08 +0200 Subject: [PATCH 297/662] Implement AsRawFd/IntoRawFd for RawFd This is useful to build os abstraction like the nix crate does. It allows to define functions, which accepts generic arguments of data structures convertible to RawFd, including RawFd itself. For example: fn write(fd: FD, buf: &[u8]) -> Result instead of: fn write(fd: RawFd, buf: &[u8]) -> Result write(foo.as_raw_fd(), buf); --- src/libstd/sys/unix/ext/io.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 296235e173d13..75aa72e3cff8c 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -72,6 +72,13 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -84,6 +91,14 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} + #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { fn into_raw_fd(self) -> RawFd { From fda8e1571f7a0c4da77c57bc7a7728c4ed1e6aea Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Sun, 26 Mar 2017 01:01:54 +0300 Subject: [PATCH 298/662] libcore: sort_unstable: improve randomization in break_patterns. Select 3 random points instead of just 1. Also the code now compiles on 16bit architectures. --- src/libcore/slice/sort.rs | 56 ++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 307e4974d9769..3612ee65bca0d 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -498,32 +498,40 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize #[cold] fn break_patterns(v: &mut [T]) { let len = v.len(); - if len >= 8 { - // A random number will be taken modulo this one. The modulus is a power of two so that we - // can simply take bitwise "and", thus avoiding costly CPU operations. - let modulus = (len / 4).next_power_of_two(); - debug_assert!(modulus >= 1 && modulus <= len / 2); - - // Pseudorandom number generation from the "Xorshift RNGs" paper by George Marsaglia. - let mut random = len; - random ^= random << 13; - random ^= random >> 17; - random ^= random << 5; - random &= modulus - 1; - debug_assert!(random < len / 2); - - // The first index. - let a = len / 4 * 2; - debug_assert!(a >= 1 && a < len - 2); - - // The second index. - let b = len / 4 + random; - debug_assert!(b >= 1 && b < len - 2); - - // Swap neighbourhoods of `a` and `b`. + // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. + let mut random = len as u32; + let mut gen_u32 = || { + random ^= random << 13; + random ^= random >> 17; + random ^= random << 5; + random + }; + let mut gen_usize = || { + if mem::size_of::() <= 4 { + gen_u32() as usize + } else { + (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize + } + }; + + // Take random numbers modulo this number. + // The number fits into `usize` because `len` is not greater than `isize::MAX`. + let modulus = len.next_power_of_two(); + + // Some pivot candidates will be in the nearby of this index. Let's randomize them. + let pos = len / 4 * 2; + for i in 0..3 { - v.swap(a - 1 + i, b - 1 + i); + // Generate a random number modulo `len`. However, in order to avoid costly operations + // we first take it modulo a power of two, and then decrease by `len` until it fits + // into the range `[0, len - 1]`. + let mut other = gen_usize() & (modulus - 1); + while other >= len { + other -= len; + } + + v.swap(pos - 1 + i, other); } } } From 1579fbd8ca8452d462f76e47a5367c1d51fb8d43 Mon Sep 17 00:00:00 2001 From: Alan Stoate Date: Mon, 27 Mar 2017 07:46:43 +1030 Subject: [PATCH 299/662] Fixed spelling mistakes --- src/libstd/ascii.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index ba2b059f8284b..1cac11f668d95 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -63,7 +63,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; - /// Makes a copy of the value in it's ASCII upper case equivalent. + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. @@ -92,7 +92,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_uppercase(&self) -> Self::Owned; - /// Makes a copy of the value in it's ASCII lower case equivalent. + /// Makes a copy of the value in its ASCII lower case equivalent. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. From 50728e52455804143e5cc601004381e395a1e2f7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 26 Mar 2017 19:35:46 +0300 Subject: [PATCH 300/662] borrowck: consolidate `mut` suggestions This converts all of borrowck's `mut` suggestions to a new `mc::ImmutabilityBlame` API instead of the current mix of various hacks. Fixes #35937. Fixes #40823. --- src/librustc/middle/mem_categorization.rs | 140 +++++------- .../borrowck/gather_loans/mod.rs | 9 - src/librustc_borrowck/borrowck/mod.rs | 208 ++++++++++-------- src/librustc_borrowck/diagnostics.rs | 6 +- .../compile-fail/augmented-assignments.rs | 2 +- .../borrowck/borrowck-issue-14498.rs | 6 +- src/test/compile-fail/issue-33819.rs | 2 +- src/test/compile-fail/mut-suggestion.rs | 4 +- .../huge_multispan_highlight.stderr | 2 +- src/test/ui/did_you_mean/issue-31424.stderr | 2 + src/test/ui/did_you_mean/issue-35937.rs | 31 +++ src/test/ui/did_you_mean/issue-35937.stderr | 26 +++ src/test/ui/did_you_mean/issue-38147-2.stderr | 2 +- src/test/ui/did_you_mean/issue-38147-3.stderr | 4 +- src/test/ui/did_you_mean/issue-39544.rs | 11 +- src/test/ui/did_you_mean/issue-39544.stderr | 19 +- src/test/ui/did_you_mean/issue-40823.rs | 14 ++ src/test/ui/did_you_mean/issue-40823.stderr | 8 + ...ck-borrow-overloaded-auto-deref-mut.stderr | 8 +- ...orrowck-borrow-overloaded-deref-mut.stderr | 4 +- .../ui/span/borrowck-object-mutability.stderr | 3 + 21 files changed, 304 insertions(+), 207 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-35937.rs create mode 100644 src/test/ui/did_you_mean/issue-35937.stderr create mode 100644 src/test/ui/did_you_mean/issue-40823.rs create mode 100644 src/test/ui/did_you_mean/issue-40823.stderr diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0cf53826dd427..3b52e85e08e32 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -194,76 +194,75 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; +pub enum ImmutabilityBlame<'tcx> { + ImmLocal(ast::NodeId), + ClosureEnv(ast::NodeId), + LocalDeref(ast::NodeId), + AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef) +} + impl<'tcx> cmt_<'tcx> { - pub fn get_def(&self) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - Some(nid) - } else { - None - } + fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + { + let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { + bug!("interior cmt {:?} is not an ADT", self) + }); + let variant_def = match self.cat { + Categorization::Downcast(_, variant_did) => { + adt_def.variant_with_id(variant_did) } - _ => None - } + _ => { + assert!(adt_def.is_univariant()); + &adt_def.variants[0] + } + }; + let field_def = match field_name { + NamedField(name) => variant_def.field_named(name), + PositionalField(idx) => &variant_def.fields[idx] + }; + (adt_def, field_def) } - pub fn get_field(&self, name: ast::Name) -> Option { + pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(_) = cmt.cat { - if let ty::TyAdt(def, _) = self.ty.sty { - if def.is_struct() { - return def.struct_variant().find_field_named(name).map(|x| x.did); + Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => { + // try to figure out where the immutable reference came from + match base_cmt.cat { + Categorization::Local(node_id) => + Some(ImmutabilityBlame::LocalDeref(node_id)), + Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { + let (adt_def, field_def) = base_cmt.resolve_field(field_name); + Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + } + Categorization::Upvar(Upvar { id, .. }) => { + if let NoteClosureEnv(..) = self.note { + Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id)) + } else { + None } } - None - } else { - cmt.get_field(name) + _ => None } } - _ => None - } - } - - pub fn get_field_name(&self) -> Option { - match self.cat { - Categorization::Interior(_, ref ik) => { - if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik { - Some(name) - } else { - None - } + Categorization::Local(node_id) => { + Some(ImmutabilityBlame::ImmLocal(node_id)) } - Categorization::Deref(ref cmt, ..) | - Categorization::Downcast(ref cmt, _) => { - cmt.get_field_name() + Categorization::Rvalue(..) | + Categorization::Upvar(..) | + Categorization::Deref(.., UnsafePtr(..)) => { + // This should not be reachable up to inference limitations. + None } - _ => None, - } - } - - pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - if let ty::TyAdt(_, _) = self.ty.sty { - if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty { - return Some(nid); - } - } - None - } else { - cmt.get_arg_if_immutable(map) - } + Categorization::Interior(ref base_cmt, _) | + Categorization::Downcast(ref base_cmt, _) | + Categorization::Deref(ref base_cmt, _, _) => { + base_cmt.immutability_blame() + } + Categorization::StaticItem => { + // Do we want to do something here? + None } - _ => None } } } @@ -1282,9 +1281,6 @@ pub enum Aliasability { #[derive(Copy, Clone, Debug)] pub enum AliasableReason { AliasableBorrowed, - AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env - AliasableOther, - UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique AliasableStatic, AliasableStaticMut, } @@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> { Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, _, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { // Aliasability depends on base cmt b.freely_aliasable() } - Categorization::Deref(ref b, _, Unique) => { - let sub = b.freely_aliasable(); - if b.mutbl.is_mutable() { - // Aliasability depends on base cmt alone - sub - } else { - // Do not allow mutation through an immutable box. - ImmutableUnique(Box::new(sub)) - } - } - Categorization::Rvalue(..) | Categorization::Local(..) | Categorization::Upvar(..) | @@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => { - match base.cat { - Categorization::Upvar(Upvar{ id, .. }) => - FreelyAliasable(AliasableClosure(id.closure_expr_id)), - _ => FreelyAliasable(AliasableBorrowed) - } + Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => { + FreelyAliasable(AliasableBorrowed) } } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 28b6c7a13f171..cedb9e1cd1cff 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, // user knows what they're doing in these cases. Ok(()) } - (mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => { - bccx.report_aliasability_violation( - borrow_span, - loan_cause, - mc::AliasableReason::UnaliasableImmutable, - cmt); - Err(()) - } (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => { bccx.report_aliasability_violation( @@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { self.move_error_collector.report_potential_errors(self.bccx); } } - diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b05f..0981369ace5c1 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,6 +34,7 @@ use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; +use rustc::middle::mem_categorization::ImmutabilityBlame; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; @@ -41,6 +42,7 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; +use syntax::symbol::keywords; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; @@ -659,12 +661,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { + fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { let span = err.span.clone(); - let mut immutable_field = None; - let mut local_def = None; - let msg = &match err.code { + let msg = match err.code { err_mutbl => { let descr = match err.cmt.note { mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => { @@ -700,27 +700,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { - // Check for this field's definition to see if it is an immutable reference - // and suggest making it mutable if that is the case. - immutable_field = err.cmt.get_field_name() - .and_then(|name| err.cmt.get_field(name)) - .and_then(|did| self.tcx.hir.as_local_node_id(did)) - .and_then(|nid| { - if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) { - return self.suggest_mut_for_immutable(&field.ty) - .map(|msg| (self.tcx.hir.span(nid), msg)); - } - None - }); - local_def = err.cmt.get_def() - .and_then(|nid| { - if !self.tcx.hir.is_argument(nid) { - Some(self.tcx.hir.span(nid)) - } else { - None - } - }); - format!("cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { @@ -746,16 +725,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut db = self.struct_span_err(span, msg); - if let Some((span, msg)) = immutable_field { - db.span_label(span, &msg); - } - if let Some(let_span) = local_def { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet)); - } - } - db + self.struct_span_err(span, &msg) } pub fn report_aliasability_violation(&self, @@ -788,55 +758,49 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut err = match cause { - mc::AliasableOther => { - struct_span_err!( - self.tcx.sess, span, E0385, - "{} in an aliasable location", prefix) - } - mc::AliasableReason::UnaliasableImmutable => { - struct_span_err!( - self.tcx.sess, span, E0386, - "{} in an immutable container", prefix) + match cause { + mc::AliasableStatic | + mc::AliasableStaticMut => { + // This path cannot occur. It happens when we have an + // `&mut` or assignment to a static. But in the case + // of `static X`, we get a mutability violation first, + // and never get here. In the case of `static mut X`, + // that is unsafe and hence the aliasability error is + // ignored. + span_bug!(span, "aliasability violation for static `{}`", prefix) } - mc::AliasableClosure(id) => { + mc::AliasableBorrowed => {} + }; + let blame = cmt.immutability_blame(); + let mut err = match blame { + Some(ImmutabilityBlame::ClosureEnv(id)) => { let mut err = struct_span_err!( self.tcx.sess, span, E0387, "{} in a captured outer variable in an `Fn` closure", prefix); - if let BorrowViolation(euv::ClosureCapture(_)) = kind { + + // FIXME: the distinction between these 2 messages looks wrong. + let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind { // The aliasability violation with closure captures can // happen for nested closures, so we know the enclosing // closure incorrectly accepts an `Fn` while it needs to // be `FnMut`. - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this to accept closures that implement `FnMut`"); + "consider changing this to accept closures that implement `FnMut`" + } else { - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this closure to take self by mutable reference"); - } + "consider changing this closure to take self by mutable reference" + }; + err.span_help(self.tcx.hir.span(id), help); err } - mc::AliasableStatic | - mc::AliasableStaticMut => { - // This path cannot occur. It happens when we have an - // `&mut` or assignment to a static. But in the case - // of `static X`, we get a mutability violation first, - // and never get here. In the case of `static mut X`, - // that is unsafe and hence the aliasability error is - // ignored. - span_bug!(span, "aliasability violation for static `{}`", prefix) - } - mc::AliasableBorrowed => { - let mut e = struct_span_err!( + _ => { + let mut err = struct_span_err!( self.tcx.sess, span, E0389, "{} in a `&` reference", prefix); - e.span_label(span, &"assignment into an immutable reference"); - if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(nid, &mut e); - } - e + err.span_label(span, &"assignment into an immutable reference"); + err } }; + self.note_immutability_blame(&mut err, blame); if is_closure { err.help("closures behind references must be called via `&mut`"); @@ -873,8 +837,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { None } - fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) { - let parent = self.tcx.hir.get_parent_node(nid); + fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { + let pat = match self.tcx.hir.get(node_id) { + hir_map::Node::NodeLocal(pat) => pat, + node => bug!("bad node for local: {:?}", node) + }; + + match pat.node { + hir::PatKind::Binding(mode, ..) => mode, + _ => bug!("local is not a binding: {:?}", pat) + } + } + + fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> { + let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); // The parent node is like a fn @@ -882,12 +858,72 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); // Get the position of `nid` in the arguments list - let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid); + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - let arg_ty = &fn_like.decl().inputs[i]; - if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) { - db.span_label(arg_ty.span, &msg); + Some(&fn_like.decl().inputs[i]) + } else { + None + } + } else { + None + } + } + + fn note_immutability_blame(&self, + db: &mut DiagnosticBuilder, + blame: Option) { + match blame { + None => {} + Some(ImmutabilityBlame::ClosureEnv(_)) => {} + Some(ImmutabilityBlame::ImmLocal(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + if self.tcx.hir.name(node_id) == keywords::SelfValue.name() && + snippet != "self" { + // avoid suggesting `mut &self`. + return + } + db.span_label( + let_span, + &format!("consider changing this to `mut {}`", snippet) + ); + } + } + } + Some(ImmutabilityBlame::LocalDeref(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + match self.local_binding_mode(node_id) { + hir::BindingMode::BindByRef(..) => { + let snippet = self.tcx.sess.codemap().span_to_snippet(let_span); + if let Ok(snippet) = snippet { + db.span_label( + let_span, + &format!("consider changing this to `{}`", + snippet.replace("ref ", "ref mut ")) + ); + } + } + hir::BindingMode::BindByValue(..) => { + if let Some(local_ty) = self.local_ty(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(local_ty) { + db.span_label(local_ty.span, &msg); + } + } + } + } + } + Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => { + let node_id = match self.tcx.hir.as_local_node_id(field.did) { + Some(node_id) => node_id, + None => return + }; + + if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) { + db.span_label(field.ty.span, &msg); + } } } } @@ -941,10 +977,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { + fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { let error_span = err.span.clone(); match err.code { - err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), + err_mutbl => { + self.note_and_explain_mutbl_error(db, &err, &error_span); + self.note_immutability_blame(db, err.cmt.immutability_blame()); + } err_out_of_scope(super_scope, sub_scope, cause) => { let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(..) => @@ -1096,13 +1135,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ _ => { if let Categorization::Deref(..) = err.cmt.cat { db.span_label(*error_span, &"cannot borrow as mutable"); - if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(local_id, db); - } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { - if let Categorization::Local(local_id) = inner_cmt.cat { - self.immutable_argument_should_be_mut(local_id, db); - } - } } else if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.hir.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { @@ -1110,14 +1142,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ db.span_label(*error_span, &format!("cannot reborrow mutably")); db.span_label(*error_span, &format!("try removing `&mut` here")); } else { - if snippet.starts_with("ref ") { - db.span_label(span, &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", - snippet)); - } db.span_label(*error_span, &format!("cannot borrow mutably")); } } else { diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index db4a1701e976b..bfd342a9f2134 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -198,7 +198,7 @@ fn main() { ``` "##, -E0386: r##" +/*E0386: r##" This error occurs when an attempt is made to mutate the target of a mutable reference stored inside an immutable container. @@ -228,7 +228,7 @@ let x: i64 = 1; let y: Box> = Box::new(Cell::new(x)); y.set(2); ``` -"##, +"##,*/ E0387: r##" This error occurs when an attempt is made to mutate or mutably reference data @@ -1117,6 +1117,6 @@ fn main() { } register_diagnostics! { - E0385, // {} in an aliasable location +// E0385, // {} in an aliasable location E0524, // two closures require unique access to `..` at the same time } diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs index 92a8b10669cee..736aa465aa732 100644 --- a/src/test/compile-fail/augmented-assignments.rs +++ b/src/test/compile-fail/augmented-assignments.rs @@ -27,7 +27,7 @@ fn main() { x; //~ value moved here let y = Int(2); - //~^use `mut y` here to make mutable + //~^ consider changing this to `mut y` y //~ error: cannot borrow immutable local variable `y` as mutable //~| cannot borrow += diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs index 64033623fe2d1..8b7ccedd6974f 100644 --- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs +++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs @@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() { let mut x: isize = 1; let y: Box<_> = box &mut x; let p = &y; - ***p = 2; //~ ERROR cannot assign to data in an immutable container + ***p = 2; //~ ERROR cannot assign to data in a `&` reference drop(p); } @@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() { let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() { let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() { let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() { let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs index 9c9677c1e9863..499e7e54947b7 100644 --- a/src/test/compile-fail/issue-33819.rs +++ b/src/test/compile-fail/issue-33819.rs @@ -12,7 +12,7 @@ fn main() { match op { Some(ref v) => { let a = &mut v; }, //~^ ERROR:cannot borrow immutable - //~| use `ref mut v` here to make mutable + //~| cannot borrow mutably None => {}, } } diff --git a/src/test/compile-fail/mut-suggestion.rs b/src/test/compile-fail/mut-suggestion.rs index 242ad7aee8d12..0015c8e5c00a1 100644 --- a/src/test/compile-fail/mut-suggestion.rs +++ b/src/test/compile-fail/mut-suggestion.rs @@ -17,7 +17,7 @@ impl S { } fn func(arg: S) { - //~^ here to make mutable + //~^ consider changing this to `mut arg` arg.mutate(); //~^ ERROR cannot borrow immutable argument //~| cannot borrow mutably @@ -25,7 +25,7 @@ fn func(arg: S) { fn main() { let local = S; - //~^ here to make mutable + //~^ consider changing this to `mut local` local.mutate(); //~^ ERROR cannot borrow immutable local variable //~| cannot borrow mutably diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr index edbfd72df615f..7bb69caa1024a 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable --> $DIR/huge_multispan_highlight.rs:100:18 | 12 | let x = "foo"; - | - use `mut x` here to make mutable + | - consider changing this to `mut x` ... 100 | let y = &mut x; | ^ cannot borrow mutably diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr index 4873acf551ebc..60fa06d314ff7 100644 --- a/src/test/ui/did_you_mean/issue-31424.stderr +++ b/src/test/ui/did_you_mean/issue-31424.stderr @@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable error: cannot borrow immutable argument `self` as mutable --> $DIR/issue-31424.rs:23:15 | +22 | fn bar(self: &mut Self) { + | ---- consider changing this to `mut self` 23 | (&mut self).bar(); | ^^^^ cannot borrow mutably diff --git a/src/test/ui/did_you_mean/issue-35937.rs b/src/test/ui/did_you_mean/issue-35937.rs new file mode 100644 index 0000000000000..9ec8728fd32c1 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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 Foo { + pub v: Vec +} + +fn main() { + let f = Foo { v: Vec::new() }; + f.v.push("cat".to_string()); +} + + +struct S { + x: i32, +} +fn foo() { + let s = S { x: 42 }; + s.x += 1; +} + +fn bar(s: S) { + s.x += 1; +} diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr new file mode 100644 index 0000000000000..bea3d1291433d --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.stderr @@ -0,0 +1,26 @@ +error: cannot borrow immutable field `f.v` as mutable + --> $DIR/issue-35937.rs:17:5 + | +16 | let f = Foo { v: Vec::new() }; + | - consider changing this to `mut f` +17 | f.v.push("cat".to_string()); + | ^^^ cannot mutably borrow immutable field + +error: cannot assign to immutable field `s.x` + --> $DIR/issue-35937.rs:26:5 + | +25 | let s = S { x: 42 }; + | - consider changing this to `mut s` +26 | s.x += 1; + | ^^^^^^^^ cannot mutably borrow immutable field + +error: cannot assign to immutable field `s.x` + --> $DIR/issue-35937.rs:30:5 + | +29 | fn bar(s: S) { + | - consider changing this to `mut s` +30 | s.x += 1; + | ^^^^^^^^ cannot mutably borrow immutable field + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr index fdaf0cd44d9d4..855feaf7d2d5e 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-2.rs:17:9 | 12 | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- use `&'a mut String` here to make mutable ... 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr index d2280fa561bde..d970d078df8d9 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-3.rs:17:9 | 12 | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- use `&'a mut String` here to make mutable ... -16 | fn f(&self) { - | ----- use `&mut self` here to make mutable 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index bcdafefa2472b..c98fed3c3c3c7 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -8,15 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum X { +pub enum X { Y } -struct Z { +pub struct Z { x: X } -fn main() { +pub fn main() { let z = Z { x: X::Y }; let _ = &mut z.x; } + +pub fn with_arg(z: Z, w: &Z) { + let _ = &mut z.x; + let _ = &mut w.x; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index 7f124e6d34d35..bcd55fd744bb6 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -6,5 +6,22 @@ error: cannot borrow immutable field `z.x` as mutable 21 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to previous error +error: cannot borrow immutable field `z.x` as mutable + --> $DIR/issue-39544.rs:25:18 + | +24 | pub fn with_arg(z: Z, w: &Z) { + | - consider changing this to `mut z` +25 | let _ = &mut z.x; + | ^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `w.x` as mutable + --> $DIR/issue-39544.rs:26:18 + | +24 | pub fn with_arg(z: Z, w: &Z) { + | -- use `&mut Z` here to make mutable +25 | let _ = &mut z.x; +26 | let _ = &mut w.x; + | ^^^ cannot mutably borrow immutable field + +error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/issue-40823.rs b/src/test/ui/did_you_mean/issue-40823.rs new file mode 100644 index 0000000000000..f4ae325727982 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.rs @@ -0,0 +1,14 @@ +// Copyright 2017 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 mut buf = &[1, 2, 3, 4]; + buf.iter_mut(); +} diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr new file mode 100644 index 0000000000000..8e77ebd9b6da3 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.stderr @@ -0,0 +1,8 @@ +error: cannot borrow immutable borrowed content `*buf` as mutable + --> $DIR/issue-40823.rs:13:5 + | +13 | buf.iter_mut(); + | ^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index b83a6aaebf323..edf1635a6b84f 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24 | 62 | fn deref_mut_field1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 63 | let __isize = &mut x.y; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -28,7 +28,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5 | 97 | fn assign_field1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 98 | x.y = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -54,7 +54,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5 | 118 | fn deref_mut_method1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 119 | x.set(0, 0); //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -70,7 +70,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 | 138 | fn assign_method1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 139 | *x.y_mut() = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index af954a4d7924f..2ec0116872179 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25 | 38 | fn deref_mut1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 39 | let __isize = &mut *x; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -18,7 +18,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 | 58 | fn assign1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 59 | *x = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index 4ef1cb9c239e4..0abdbdc3a21b5 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable error: cannot borrow immutable `Box` content `*x` as mutable --> $DIR/borrowck-object-mutability.rs:29:5 | +27 | fn owned_receiver(x: Box) { + | - consider changing this to `mut x` +28 | x.borrowed(); 29 | x.borrowed_mut(); //~ ERROR cannot borrow | ^ cannot borrow as mutable From 39011f8590b69d5ee9037c4ac9b863a516ae2e1e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Mar 2017 01:35:50 +0300 Subject: [PATCH 301/662] fix handling of `self` --- src/librustc/hir/lowering.rs | 7 ++ src/librustc/hir/mod.rs | 3 + src/librustc_borrowck/borrowck/mod.rs | 60 ++++++++------- src/test/ui/did_you_mean/issue-39544.rs | 28 ++++++- src/test/ui/did_you_mean/issue-39544.stderr | 83 +++++++++++++++++++-- 5 files changed, 143 insertions(+), 38 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99e1..726c305e90304 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> { FunctionRetTy::Default(span) => hir::DefaultReturn(span), }, variadic: decl.variadic, + has_implicit_self: decl.inputs.get(0).map_or(false, |arg| { + match arg.ty.node { + TyKind::ImplicitSelf => true, + TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf, + _ => false + } + }) }) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 1c79a02d3da0e..43b7deb5b90e3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1379,6 +1379,9 @@ pub struct FnDecl { pub inputs: HirVec>, pub output: FunctionRetTy, pub variadic: bool, + /// True if this function has an `self`, `&self` or `&mut self` receiver + /// (but not a `self: Xxx` one). + pub has_implicit_self: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0981369ace5c1..558a835be1884 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,6 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; -use syntax::symbol::keywords; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; @@ -809,32 +808,33 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } /// Given a type, if it is an immutable reference, return a suggestion to make it mutable - fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { + fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { // Check wether the argument is an immutable reference + debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { // Account for existing lifetimes when generating the message - if !lifetime.is_elided() { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { - if let Ok(lifetime_snippet) = self.tcx.sess.codemap() - .span_to_snippet(lifetime.span) { - return Some(format!("use `&{} mut {}` here to make mutable", - lifetime_snippet, - snippet)); - } - } - } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) { - if snippet.starts_with("&") { - return Some(format!("use `{}` here to make mutable", - snippet.replace("&", "&mut "))); - } + let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) { + Ok(snippet) => snippet, + _ => return None + }; + + let lifetime_snippet = if !lifetime.is_elided() { + format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) { + Ok(lifetime_snippet) => lifetime_snippet, + _ => return None + }) } else { - bug!("couldn't find a snippet for span: {:?}", pty.span); - } + String::new() + }; + Some(format!("use `&{}mut {}` here to make mutable", + lifetime_snippet, + if is_implicit_self { "self" } else { &*pointee_snippet })) + } else { + None } - None } fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { @@ -849,7 +849,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> { + fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) { let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); @@ -857,16 +857,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some(fn_like) = FnLikeNode::from_node(parent_node) { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); - // Get the position of `nid` in the arguments list + // Get the position of `node_id` in the arguments list let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - Some(&fn_like.decl().inputs[i]) + (Some(&fn_like.decl().inputs[i]), + i == 0 && fn_like.decl().has_implicit_self) } else { - None + (None, false) } } else { - None + (None, false) } } @@ -880,8 +881,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let let_span = self.tcx.hir.span(node_id); if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - if self.tcx.hir.name(node_id) == keywords::SelfValue.name() && - snippet != "self" { + let (_, is_implicit_self) = self.local_ty(node_id); + if is_implicit_self && snippet != "self" { // avoid suggesting `mut &self`. return } @@ -906,8 +907,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } hir::BindingMode::BindByValue(..) => { - if let Some(local_ty) = self.local_ty(node_id) { - if let Some(msg) = self.suggest_mut_for_immutable(local_ty) { + if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { + if let Some(msg) = + self.suggest_mut_for_immutable(local_ty, is_implicit_self) { db.span_label(local_ty.span, &msg); } } @@ -921,7 +923,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { - if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) { db.span_label(field.ty.span, &msg); } } diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index c98fed3c3c3c7..6331fc5771fcb 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -16,11 +16,37 @@ pub struct Z { x: X } -pub fn main() { +fn main() { let z = Z { x: X::Y }; let _ = &mut z.x; } +impl Z { + fn foo<'z>(&'z self) { + let _ = &mut self.x; + } + + fn foo1(&self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo2<'a>(&'a self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo3<'a>(self: &'a Self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo4(other: &Z) { + let _ = &mut other.x; + } + +} + pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index bcd55fd744bb6..e1e229a8b0572 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -6,22 +6,89 @@ error: cannot borrow immutable field `z.x` as mutable 21 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:26:22 + | +25 | fn foo<'z>(&'z self) { + | -------- use `&'z mut self` here to make mutable +26 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:30:22 + | +29 | fn foo1(&self, other: &Z) { + | ----- use `&mut self` here to make mutable +30 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:31:22 + | +29 | fn foo1(&self, other: &Z) { + | -- use `&mut Z` here to make mutable +30 | let _ = &mut self.x; +31 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:35:22 + | +34 | fn foo2<'a>(&'a self, other: &Z) { + | -------- use `&'a mut self` here to make mutable +35 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:36:22 + | +34 | fn foo2<'a>(&'a self, other: &Z) { + | -- use `&mut Z` here to make mutable +35 | let _ = &mut self.x; +36 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:40:22 + | +39 | fn foo3<'a>(self: &'a Self, other: &Z) { + | -------- use `&'a mut Self` here to make mutable +40 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:41:22 + | +39 | fn foo3<'a>(self: &'a Self, other: &Z) { + | -- use `&mut Z` here to make mutable +40 | let _ = &mut self.x; +41 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:45:22 + | +44 | fn foo4(other: &Z) { + | -- use `&mut Z` here to make mutable +45 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + error: cannot borrow immutable field `z.x` as mutable - --> $DIR/issue-39544.rs:25:18 + --> $DIR/issue-39544.rs:51:18 | -24 | pub fn with_arg(z: Z, w: &Z) { +50 | pub fn with_arg(z: Z, w: &Z) { | - consider changing this to `mut z` -25 | let _ = &mut z.x; +51 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field error: cannot borrow immutable field `w.x` as mutable - --> $DIR/issue-39544.rs:26:18 + --> $DIR/issue-39544.rs:52:18 | -24 | pub fn with_arg(z: Z, w: &Z) { +50 | pub fn with_arg(z: Z, w: &Z) { | -- use `&mut Z` here to make mutable -25 | let _ = &mut z.x; -26 | let _ = &mut w.x; +51 | let _ = &mut z.x; +52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 3 previous errors +error: aborting due to 11 previous errors From 737511ee118b16382bc7eb6a217ea370731f4821 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 27 Mar 2017 05:22:18 +0000 Subject: [PATCH 302/662] Ensure that macro resolutions in trait positions get finalized. --- src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/macros.rs | 5 ++--- src/test/compile-fail/issue-40845.rs | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-40845.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 879d8816488b2..0466e76475da3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -922,6 +922,10 @@ impl<'a> ModuleData<'a> { fn is_local(&self) -> bool { self.normal_ancestor_id.is_local() } + + fn nearest_item_scope(&'a self) -> Module<'a> { + if self.is_trait() { self.parent.unwrap() } else { self } + } } impl<'a> fmt::Debug for ModuleData<'a> { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3d6c6896549a4..05f30f039c8f0 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -172,7 +172,6 @@ impl<'a> base::Resolver for Resolver<'a> { expansion: mark, }; expansion.visit_with(&mut visitor); - self.current_module.unresolved_invocations.borrow_mut().remove(&mark); invocation.expansion.set(visitor.legacy_scope); } @@ -390,7 +389,7 @@ impl<'a> Resolver<'a> { Err(Determinacy::Determined) }, }; - self.current_module.macro_resolutions.borrow_mut() + self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); return def; } @@ -410,7 +409,7 @@ impl<'a> Resolver<'a> { } }; - self.current_module.legacy_macro_resolutions.borrow_mut() + self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() .push((scope, path[0], span, kind)); result diff --git a/src/test/compile-fail/issue-40845.rs b/src/test/compile-fail/issue-40845.rs new file mode 100644 index 0000000000000..c5604a0427b2a --- /dev/null +++ b/src/test/compile-fail/issue-40845.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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 T { m!(); } //~ ERROR cannot find macro `m!` in this scope + +struct S; +impl S { m!(); } //~ ERROR cannot find macro `m!` in this scope + +fn main() {} From 79feb9476d9275cb6abac88affdbfd3c922a2805 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Mar 2017 10:10:18 +0100 Subject: [PATCH 303/662] allow `InternedString` to be compared to `str` directly --- src/libsyntax/symbol.rs | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index 6642c60d256b3..2acbeee426bee 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -72,9 +72,9 @@ impl Decodable for Symbol { } } -impl<'a> PartialEq<&'a str> for Symbol { - fn eq(&self, other: &&str) -> bool { - *self.as_str() == **other +impl> PartialEq for Symbol { + fn eq(&self, other: &T) -> bool { + self.as_str() == other.deref() } } @@ -244,11 +244,47 @@ fn with_interner T>(f: F) -> T { /// destroyed. In particular, they must not access string contents. This can /// be fixed in the future by just leaking all strings until thread death /// somehow. -#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] +#[derive(Clone, Hash, PartialOrd, Eq, Ord)] pub struct InternedString { string: &'static str, } +impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { + fn as_ref(&self) -> &U { + self.string.as_ref() + } +} + +impl> ::std::cmp::PartialEq for InternedString { + fn eq(&self, other: &T) -> bool { + self.string == other.deref() + } +} + +impl ::std::cmp::PartialEq for str { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a str { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + +impl ::std::cmp::PartialEq for String { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a String { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + impl !Send for InternedString { } impl ::std::ops::Deref for InternedString { From eb447f4ef436f0c6211a13de1e6150a09228a9c6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 24 Mar 2017 09:31:26 +0100 Subject: [PATCH 304/662] Fix various useless derefs and slicings --- src/bootstrap/check.rs | 2 +- src/grammar/verify.rs | 6 ++--- src/libcollections/linked_list.rs | 2 +- src/libgraphviz/lib.rs | 6 ++--- src/librustc/ich/fingerprint.rs | 4 ++-- src/librustc/lint/context.rs | 5 ++-- src/librustc/middle/stability.rs | 2 +- src/librustc_borrowck/borrowck/fragments.rs | 24 +++++++++---------- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_borrowck/graphviz.rs | 2 +- src/librustc_const_eval/_match.rs | 4 ++-- src/librustc_const_eval/check_match.rs | 2 +- .../accumulate_vec.rs | 8 +++---- src/librustc_data_structures/base_n.rs | 2 +- src/librustc_data_structures/blake2b.rs | 2 +- src/librustc_data_structures/indexed_set.rs | 8 +++---- src/librustc_driver/lib.rs | 10 ++++---- src/librustc_driver/pretty.rs | 6 ++--- src/librustc_driver/test.rs | 2 +- .../persist/file_format.rs | 4 ++-- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_llvm/build.rs | 4 ++-- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/encoder.rs | 4 ++-- src/librustc_metadata/locator.rs | 6 ++--- src/librustc_plugin/load.rs | 6 ++--- src/librustc_save_analysis/csv_dumper.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 8 +++---- src/librustc_trans/asm.rs | 4 ++-- src/librustc_trans/back/archive.rs | 4 ++-- src/librustc_trans/back/link.rs | 14 +++++------ src/librustc_trans/back/lto.rs | 4 ++-- src/librustc_trans/back/rpath.rs | 14 +++++------ src/librustc_trans/back/symbol_export.rs | 4 ++-- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/back/write.rs | 12 +++++----- src/librustc_trans/base.rs | 12 +++++----- src/librustc_trans/builder.rs | 6 ++--- src/librustdoc/html/render.rs | 4 ++-- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/feature_gate.rs | 9 ++++--- src/libsyntax/parse/parser.rs | 6 ++--- src/libsyntax/test.rs | 2 +- 46 files changed, 120 insertions(+), 122 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 40cdb9242df15..f8f641060c442 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -586,7 +586,7 @@ fn android_copy_libs(build: &Build, compiler: &Compiler, target: &str) { .arg(ADB_TEST_DIR)); let target_dir = format!("{}/{}", ADB_TEST_DIR, target); - build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir[..]])); + build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir])); for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 919fc98e438c5..bd28a63c5f4df 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -196,7 +196,7 @@ fn parse_antlr_token(s: &str, tokens: &HashMap, surrogate_ let toknum = &s[content_end + 3 .. toknum_end]; let not_found = format!("didn't find token {:?} in the map", toknum); - let proto_tok = tokens.get(toknum).expect(¬_found[..]); + let proto_tok = tokens.get(toknum).expect(¬_found); let nm = Symbol::intern(content); @@ -304,14 +304,14 @@ fn main() { let mut token_file = File::open(&Path::new(&args.next().unwrap())).unwrap(); let mut token_list = String::new(); token_file.read_to_string(&mut token_list).unwrap(); - let token_map = parse_token_list(&token_list[..]); + let token_map = parse_token_list(&token_list); let stdin = std::io::stdin(); let lock = stdin.lock(); let lines = lock.lines(); let antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().trim(), &token_map, - &surrogate_pairs_pos[..], + &surrogate_pairs_pos, has_bom)); for antlr_tok in antlr_tokens { diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index f58c87b801f55..8f0488f69369e 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -1376,7 +1376,7 @@ mod tests { thread::spawn(move || { check_links(&n); let a: &[_] = &[&1, &2, &3]; - assert_eq!(a, &n.iter().collect::>()[..]); + assert_eq!(a, &*n.iter().collect::>()); }) .join() .ok() diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 8e587ad211de8..1b2c7775185f7 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -554,7 +554,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match self { &LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s[..])), + &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), &HtmlStr(ref s) => format!("<{}>", s), } } @@ -587,7 +587,7 @@ impl<'a> LabelText<'a> { let mut prefix = self.pre_escaped_content().into_owned(); let suffix = suffix.pre_escaped_content(); prefix.push_str(r"\n\n"); - prefix.push_str(&suffix[..]); + prefix.push_str(&suffix); EscStr(prefix.into_cow()) } } @@ -878,7 +878,7 @@ mod tests { type Node = Node; type Edge = &'a Edge; fn graph_id(&'a self) -> Id<'a> { - Id::new(&self.name[..]).unwrap() + Id::new(self.name).unwrap() } fn node_id(&'a self, n: &Node) -> Id<'a> { id_name(n) diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index d296d8293fb06..e760f7efc93d9 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -55,7 +55,7 @@ impl Fingerprint { impl Encodable for Fingerprint { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { - for &byte in &self.0[..] { + for &byte in &self.0 { s.emit_u8(byte)?; } Ok(()) @@ -66,7 +66,7 @@ impl Decodable for Fingerprint { #[inline] fn decode(d: &mut D) -> Result { let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]); - for byte in &mut result.0[..] { + for byte in &mut result.0 { *byte = d.read_u8()?; } Ok(result) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index d35f965e2ffd7..20bf241a99906 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -40,7 +40,6 @@ use std::cmp; use std::default::Default as StdDefault; use std::mem; use std::fmt; -use std::ops::Deref; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; @@ -485,7 +484,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, Allow => bug!("earlier conditional return should handle Allow case") }; let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str().deref() == name { + if lint_flag_val.as_str() == name { err.note(&format!("requested on the command line with `{} {}`", flag, hyphen_case_lint_name)); } else { @@ -496,7 +495,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, }, Node(lint_attr_name, src) => { def = Some(src); - if lint_attr_name.as_str().deref() != name { + if lint_attr_name.as_str() != name { let level_str = level.as_str(); err.note(&format!("#[{}({})] implied by #[{}({})]", level_str, name, level_str, lint_attr_name)); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4115b4669f4b2..4354ed6817ae9 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -536,7 +536,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if !self.stability.borrow().active_features.contains(feature) { let msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", - &feature.as_str(), &r), + feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index c0f681680a967..b728d4d534516 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -267,11 +267,11 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx // First, filter out duplicates moved.sort(); moved.dedup(); - debug!("fragments 1 moved: {:?}", path_lps(&moved[..])); + debug!("fragments 1 moved: {:?}", path_lps(&moved)); assigned.sort(); assigned.dedup(); - debug!("fragments 1 assigned: {:?}", path_lps(&assigned[..])); + debug!("fragments 1 assigned: {:?}", path_lps(&assigned)); // Second, build parents from the moved and assigned. for m in &moved { @@ -291,14 +291,14 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx parents.sort(); parents.dedup(); - debug!("fragments 2 parents: {:?}", path_lps(&parents[..])); + debug!("fragments 2 parents: {:?}", path_lps(&parents)); // Third, filter the moved and assigned fragments down to just the non-parents - moved.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 moved: {:?}", path_lps(&moved[..])); + moved.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 moved: {:?}", path_lps(&moved)); - assigned.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 assigned: {:?}", path_lps(&assigned[..])); + assigned.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 assigned: {:?}", path_lps(&assigned)); // Fourth, build the leftover from the moved, assigned, and parents. for m in &moved { @@ -316,16 +316,16 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx unmoved.sort(); unmoved.dedup(); - debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved)); // Fifth, filter the leftover fragments down to its core. unmoved.retain(|f| match *f { AllButOneFrom(_) => true, - Just(mpi) => non_member(mpi, &parents[..]) && - non_member(mpi, &moved[..]) && - non_member(mpi, &assigned[..]) + Just(mpi) => non_member(mpi, &parents) && + non_member(mpi, &moved) && + non_member(mpi, &assigned) }); - debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved)); // Swap contents back in. fragments.unmoved_fragments = unmoved; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b05f..59c3e68aadab2 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -112,7 +112,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { &flowed_moves.move_data, owner_id); - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 0da9525efd856..e3a2bfa392738 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { set.push_str(", "); } let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp); - set.push_str(&loan_str[..]); + set.push_str(&loan_str); saw_some = true; true }); diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 53a7e87292818..c1dc5f5f7a2b8 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -680,10 +680,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( }).collect(); let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect(); let matrix = Matrix(m.iter().flat_map(|r| { - specialize(cx, &r[..], &ctor, &wild_patterns) + specialize(cx, &r, &ctor, &wild_patterns) }).collect()); match specialize(cx, v, &ctor, &wild_patterns) { - Some(v) => match is_useful(cx, &matrix, &v[..], witness) { + Some(v) => match is_useful(cx, &matrix, &v, witness) { UsefulWithWitness(witnesses) => UsefulWithWitness( witnesses.into_iter() .map(|witness| witness.apply_constructor(cx, &ctor, lty)) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e2b9f174ff0c2..9d55281d019d9 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -311,7 +311,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, for &(pat, hir_pat) in pats { let v = vec![pat]; - match is_useful(cx, &seen, &v[..], LeaveOutWitness) { + match is_useful(cx, &seen, &v, LeaveOutWitness) { NotUseful => { match source { hir::MatchSource::IfLetDesugar { .. } => { diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index d4bd9e707fdcb..c03c2890ba34c 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -91,8 +91,8 @@ impl Deref for AccumulateVec
{ type Target = [A::Element]; fn deref(&self) -> &Self::Target { match *self { - AccumulateVec::Array(ref v) => &v[..], - AccumulateVec::Heap(ref v) => &v[..], + AccumulateVec::Array(ref v) => v, + AccumulateVec::Heap(ref v) => v, } } } @@ -100,8 +100,8 @@ impl Deref for AccumulateVec { impl DerefMut for AccumulateVec { fn deref_mut(&mut self) -> &mut [A::Element] { match *self { - AccumulateVec::Array(ref mut v) => &mut v[..], - AccumulateVec::Heap(ref mut v) => &mut v[..], + AccumulateVec::Array(ref mut v) => v, + AccumulateVec::Heap(ref mut v) => v, } } } diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs index 4359581a897f5..cf54229fa7f52 100644 --- a/src/librustc_data_structures/base_n.rs +++ b/src/librustc_data_structures/base_n.rs @@ -48,7 +48,7 @@ pub fn encode(n: u64, base: u64) -> String { #[test] fn test_encode() { fn test(n: u64, base: u64) { - assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32)); + assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base), base as u32)); } for base in 2..37 { diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 31492e2621945..9d97a83f693c3 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -35,7 +35,7 @@ pub struct Blake2bCtx { impl ::std::fmt::Debug for Blake2bCtx { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { try!(write!(fmt, "hash: ")); - for v in &self.h[..] { + for v in &self.h { try!(write!(fmt, "{:x}", v)); } Ok(()) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e9e054e97eaf..572ce98d3ae8e 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -91,13 +91,13 @@ impl IdxSet { impl Deref for IdxSetBuf { type Target = IdxSet; fn deref(&self) -> &IdxSet { - unsafe { IdxSet::from_slice(&self.bits[..]) } + unsafe { IdxSet::from_slice(&self.bits) } } } impl DerefMut for IdxSetBuf { fn deref_mut(&mut self) -> &mut IdxSet { - unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) } + unsafe { IdxSet::from_slice_mut(&mut self.bits) } } } @@ -135,11 +135,11 @@ impl IdxSet { } pub fn words(&self) -> &[Word] { - &self.bits[..] + &self.bits } pub fn words_mut(&mut self) -> &mut [Word] { - &mut self.bits[..] + &mut self.bits } pub fn clone_from(&mut self, other: &IdxSet) { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 68b9f85721ad5..e11118901d283 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -233,7 +233,7 @@ fn make_output(matches: &getopts::Matches) -> (Option, Option) // Extract input (string or file and optional path) from matches. fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { if free_matches.len() == 1 { - let ifile = &free_matches[0][..]; + let ifile = &free_matches[0]; if ifile == "-" { let mut src = String::new(); io::stdin().read_to_string(&mut src).unwrap(); @@ -800,7 +800,7 @@ Available lint options: for lint in lints { let name = lint.name_lower().replace("_", "-"); println!(" {} {:7.7} {}", - padded(&name[..]), + padded(&name), lint.default_level.as_str(), lint.desc); } @@ -838,7 +838,7 @@ Available lint options: .map(|x| x.to_string().replace("_", "-")) .collect::>() .join(", "); - println!(" {} {}", padded(&name[..]), desc); + println!(" {} {}", padded(&name), desc); } println!("\n"); }; @@ -945,7 +945,7 @@ pub fn handle_options(args: &[String]) -> Option { .into_iter() .map(|x| x.opt_group) .collect(); - let matches = match getopts::getopts(&args[..], &all_groups) { + let matches = match getopts::getopts(&args, &all_groups) { Ok(m) => m, Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), }; @@ -1084,7 +1084,7 @@ pub fn monitor(f: F) { format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; for note in &xs { handler.emit(&MultiSpan::new(), - ¬e[..], + ¬e, errors::Level::Note); } if match env::var_os("RUST_BACKTRACE") { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 6cd97e9559885..18dc504ca8aa9 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -589,7 +589,7 @@ impl UserIdentifiedItem { -> NodesMatchingUII<'a, 'hir> { match *self { ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), - ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])), + ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), } } @@ -600,7 +600,7 @@ impl UserIdentifiedItem { user_option, self.reconstructed_input(), is_wrong_because); - sess.fatal(&message[..]) + sess.fatal(&message) }; let mut saw_node = ast::DUMMY_NODE_ID; @@ -771,7 +771,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, fn expand_err_details(r: io::Result<()>) -> io::Result<()> { r.map_err(|ioerr| { io::Error::new(io::ErrorKind::Other, - &format!("graphviz::render failed: {}", ioerr)[..]) + format!("graphviz::render failed: {}", ioerr)) }) } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9568cc3d6de0e..af2416f787ea4 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name[..])) + self.infcx.tcx.mk_param(index, Symbol::intern(&name)) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> &'tcx ty::Region { diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index b67caa6750a81..5c20f65274f54 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -99,9 +99,9 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result>> { let rustc_version_str_len = rustc_version_str_len[0] as usize; let mut buffer = Vec::with_capacity(rustc_version_str_len); buffer.resize(rustc_version_str_len, 0); - file.read_exact(&mut buffer[..])?; + file.read_exact(&mut buffer)?; - if &buffer[..] != rustc_version().as_bytes() { + if buffer != rustc_version().as_bytes() { report_format_mismatch(sess, path, "Different compiler version"); return Ok(None); } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 353b86820c405..c4220e9a0d3dc 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -88,7 +88,7 @@ impl NonCamelCaseTypes { } else { format!("{} `{}` should have a camel case name such as `{}`", sort, name, c) }; - cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); + cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m); } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f0276f90f274d..0ee9d4a42c7f8 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -334,7 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { attr.check_name("doc") && match attr.meta_item_list() { None => false, - Some(l) => attr::list_contains_name(&l[..], "hidden"), + Some(l) => attr::list_contains_name(&l, "hidden"), } }); self.doc_hidden_stack.push(doc_hidden); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index abba8afd9da86..86bf209ccf8c8 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::TyBool => return, ty::TyAdt(def, _) => { let attrs = cx.tcx.get_attrs(def.did); - check_must_use(cx, &attrs[..], s.span) + check_must_use(cx, &attrs, s.span) } _ => false, }; diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 42717ec289c34..2b945e0a3afaf 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -140,7 +140,7 @@ fn main() { cfg.flag(flag); } - for component in &components[..] { + for component in &components { let mut flag = String::from("-DLLVM_COMPONENT_"); flag.push_str(&component.to_uppercase()); cfg.flag(&flag); @@ -173,7 +173,7 @@ fn main() { if !is_crossed { cmd.arg("--system-libs"); } - cmd.args(&components[..]); + cmd.args(&components); for lib in output(&mut cmd).split_whitespace() { let name = if lib.starts_with("-l") { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index e1255110a83d1..04a8b88f8a594 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -669,7 +669,7 @@ impl<'a> CrateLoader<'a> { name, config::host_triple(), self.sess.opts.target_triple); - span_fatal!(self.sess, span, E0456, "{}", &message[..]); + span_fatal!(self.sess, span, E0456, "{}", &message); } let root = ekrate.metadata.get_root(); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a324c166e738d..1370d69f90466 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -918,14 +918,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(def_id); } hir::ItemImpl(..) => { - for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { + for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { - for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { + for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, EncodeContext::encode_info_for_trait_item, item_def_id); diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index a6771083fc34e..e8bc8b01652a6 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -477,15 +477,15 @@ impl<'a> Context<'a> { Some(file) => file, }; let (hash, found_kind) = - if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { + if file.starts_with(&rlib_prefix) && file.ends_with(".rlib") { (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) - } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") { + } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") { (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) } else if file.starts_with(&dylib_prefix) && file.ends_with(&dypair.1) { (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib) } else { - if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) { + if file.starts_with(&staticlib_prefix) && file.ends_with(&staticpair.1) { staticlibs.push(CrateMismatch { path: path.to_path_buf(), got: "static".to_string(), diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 1bfc445fca98d..efe9963cecc73 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -126,19 +126,19 @@ impl<'a> PluginLoader<'a> { // inside this crate, so continue would spew "macro undefined" // errors Err(err) => { - self.sess.span_fatal(span, &err[..]) + self.sess.span_fatal(span, &err) } }; unsafe { let registrar = - match lib.symbol(&symbol[..]) { + match lib.symbol(&symbol) { Ok(registrar) => { mem::transmute::<*mut u8,PluginRegistrarFun>(registrar) } // again fatal if we can't register macros Err(err) => { - self.sess.span_fatal(span, &err[..]) + self.sess.span_fatal(span, &err) } }; diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index 59340ae87ee5d..4bab135ff12f7 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -423,7 +423,7 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String { let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); strs.fold(String::new(), |mut s, ss| { - s.push_str(&ss[..]); + s.push_str(&ss); s }) } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 27a19d211c290..1530708b4b888 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -369,7 +369,7 @@ impl FnType { match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments, _) => { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - &tupled_arguments[..] + &tupled_arguments } _ => { bug!("argument to function with \"rust-call\" ABI \ diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 058f37f62dd82..5c1ced573402e 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -229,11 +229,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, variant_fill].iter().cloned().collect(); match name { None => { - Type::struct_(cx, &fields[..], false) + Type::struct_(cx, &fields, false) } Some(name) => { let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&fields[..], false); + llty.set_struct_body(&fields, false); llty } } @@ -330,7 +330,7 @@ fn struct_wrapped_nullable_bitdiscr( alignment: Alignment, ) -> ValueRef { let llptrptr = bcx.gepi(scrutinee, - &discrfield.iter().map(|f| *f as usize).collect::>()[..]); + &discrfield.iter().map(|f| *f as usize).collect::>()); let llptr = bcx.load(llptrptr, alignment.to_align()); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; bcx.icmp(cmp, llptr, C_null(val_ty(llptr))) @@ -402,7 +402,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu base::call_memset(bcx, llptr, fill_byte, size, align, false); } else { let path = discrfield.iter().map(|&i| i as usize).collect::>(); - let llptrptr = bcx.gepi(val, &path[..]); + let llptrptr = bcx.gepi(val, &path); let llptrty = val_ty(llptrptr).element_type(); bcx.store(C_null(llptrty), llptrptr, None); } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 12e4e57964f98..b6195765b27c2 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -77,14 +77,14 @@ pub fn trans_inline_asm<'a, 'tcx>( .chain(arch_clobbers.iter().map(|s| s.to_string())) .collect::>().join(","); - debug!("Asm Constraints: {}", &all_constraints[..]); + debug!("Asm Constraints: {}", &all_constraints); // Depending on how many outputs we have, the return type is different let num_outputs = output_types.len(); let output_type = match num_outputs { 0 => Type::void(bcx.ccx), 1 => output_types[0], - _ => Type::struct_(bcx.ccx, &output_types[..], false) + _ => Type::struct_(bcx.ccx, &output_types, false) }; let dialect = match ia.dialect { diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 11ab6dcaa87f9..0f908b7d0698b 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -65,10 +65,10 @@ pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) for path in search_paths { debug!("looking for {} inside {:?}", name, path); - let test = path.join(&oslibname[..]); + let test = path.join(&oslibname); if test.exists() { return test } if oslibname != unixlibname { - let test = path.join(&unixlibname[..]); + let test = path.join(&unixlibname); if test.exists() { return test } } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index cf1e10b317b1e..6d17b2f0eeda3 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -91,7 +91,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { let validate = |s: String, span: Option| { - cstore::validate_crate_name(sess, &s[..], span); + cstore::validate_crate_name(sess, &s, span); s }; @@ -109,7 +109,7 @@ pub fn find_crate_name(sess: Option<&Session>, let msg = format!("--crate-name and #[crate_name] are \ required to match, but `{}` != `{}`", s, name); - sess.span_err(attr.span, &msg[..]); + sess.span_err(attr.span, &msg); } } return validate(s.clone(), None); @@ -417,7 +417,7 @@ fn object_filenames(trans: &CrateTranslation, outputs: &OutputFilenames) -> Vec { trans.modules.iter().map(|module| { - outputs.temp_path(OutputType::Object, Some(&module.name[..])) + outputs.temp_path(OutputType::Object, Some(&module.name)) }).collect() } @@ -551,7 +551,7 @@ fn link_rlib<'a>(sess: &'a Session, e)) } - let bc_data_deflated = flate::deflate_bytes(&bc_data[..]); + let bc_data_deflated = flate::deflate_bytes(&bc_data); let mut bc_file_deflated = match fs::File::create(&bc_deflated_filename) { Ok(file) => file, @@ -819,12 +819,12 @@ fn link_natively(sess: &Session, pname, prog.status)) .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output[..])) + .note(&escape_string(&output)) .emit(); sess.abort_if_errors(); } - info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); - info!("linker stdout:\n{}", escape_string(&prog.stdout[..])); + info!("linker stderr:\n{}", escape_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_string(&prog.stdout)); }, Err(e) => { sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e)) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 0ef3f351a2a4b..e23ddd2542a80 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -61,7 +61,7 @@ pub fn run(sess: &session::Session, } let export_threshold = - symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + symbol_export::crates_export_threshold(&sess.crate_types.borrow()); let symbol_filter = &|&(ref name, level): &(String, _)| { if symbol_export::is_below_threshold(level, export_threshold) { @@ -147,7 +147,7 @@ pub fn run(sess: &session::Session, bc_decoded.len() as libc::size_t) { write::llvm_err(sess.diagnostic(), format!("failed to load bc of `{}`", - &name[..])); + name)); } }); } diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_trans/back/rpath.rs index 9c982be3fa03e..104e7bc6a52bd 100644 --- a/src/librustc_trans/back/rpath.rs +++ b/src/librustc_trans/back/rpath.rs @@ -37,8 +37,8 @@ pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { let libs = config.used_crates.clone(); let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::>(); - let rpaths = get_rpaths(config, &libs[..]); - flags.extend_from_slice(&rpaths_to_flags(&rpaths[..])); + let rpaths = get_rpaths(config, &libs); + flags.extend_from_slice(&rpaths_to_flags(&rpaths)); // Use DT_RUNPATH instead of DT_RPATH if available if config.linker_is_gnu { @@ -84,14 +84,14 @@ fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec { } } - log_rpaths("relative", &rel_rpaths[..]); - log_rpaths("fallback", &fallback_rpaths[..]); + log_rpaths("relative", &rel_rpaths); + log_rpaths("fallback", &fallback_rpaths); let mut rpaths = rel_rpaths; - rpaths.extend_from_slice(&fallback_rpaths[..]); + rpaths.extend_from_slice(&fallback_rpaths); // Remove duplicates - let rpaths = minimize_rpaths(&rpaths[..]); + let rpaths = minimize_rpaths(&rpaths); return rpaths; } @@ -177,7 +177,7 @@ fn minimize_rpaths(rpaths: &[String]) -> Vec { let mut set = HashSet::new(); let mut minimized = Vec::new(); for rpath in rpaths { - if set.insert(&rpath[..]) { + if set.insert(rpath) { minimized.push(rpath.clone()); } } diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 005fb3533ab0b..23a67ef5046ee 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -154,7 +154,7 @@ impl ExportedSymbols { cnum: CrateNum) -> &[(String, SymbolExportLevel)] { match self.exports.get(&cnum) { - Some(exports) => &exports[..], + Some(exports) => exports, None => &[] } } @@ -167,7 +167,7 @@ impl ExportedSymbols { { for &(ref name, export_level) in self.exported_symbols(cnum) { if is_below_threshold(export_level, export_threshold) { - f(&name[..], export_level) + f(&name, export_level) } } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 518995dfedcc2..3ad04e10cb027 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -341,7 +341,7 @@ pub fn sanitize(s: &str) -> String { if !result.is_empty() && result.as_bytes()[0] != '_' as u8 && ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", &result[..]); + return format!("_{}", result); } return result; diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 377ff34cb7e0d..5a017e4fb8a9a 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -105,7 +105,7 @@ impl SharedEmitter { Some(ref code) => { handler.emit_with_code(&MultiSpan::new(), &diag.msg, - &code[..], + &code, diag.lvl); }, None => { @@ -189,8 +189,8 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { let fdata_sections = ffunction_sections; let code_model_arg = match sess.opts.cg.code_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.code_model[..], + Some(ref s) => &s, + None => &sess.target.target.options.code_model, }; let code_model = match CODE_GEN_MODEL_ARGS.iter().find( @@ -397,7 +397,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) .expect("non-UTF8 SMDiagnostic"); - report_inline_asm(cgcx, &msg[..], cookie); + report_inline_asm(cgcx, &msg, cookie); } unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { @@ -823,7 +823,7 @@ pub fn run_passes(sess: &Session, if trans.modules.len() == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&(trans.modules[0].name)[..]); + let module_name = Some(&trans.modules[0].name[..]); let path = crate_output.temp_path(output_type, module_name); copy_gracefully(&path, &crate_output.path(output_type)); @@ -939,7 +939,7 @@ pub fn run_passes(sess: &Session, if metadata_config.emit_bc && !user_wants_bitcode { let path = crate_output.temp_path(OutputType::Bitcode, - Some(&trans.metadata_module.name[..])); + Some(&trans.metadata_module.name)); remove(sess, &path); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f7ca468fddaef..ec45c5593632e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -514,7 +514,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>, n_bytes: ValueRef, align: u32) { let ccx = b.ccx; - let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; + let ptr_width = &ccx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); let memcpy = ccx.get_intrinsic(&key); let src_ptr = b.pointercast(src, Type::i8p(ccx)); @@ -550,7 +550,7 @@ pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, size: ValueRef, align: ValueRef, volatile: bool) -> ValueRef { - let ptr_width = &b.ccx.sess().target.target.target_pointer_width[..]; + let ptr_width = &b.ccx.sess().target.target.target_pointer_width; let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); let llintrinsicfn = b.ccx.get_intrinsic(&intrinsic_key); let volatile = C_bool(b.ccx, volatile); @@ -765,7 +765,7 @@ fn write_metadata(cx: &SharedCrateContext, let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); - let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); + let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); let name = cx.metadata_symbol_name(); let buf = CString::new(name).unwrap(); @@ -796,7 +796,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { let export_threshold = - symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + symbol_export::crates_export_threshold(&sess.crate_types.borrow()); let exported_symbols = exported_symbols .exported_symbols(LOCAL_CRATE) @@ -1035,7 +1035,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated // with "internal" linkage and are never exported. - !attr::requests_inline(&attributes[..]) + !attr::requests_inline(&attributes) } _ => false @@ -1574,7 +1574,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a cgus.dedup(); for &(ref cgu_name, linkage) in cgus.iter() { output.push_str(" "); - output.push_str(&cgu_name[..]); + output.push_str(&cgu_name); let linkage_abbrev = match linkage { llvm::Linkage::ExternalLinkage => "External", diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index a62f07042a703..8b1010d89fd9f 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -627,7 +627,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { let v = ixs.iter().map(|i| C_i32(self.ccx, *i as i32)).collect::>(); self.count_insn("gepi"); - self.inbounds_gep(base, &v[..]) + self.inbounds_gep(base, &v) } } @@ -835,8 +835,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let s = format!("{} ({})", text, self.ccx.sess().codemap().span_to_string(sp)); - debug!("{}", &s[..]); - self.add_comment(&s[..]); + debug!("{}", s); + self.add_comment(&s); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5c94032c6b9cf..612e765a499b7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2611,7 +2611,7 @@ fn render_attribute(attr: &ast::MetaItem) -> Option { if attr.is_word() { Some(format!("{}", name)) } else if let Some(v) = attr.value_str() { - Some(format!("{} = {:?}", name, &v.as_str()[..])) + Some(format!("{} = {:?}", name, v.as_str())) } else if let Some(values) = attr.meta_item_list() { let display: Vec<_> = values.iter().filter_map(|attr| { attr.meta_item().and_then(|mi| render_attribute(mi)) @@ -2642,7 +2642,7 @@ fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { for attr in &it.attrs.other_attrs { let name = attr.name().unwrap(); - if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) { + if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) { continue; } if let Some(s) = render_attribute(&attr.meta().unwrap()) { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 021c5398a4200..66f5520b88263 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -119,7 +119,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, }; let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false); p.root_module_name = cx.current_expansion.module.mod_path.last() - .map(|id| (*id.name.as_str()).to_owned()); + .map(|id| id.name.as_str().to_string()); p.check_unknown_macro_variable(); // Let the context choose how to interpret the result. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7af432176cf6e..9d280a413e666 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -818,7 +818,7 @@ pub struct GatedCfg { impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option { - let name = &*cfg.name().as_str(); + let name = cfg.name().as_str(); GATED_CFGS.iter() .position(|info| info.0 == name) .map(|idx| { @@ -865,8 +865,7 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = unwrap_or!(attr.name(), return); - + let name = unwrap_or!(attr.name(), return).as_str(); for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { if name == n { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { @@ -885,12 +884,12 @@ impl<'a> Context<'a> { return; } } - if name.as_str().starts_with("rustc_") { + if name.starts_with("rustc_") { gate_feature!(self, rustc_attrs, attr.span, "unless otherwise specified, attributes \ with the prefix `rustc_` \ are reserved for internal compiler diagnostics"); - } else if name.as_str().starts_with("derive_") { + } else if name.starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); } else if !attr::is_known(attr) { // Only run the custom attribute lint during regular diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 649e90599345b..43a9d8c5f787c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5151,15 +5151,15 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { - self.directory.path.push(&*path.as_str()); + self.directory.path.push(&path.as_str()); self.directory.ownership = DirectoryOwnership::Owned; } else { - self.directory.path.push(&*id.name.as_str()); + self.directory.path.push(&id.name.as_str()); } } pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option { - attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str())) + attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str())) } /// Returns either a path to a module, or . diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e052d2cda3a42..6fb6db9ca0282 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -616,7 +616,7 @@ fn mk_tests(cx: &TestCtxt) -> P { fn is_test_crate(krate: &ast::Crate) -> bool { match attr::find_crate_name(&krate.attrs) { - Some(s) if "test" == &*s.as_str() => true, + Some(s) if "test" == s.as_str() => true, _ => false } } From 3545fb512eacc18f4ef62aa91916b45bf9097497 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 27 Mar 2017 12:55:57 +0100 Subject: [PATCH 305/662] rustbuild: Fix compiler docs again The docs need to be built with the rustbuild feature so the correct stability attributes (rustc_private) get applied. --- src/bootstrap/bin/rustdoc.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index e9ca430f1582b..3a1a9c3e40d66 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -40,6 +40,14 @@ fn main() { .arg(sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + + // Pass the `rustbuild` feature flag to crates which rustbuild is + // building. See the comment in bootstrap/lib.rs where this env var is + // set for more details. + if env::var_os("RUSTBUILD_UNSTABLE").is_some() { + cmd.arg("--cfg").arg("rustbuild"); + } + std::process::exit(match cmd.status() { Ok(s) => s.code().unwrap_or(1), Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), From c80868e3b348f00d316ca411f9f3f2f3feb7e6a9 Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Mon, 27 Mar 2017 16:17:08 +0200 Subject: [PATCH 306/662] correcting another mistake in an example copy_pointer -> copy_borrowed_ptr --- src/librustc_borrowck/borrowck/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 29b007a7499c3..034b7cbadd9c6 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -633,7 +633,7 @@ Here is a concrete example of a bug this rule prevents: ```rust // Test region-reborrow-from-shorter-mut-ref.rs: -fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { +fn copy_borrowed_ptr<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { &mut **p // ERROR due to clause (1) } fn main() { From 99a069eec9a1ad8f4b4dd592d062f948e9b99540 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 27 Mar 2017 15:21:04 +0100 Subject: [PATCH 307/662] Fix broken Markdown and bad links in the error index This makes sure RFC links point to the RFC text not the pull request. --- src/librustc/diagnostics.rs | 5 +++-- src/librustc_resolve/diagnostics.rs | 6 ++++- src/librustc_typeck/diagnostics.rs | 34 ++++++++++++++++------------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 85b4ddcdd7190..5a0fbf8efb707 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1336,7 +1336,7 @@ trait SecondTrait : FirstTrait { E0398: r##" In Rust 1.3, the default object lifetime bounds are expected to change, as -described in RFC #1156 [1]. You are getting a warning because the compiler +described in [RFC 1156]. You are getting a warning because the compiler thinks it is possible that this change will cause a compilation error in your code. It is possible, though unlikely, that this is a false alarm. @@ -1365,7 +1365,7 @@ fn foo<'a>(arg: &Box) { ... } This explicitly states that you expect the trait object `SomeTrait` to contain references (with a maximum lifetime of `'a`). -[1]: https://github.com/rust-lang/rfcs/pull/1156 +[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md "##, E0452: r##" @@ -1771,6 +1771,7 @@ This pattern is incorrect because, because the type of `foo` is a function **item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`) is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: + - change the original fn declaration to match the expected signature, and do the cast in the fn body (the prefered option) - cast the fn item fo a fn pointer before calling transmute, as shown here: diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 8f6b1b8971e5b..2c2babf0a6653 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -890,19 +890,23 @@ match (A, B, C) { E0422: r##" You are trying to use an identifier that is either undefined or not a struct. Erroneous code example: -``` compile_fail,E0422 + +```compile_fail,E0422 fn main () { let x = Foo { x: 1, y: 2 }; } ``` + In this case, `Foo` is undefined, so it inherently isn't anything, and definitely not a struct. + ```compile_fail fn main () { let foo = 1; let x = foo { x: 1, y: 2 }; } ``` + In this case, `foo` is defined, but is not a struct, so Rust can't use it as one. "##, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0136faef28d8c..bd6129eb5bee3 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -790,7 +790,7 @@ Furthermore, the syntax is changing to use `in` instead of `box`. See [RFC 470] and [RFC 809] for more details. [RFC 470]: https://github.com/rust-lang/rfcs/pull/470 -[RFC 809]: https://github.com/rust-lang/rfcs/pull/809 +[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md "##, E0067: r##" @@ -1428,7 +1428,7 @@ type X = u32; // this compiles ``` Note that type parameters for enum-variant constructors go after the variant, -not after the enum (Option::None::, not Option::::None). +not after the enum (`Option::None::`, not `Option::::None`). "##, E0110: r##" @@ -1521,7 +1521,7 @@ impl Bar for u32 { For information on the design of the orphan rules, see [RFC 1023]. -[RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 +[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md "##, E0118: r##" @@ -1911,8 +1911,9 @@ type Foo = Trait; // ok! E0192: r##" Negative impls are only allowed for traits with default impls. For more -information see the [opt-in builtin traits RFC](https://github.com/rust-lang/ -rfcs/blob/master/text/0019-opt-in-builtin-traits.md). +information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md "##, E0193: r##" @@ -2147,7 +2148,7 @@ E0202: r##" Inherent associated types were part of [RFC 195] but are not yet implemented. See [the tracking issue][iss8995] for the status of this implementation. -[RFC 195]: https://github.com/rust-lang/rfcs/pull/195 +[RFC 195]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md [iss8995]: https://github.com/rust-lang/rust/issues/8995 "##, @@ -2424,7 +2425,7 @@ such that `Ti` is a local type. Then no type parameter can appear in any of the For information on the design of the orphan rules, see [RFC 1023]. -[RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 +[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md "##, /* @@ -2799,8 +2800,9 @@ verify this assertion; therefore we must tag this `impl` as unsafe. E0318: r##" Default impls for a trait must be located in the same crate where the trait was -defined. For more information see the [opt-in builtin traits RFC](https://github -.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md). +defined. For more information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md "##, E0321: r##" @@ -3018,10 +3020,8 @@ impl Unsize for MyType {} ``` If you are defining your own smart pointer type and would like to enable -conversion from a sized to an unsized type with the [DST coercion system] -(https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md), use -[`CoerceUnsized`](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html) -instead. +conversion from a sized to an unsized type with the +[DST coercion system][RFC 982], use [`CoerceUnsized`] instead. ``` #![feature(coerce_unsized)] @@ -3035,6 +3035,9 @@ pub struct MyType { impl CoerceUnsized> for MyType where T: CoerceUnsized {} ``` + +[RFC 982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md +[`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html "##, E0329: r##" @@ -3438,8 +3441,9 @@ struct. E0380: r##" Default impls are only allowed for traits with no methods or associated items. -For more information see the [opt-in builtin traits RFC](https://github.com/rust --lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md). +For more information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md "##, E0390: r##" From b8cbc5d46af4b15bfeca324aa37d8c2ca054e58e Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 27 Mar 2017 16:38:17 +0200 Subject: [PATCH 308/662] Addressed requested changes for PR #40838 * Fixed spelling ToSocketAddr -> ToSocketAddrs in module docs (which also fixes a link) * Added missing "when" before "interacting" in module docs * Changed SocketAddr's top-level docs to explicitly state what socket addresses consist of, making them more consistent with SocketAddrV4's and SocketAddrV6's docs * Changed "in C" -> "in C's `netinet/in.h`" * Changed wording in is_ipv4/is_ipv6 methods to ", `false` otherwise" * Add missing closing ` ``` ` in Ipv6Addr's examples * Removed "Errors" section in ToSocketAddrs' to_socket_addrs method as it was rather redundant --- src/libstd/net/addr.rs | 30 ++++++++++++------------------ src/libstd/net/ip.rs | 9 +++------ src/libstd/net/mod.rs | 4 ++-- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ccfd2a1dfb153..36c06dc0b58d0 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -22,9 +22,11 @@ use slice; /// An internet socket address, either IPv4 or IPv6. /// -/// This enum can contain either an [`SocketAddrV4`] or an [`SocketAddrV6`]. see their -/// respective documentation for more details. +/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well +/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and +/// [`SocketAddrV6`]'s respective documentation for more details. /// +/// [IP address]: ../../std/net/enum.IpAddr.html /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html /// @@ -202,13 +204,12 @@ impl SocketAddr { } /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [IPv4 address] and [`false`] if it's an [IPv6 address]. + /// [IPv4 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html /// [IP address]: ../../std/net/enum.IpAddr.html /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 - /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -230,12 +231,11 @@ impl SocketAddr { } /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [IPv6 address] and [`false`] if it's an [IPv4 address]. + /// [IPv6 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html /// [IP address]: ../../std/net/enum.IpAddr.html - /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples @@ -446,10 +446,10 @@ impl SocketAddrV6 { /// Returns the flow information associated with this address. /// - /// This information corresponds to the `sin6_flowinfo` field in C, as specified in - /// [IETF RFC 2553, Section 3.3]. It combines information about the flow label and - /// the traffic class as specified in [IETF RFC 2460], respectively [Section 6] and - /// [Section 7]. + /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// It combines information about the flow label and the traffic class as specified + /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 @@ -491,8 +491,8 @@ impl SocketAddrV6 { /// Returns the scope ID associated with this address. /// - /// This information corresponds to the `sin6_scope_id` field in C, as specified in - /// [IETF RFC 2553, Section 3.3]. + /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// @@ -743,12 +743,6 @@ pub trait ToSocketAddrs { /// /// Note that this function may block the current thread while resolution is /// performed. - /// - /// # Errors - /// - /// Any errors encountered during resolution will be returned as an [`Err`]. - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[stable(feature = "rust1", since = "1.0.0")] fn to_socket_addrs(&self) -> io::Result; } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 2a1f959b35d03..c46fe4a58c7e2 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -114,6 +114,7 @@ pub struct Ipv4Addr { /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); /// assert_eq!("::1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { @@ -266,13 +267,11 @@ impl IpAddr { } } - /// Returns [`true`] if this address is an [IPv4 address] and [`false`] if it's an - /// [IPv6 address]. + /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html /// [IPv4 address]: #variant.V4 - /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -293,12 +292,10 @@ impl IpAddr { } } - /// Returns [`true`] if this address is an [IPv6 address] and [`false`] if it's an - /// [IPv4 address]. + /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html - /// [IPv4 address]: #variant.V4 /// [IPv6 address]: #variant.V6 /// /// # Examples diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 3b4808fee2515..9fcb93e2032b3 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -21,7 +21,7 @@ //! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses //! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] //! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses -//! * [`ToSocketAddr`] is a trait that used for generic address resolution interacting +//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting //! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] //! * Other types are return or parameter types for various methods in this module //! @@ -33,7 +33,7 @@ //! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html //! [`TcpListener`]: ../../std/net/struct.TcpListener.html //! [`TcpStream`]: ../../std/net/struct.TcpStream.html -//! [`ToSocketAddr`]: ../../std/net/trait.ToSocketAddr.html +//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html //! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html #![stable(feature = "rust1", since = "1.0.0")] From e87dd42cfe3dc384cceb3c8385f7551c3af8edaa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 27 Mar 2017 13:06:56 -0700 Subject: [PATCH 309/662] appveyor: Downgrade MinGW to 6.2.0 It looks like the 6.3.0 MinGW comes with a gdb which has issues (#40184) that an attempted workaround (#40777) does not actually fix (#40835). The original motivation for upgradin MinGW was to fix build flakiness (#40546) due to newer builds not exhibiting the same bug, so let's hope that 6.2.0 isn't too far back in time and still contains the fix we need. Closes #40835 --- appveyor.yml | 8 ++++---- src/tools/compiletest/src/procsrv.rs | 20 ++------------------ 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0f4d053b6cfeb..68b2a239aff1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -46,13 +46,13 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -71,14 +71,14 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 DEPLOY: 1 diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index f55667f93c031..3d8f2296236a2 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -58,24 +58,8 @@ pub fn run(lib_path: &str, let mut cmd = Command::new(prog); cmd.args(args) .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - // Why oh why do we sometimes make a pipe and sometimes inherit the stdin - // stream, well that's an excellent question! In theory it should suffice to - // always create a pipe here and be done with it. Unfortunately though - // there's apparently something odd with the gdb that comes with gcc 6.3.0 - // on MinGW. Tracked at rust-lang/rust#40184 when stdin is piped here - // (unconditionally) then all gdb tests will fail on MinGW when using gcc - // 6.3.0. WHen using an inherited stdin though they happen to all work! - // - // As to why this fixes the issue, well, I have no idea. If you can remove - // this branch and unconditionally use `piped` and it gets past @bors please - // feel free to send a PR! - if input.is_some() || !cfg!(windows) { - cmd.stdin(Stdio::piped()); - } else { - cmd.stdin(Stdio::inherit()); - } + .stderr(Stdio::piped()) + .stdin(Stdio::piped()); add_target_env(&mut cmd, lib_path, aux_path); for (key, val) in env { From 4806f01d7c1f35a1b6f675ff099b86ec6e6c1540 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Mon, 27 Mar 2017 16:34:13 -0400 Subject: [PATCH 310/662] Fix tidy errors and simplify example --- src/libstd/io/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 773b0964b4269..1b0c992ba0976 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -145,16 +145,14 @@ //! # } //! ``` //! -//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main`). -//! Instead, you can `match` on the return value to catch any possible errors: -//! +//! Note that you cannot use the `?` operator in functions that do not return +//! a `Result` (e.g. `main`). Instead, you can call `.unwrap()` or `match` +//! on the return value to catch any possible errors: +//! //! ``` //! let mut input = String::new(); -//! -//! match io::stdin().read_line(&mut input) { -//! Err(why) => panic!("Failed to read input: {}", why.description()), -//! Ok(_) => println!("You typed: {}", input.trim()), -//! } +//! +//! io::stdin().read_line(&mut input).unwrap(); //! ``` //! //! And a very common source of output is standard output: From 434e601446cfb8fd97731f94aa690528ebef4da0 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 27 Mar 2017 16:04:56 -0400 Subject: [PATCH 311/662] Update various book modules This includes an important fix for rustc contributors in https://github.com/rust-lang/book/pull/571 I'm going to update the other ones as well here while we're at it; no need to spam PRs. --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index 9bd223ca406b1..a2c56870d4dc5 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 9bd223ca406b1170a24942d6474f9e8a56f4a420 +Subproject commit a2c56870d4dc589237102cc5e0fe7b9ebd0d14a1 diff --git a/src/doc/nomicon b/src/doc/nomicon index d08fe97d12b41..616b98444ff4e 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit d08fe97d12b41c1ed8cc7701e545864132783941 +Subproject commit 616b98444ff4eb5260deee95ee3e090dfd98b947 diff --git a/src/doc/reference b/src/doc/reference index 516549972d61c..acedc32cacae8 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 516549972d61c8946542d1a34afeae97167ff77b +Subproject commit acedc32cacae80cf2f4925753a4ce7f7ffd7c86a From da74e865b5a2400fb44660f989008208eb25d538 Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 27 Mar 2017 16:14:13 -0600 Subject: [PATCH 312/662] Review request changes --- src/libcollections/str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index d4480ce77d646..34563e310df3b 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -11,10 +11,10 @@ //! Unicode string slices. //! //! The `&str` type is one of the two main string types, the other being `String`. -//! Unlike its `String` counterpart, its contents are borrowed and therefore -//! cannot be moved someplace else. +//! Unlike its `String` counterpart, its contents are borrowed. //! //! # Basic Usage +//! //! A basic string declaration of `&str` type: //! //! ``` @@ -27,7 +27,7 @@ //! We can explicitly specify `hello_world`'s lifetime as well: //! //! ``` -//! let hello_world:&'static str = "Hello, world!"; +//! let hello_world: &'static str = "Hello, world!"; //! ``` //! //! *[See also the `str` primitive type](../../std/primitive.str.html).* From c963d613a2275d5c9b31cd7124dda2f2af61deb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Mar 2017 17:15:16 -0700 Subject: [PATCH 313/662] Simplify error output --- src/libsyntax/parse/parser.rs | 17 ++++++----------- src/test/ui/did_you_mean/issue-40006.stderr | 10 +++------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a19339f8cc1c1..2603b3302c610 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4708,26 +4708,21 @@ impl<'a> Parser<'a> { if let Err(mut bang_err) = bang_err { // Given this code `pub path(`, it seems like this is not setting the // visibility of a macro invocation, but rather a mistyped method declaration. - // Keep the macro diagnostic, but also provide a hint that `fn` might be - // missing. Don't complain about the missing `!` as a separate diagnostic, add - // label in the appropriate place as part of one unified diagnostic. + // Create a diagnostic pointing out that `fn` is missing. // // x | pub path(&self) { - // | ^^^- - expected `!` here for a macro invocation - // | | - // | did you mean to write `fn` here for a method declaration? + // | ^ missing `fn` for method declaration + err.cancel(); bang_err.cancel(); - err.span_label(self.span, &"expected `!` here for a macro invocation"); // pub path( // ^^ `sp` below will point to this let sp = mk_sp(prev_span.hi, self.prev_span.lo); - err.span_label(sp, - &"did you mean to write `fn` here for a method declaration?"); + err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method declaration"); + err.span_label(sp, &"missing `fn`"); } return Err(err); - } else if let Err(bang_err) = bang_err { - return Err(bang_err); } // eat a matched-delimiter token tree: diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 93a0c58f91a57..460958027ad0f 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,12 +1,8 @@ -error: can't qualify macro invocation with `pub` - --> $DIR/issue-40006.rs:14:5 +error: missing `fn` for method declaration + --> $DIR/issue-40006.rs:14:8 | 14 | pub hello_method(&self) { - | ^^^- - expected `!` here for a macro invocation - | | - | did you mean to write `fn` here for a method declaration? - | - = help: try adjusting the macro to put `pub` inside the invocation + | ^ missing `fn` error: aborting due to previous error From b477682dca3343eb89a467f0d3c73986a53d49d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 25 Mar 2017 19:06:19 -0700 Subject: [PATCH 314/662] Fix unittests --- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax_pos/lib.rs | 4 ++-- src/test/ui/token/bounds-obj-parens.stderr | 1 + src/test/ui/token/issue-10636-2.stderr | 1 + src/test/ui/token/macro-incomplete-parse.stderr | 1 + src/test/ui/token/trailing-plus-in-bounds.stderr | 3 ++- 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4076368c180b6..8177d738dc834 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -571,7 +571,7 @@ impl<'a> Parser<'a> { label_sp }; err.span_label(sp, &label_exp); - if label_sp != self.span { + if !sp.source_equal(&self.span) { err.span_label(self.span, &"unexpected token"); } Err(err) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 07494ff904e95..0662c1c9cfdc8 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -81,8 +81,8 @@ impl Span { /// Returns a new span representing the next character after the end-point of this span pub fn next_point(self) -> Span { - let lo = BytePos(cmp::max(self.hi.0, self.lo.0 + 1)); - Span { lo: lo, hi: lo, expn_id: self.expn_id} + let lo = cmp::max(self.hi.0, self.lo.0 + 1); + Span { lo: BytePos(lo), hi: BytePos(lo + 1), expn_id: self.expn_id} } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr index ebee363f278e2..4d60be15ecaf0 100644 --- a/src/test/ui/token/bounds-obj-parens.stderr +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -5,3 +5,4 @@ error: expected one of `!` or `::`, found `` | ^^^^ expected one of `!` or `::` here error: aborting due to previous error + diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr index 183ad30c4ef47..b0bae1248b969 100644 --- a/src/test/ui/token/issue-10636-2.stderr +++ b/src/test/ui/token/issue-10636-2.stderr @@ -25,3 +25,4 @@ error: expected expression, found `)` error: main function not found error: aborting due to 4 previous errors + diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr index bea00a6444c47..f23d97586b843 100644 --- a/src/test/ui/token/macro-incomplete-parse.stderr +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -29,3 +29,4 @@ note: caused by the macro expansion here; the usage of `ignored_pat!` is likely | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors + diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr index 74caf8f5c2b36..c765a434b8ac6 100644 --- a/src/test/ui/token/trailing-plus-in-bounds.stderr +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -1,7 +1,8 @@ error: expected one of `!` or `::`, found `` - --> ../../src/test/ui/token/trailing-plus-in-bounds.rs:19:1 + --> $DIR/trailing-plus-in-bounds.rs:19:1 | 19 | FAIL | ^^^^ expected one of `!` or `::` here error: aborting due to previous error + From 756f2248f73d2ea2703a65855c52086a1262a290 Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 27 Mar 2017 23:55:03 -0400 Subject: [PATCH 315/662] Adding links for Atomics docs #29377 --- src/libcore/sync/atomic.rs | 104 +++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 743e3c41170a3..c3e7c9b7c989c 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -15,27 +15,37 @@ //! types. //! //! This module defines atomic versions of a select number of primitive -//! types, including `AtomicBool`, `AtomicIsize`, and `AtomicUsize`. +//! types, including [`AtomicBool`], [`AtomicIsize`], and [`AtomicUsize`]. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! -//! Each method takes an `Ordering` which represents the strength of +//! [`AtomicBool`]: struct.AtomicBool.html +//! [`AtomicIsize`]: struct.AtomicIsize.html +//! [`AtomicUsize`]: struct.AtomicUsize.html +//! +//! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as [LLVM atomic orderings][1]. For more information see the [nomicon][2]. //! +//! [`Ordering`]: enum.Ordering.html +//! //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations //! [2]: ../../../nomicon/atomics.html //! -//! Atomic variables are safe to share between threads (they implement `Sync`) +//! Atomic variables are safe to share between threads (they implement [`Sync`]) //! but they do not themselves provide the mechanism for sharing and follow the //! [threading model](../../../std/thread/index.html#the-threading-model) of rust. -//! The most common way to share an atomic variable is to put it into an `Arc` (an +//! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an //! atomically-reference-counted shared pointer). //! +//! [`Sync`]: ../../marker/trait.Sync.html +//! [arc]: ../struct.Arc.html +//! //! Most atomic types may be stored in static variables, initialized using -//! the provided static initializers like `ATOMIC_BOOL_INIT`. Atomic statics +//! the provided static initializers like [`ATOMIC_BOOL_INIT`]. Atomic statics //! are often used for lazy global initialization. //! +//! [`ATOMIC_BOOL_INIT`]: constant.ATOMIC_BOOL_INIT.html //! //! # Examples //! @@ -149,21 +159,26 @@ unsafe impl Sync for AtomicPtr {} #[derive(Copy, Clone, Debug)] pub enum Ordering { /// No ordering constraints, only atomic operations. Corresponds to LLVM's - /// `Monotonic` ordering. + /// [`Monotonic`][1] ordering. + /// [1]: http://llvm.org/docs/Atomics.html#monotonic #[stable(feature = "rust1", since = "1.0.0")] Relaxed, /// When coupled with a store, all previous writes become visible - /// to the other threads that perform a load with `Acquire` ordering + /// to the other threads that perform a load with [`Acquire`][1] ordering /// on the same value. + /// [1]: http://llvm.org/docs/Atomics.html#acquire #[stable(feature = "rust1", since = "1.0.0")] Release, /// When coupled with a load, all subsequent loads will see data - /// written before a store with `Release` ordering on the same value + /// written before a store with [`Release`][1] ordering on the same value /// in other threads. + /// [1]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] Acquire, - /// When coupled with a load, uses `Acquire` ordering, and with a store - /// `Release` ordering. + /// When coupled with a load, uses [`Acquire`][1] ordering, and with a store + /// [`Release`][2] ordering. + /// [1]: http://llvm.org/docs/Atomics.html#acquire + /// [2]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] AcqRel, /// Like `AcqRel` with the additional guarantee that all threads see all @@ -176,7 +191,8 @@ pub enum Ordering { __Nonexhaustive, } -/// An `AtomicBool` initialized to `false`. +/// An [`AtomicBool`] initialized to `false`. +/// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); @@ -241,7 +257,7 @@ impl AtomicBool { /// Loads a value from the bool. /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering + /// `load()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// # Panics @@ -250,7 +266,7 @@ impl AtomicBool { /// /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.Release + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// /// # Examples /// @@ -269,7 +285,7 @@ impl AtomicBool { /// Stores a value into the bool. /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering + /// `store()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -287,7 +303,10 @@ impl AtomicBool { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, val: bool, order: Ordering) { @@ -298,7 +317,7 @@ impl AtomicBool { /// Stores a value into the bool, returning the old value. /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering + /// `swap()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -324,7 +343,7 @@ impl AtomicBool { /// The return value is always the previous value. If it is equal to `current`, then the value /// was updated. /// - /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory + /// `compare_and_swap()` also takes an [`Ordering`] argument which describes the memory /// ordering of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -356,7 +375,7 @@ impl AtomicBool { /// The return value is a result indicating whether the new value was written and containing /// the previous value. On success this value is guaranteed to be equal to `current`. /// - /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory + /// `compare_exchange()` takes two [`Ordering`] arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the /// operation succeeds while the second describes the required ordering when the /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and must @@ -404,17 +423,18 @@ impl AtomicBool { /// Stores a value into the `bool` if the current value is the same as the `current` value. /// - /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the + /// Unlike [`compare_exchange()`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. /// - /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory + /// `compare_exchange_weak()` takes two [`Ordering`] arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the operation /// succeeds while the second describes the required ordering when the operation fails. The /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or /// weaker than the success ordering. /// + /// [`compare_exchange()`]: #method.compare_exchange /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release /// [`AcqRel`]: enum.Ordering.html#variant.Release @@ -645,7 +665,7 @@ impl AtomicPtr { /// Loads a value from the pointer. /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering + /// `load()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// # Panics @@ -674,7 +694,7 @@ impl AtomicPtr { /// Stores a value into the pointer. /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering + /// `store()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -694,7 +714,11 @@ impl AtomicPtr { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel + /// #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { @@ -705,7 +729,7 @@ impl AtomicPtr { /// Stores a value into the pointer, returning the old value. /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering + /// `swap()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -733,7 +757,7 @@ impl AtomicPtr { /// The return value is always the previous value. If it is equal to `current`, then the value /// was updated. /// - /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory + /// `compare_and_swap()` also takes an [`Ordering`] argument which describes the memory /// ordering of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -765,7 +789,7 @@ impl AtomicPtr { /// The return value is a result indicating whether the new value was written and containing /// the previous value. On success this value is guaranteed to be equal to `current`. /// - /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory + /// `compare_exchange()` takes two [`Ordering`] arguments to describe the memory /// ordering of this operation. The first describes the required ordering if /// the operation succeeds while the second describes the required ordering when /// the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] @@ -812,18 +836,18 @@ impl AtomicPtr { /// Stores a value into the pointer if the current value is the same as the `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the + /// Unlike [`compare_exchange()`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. /// - /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory + /// `compare_exchange_weak()` takes two [`Ordering`] arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the operation /// succeeds while the second describes the required ordering when the operation fails. The /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or /// weaker than the success ordering. /// - /// [`compare_exchange`]: #method.compare_exchange + /// [`compare_exchange()`]: #method.compare_exchange /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel @@ -962,7 +986,7 @@ macro_rules! atomic_int { /// Loads a value from the atomic integer. /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering of this + /// `load()` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. /// /// # Panics @@ -990,7 +1014,7 @@ macro_rules! atomic_int { /// Stores a value into the atomic integer. /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering of this + /// `store()` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. /// /// [`Ordering`]: enum.Ordering.html @@ -1008,7 +1032,11 @@ macro_rules! atomic_int { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel + /// #[inline] #[$stable] pub fn store(&self, val: $int_type, order: Ordering) { @@ -1017,7 +1045,7 @@ macro_rules! atomic_int { /// Stores a value into the atomic integer, returning the old value. /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this + /// `swap()` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. /// /// [`Ordering`]: enum.Ordering.html @@ -1043,7 +1071,7 @@ macro_rules! atomic_int { /// The return value is always the previous value. If it is equal to `current`, then the /// value was updated. /// - /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory + /// `compare_and_swap()` also takes an [`Ordering`] argument which describes the memory /// ordering of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -1083,7 +1111,7 @@ macro_rules! atomic_int { /// containing the previous value. On success this value is guaranteed to be equal to /// `current`. /// - /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory + /// `compare_exchange()` takes two [`Ordering`] arguments to describe the memory /// ordering of this operation. The first describes the required ordering if /// the operation succeeds while the second describes the required ordering when /// the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and @@ -1125,18 +1153,18 @@ macro_rules! atomic_int { /// Stores a value into the atomic integer if the current value is the same as the /// `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even + /// Unlike [`compare_exchange()`], this function is allowed to spuriously fail even /// when the comparison succeeds, which can result in more efficient code on some /// platforms. The return value is a result indicating whether the new value was /// written and containing the previous value. /// - /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory + /// `compare_exchange_weak()` takes two [`Ordering`] arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the /// operation succeeds while the second describes the required ordering when the /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and /// must be equivalent or weaker than the success ordering. /// - /// [`compare_exchange`]: #method.compare_exchange + /// [`compare_exchange()`]: #method.compare_exchange /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel From b90936449b161f4aee5ff81bbb4906bf5a27f181 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Tue, 28 Mar 2017 17:43:01 +0300 Subject: [PATCH 316/662] libcore: sort_unstable: remove unnecessary loop. `other` is guaranteed to be less than `2 * len`. --- src/libcore/slice/sort.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 3612ee65bca0d..7065fdb79fc40 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -527,7 +527,9 @@ fn break_patterns(v: &mut [T]) { // we first take it modulo a power of two, and then decrease by `len` until it fits // into the range `[0, len - 1]`. let mut other = gen_usize() & (modulus - 1); - while other >= len { + + // `other` is guaranteed to be less than `2 * len`. + if other >= len { other -= len; } From cd2ec7eded8d65b88b4c2fdb26efe1b3c505bd6f Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Tue, 28 Mar 2017 13:27:46 -0400 Subject: [PATCH 317/662] add missing import --- src/libstd/io/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 1b0c992ba0976..32ead78f6cd58 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -150,6 +150,8 @@ //! on the return value to catch any possible errors: //! //! ``` +//! use std::io; +//! //! let mut input = String::new(); //! //! io::stdin().read_line(&mut input).unwrap(); From 08a80cbda6d505b845f4d857e8f5770df0ea162a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Mar 2017 01:01:23 +0100 Subject: [PATCH 318/662] Replace hoedown with pull in rustdoc --- src/Cargo.lock | 2 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/html/markdown.rs | 415 ++++++++++++++++++++++++-------- src/librustdoc/lib.rs | 1 + 4 files changed, 312 insertions(+), 107 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index a0b47f4f0b2bb..946818e7d2087 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -772,6 +772,8 @@ dependencies = [ "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.0.0", + "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1c479ce1d0157..2222077aae80b 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -26,6 +26,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } +pulldown-cmark = "0.0.8" [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c7c5aabab97ae..a745ccc822cda 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -30,9 +30,9 @@ use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; -use std::ffi::CString; +//use std::ffi::CString; use std::fmt::{self, Write}; -use std::slice; +//use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; use syntax::codemap::Span; @@ -43,6 +43,8 @@ use html::highlight; use html::escape::Escape; use test; +use pulldown_cmark::{self, Parser}; + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. @@ -53,7 +55,7 @@ pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); -const DEF_OUNIT: libc::size_t = 64; +/*const DEF_OUNIT: libc::size_t = 64; const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11; const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; @@ -179,8 +181,8 @@ extern { fn hoedown_document_free(md: *mut hoedown_document); fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; - fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, - n: libc::size_t); + /*fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, + n: libc::size_t);*/ fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); fn hoedown_buffer_free(b: *mut hoedown_buffer); @@ -191,7 +193,7 @@ impl hoedown_buffer { fn as_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.data, self.size as usize) } } -} +}*/ /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of @@ -226,8 +228,8 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, - html_flags: libc::c_uint) -> fmt::Result { - extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, + _html_flags: libc::c_uint) -> fmt::Result { + /*extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, lang: *const hoedown_buffer, data: *const hoedown_renderer_data, line: libc::size_t) { unsafe { @@ -422,76 +424,274 @@ pub fn render(w: &mut fmt::Formatter, } hoedown_buffer_free(ob); ret + }*/ + + fn block(parser: &mut Parser, lang: &str, buffer: &mut String) { + let mut origtext = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::CodeBlock(_)) => break, + pulldown_cmark::Event::Text(ref s) => { + origtext.push_str(s); + } + _ => {} + } + } else { + break + } + } + let origtext = origtext.trim_left(); + debug!("docblock: ==============\n{:?}\n=======", origtext); + let rendered = if lang.is_empty() || origtext.is_empty() { + false + } else { + if !LangString::parse(lang).rust { + /*(my_opaque.dfltblk)(ob, orig_text, lang, + opaque as *const hoedown_renderer_data, + line);*/ + // true + false + } else { + false + } + }; + + let lines = origtext.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); + let text = lines.collect::>().join("\n"); + if rendered { return } + PLAYGROUND.with(|play| { + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + let mut s = String::from("\n"); + let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { + if url.is_empty() { + return None; + } + let test = origtext.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }).collect::>().join("\n"); + let krate = krate.as_ref().map(|s| &**s); + let test = test::maketest(&test, krate, false, + &Default::default()); + let channel = if test.contains("#![feature(") { + "&version=nightly" + } else { + "" + }; + // These characters don't need to be escaped in a URI. + // FIXME: use a library function for percent encoding. + fn dont_escape(c: u8) -> bool { + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z') || + (b'0' <= c && c <= b'9') || + c == b'-' || c == b'_' || c == b'.' || + c == b'~' || c == b'!' || c == b'\'' || + c == b'(' || c == b')' || c == b'*' + } + let mut test_escaped = String::new(); + for b in test.bytes() { + if dont_escape(b) { + test_escaped.push(char::from(b)); + } else { + write!(test_escaped, "%{:02X}", b).unwrap(); + } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) + }); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + buffer.push_str(&s); + }); } -} -pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { - extern fn block(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - lang: *const hoedown_buffer, - data: *const hoedown_renderer_data, - line: libc::size_t) { - unsafe { - if text.is_null() { return } - let block_info = if lang.is_null() { - LangString::all_false() + fn header(parser: &mut Parser, level: i32, toc_builder: &mut Option, + buffer: &mut String) { + let mut ret = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Header(_)) => break, + pulldown_cmark::Event::Text(ref s) => { + ret.push_str(s); + } + _ => {} + } } else { - let lang = (*lang).as_bytes(); - let s = str::from_utf8(lang).unwrap(); - LangString::parse(s) - }; - if !block_info.rust { return } - let text = (*text).as_bytes(); - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - let text = str::from_utf8(text).unwrap(); - let lines = text.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }); - let text = lines.collect::>().join("\n"); - let line = tests.get_line() + line; - let filename = tests.get_filename(); - tests.add_test(text.to_owned(), - block_info.should_panic, block_info.no_run, - block_info.ignore, block_info.test_harness, - block_info.compile_fail, block_info.error_codes, - line, filename); + break + } } + + let id = ret.clone(); + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // + // This is a terrible hack working around how hoedown gives us rendered + // html for text rather than the raw text. + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); + + let id = derive_id(id); + + let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, ret.clone(), id.clone())) + }); + + // Render the HTML + buffer.push_str(&format!("\ + {sec}{}", + ret, lvl = level, id = id, sec = sec)); } - extern fn header(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data, - _: libc::size_t) { - unsafe { - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - if text.is_null() { - tests.register_header("", level as u32); + fn codespan(parser: &mut Parser, buffer: &mut String) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Code) => break, + pulldown_cmark::Event::Text(ref s) => { + content.push_str(s); + } + _ => {} + } } else { - let text = (*text).as_bytes(); - let text = str::from_utf8(text).unwrap(); - tests.register_header(text, level as u32); + break } } + buffer.push_str(&format!("{}", Escape(&collapse_whitespace(&content)))); } - tests.set_position(position); - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let renderer = hoedown_html_renderer_new(0, 0); - (*renderer).blockcode = Some(block); - (*renderer).header = Some(header); - (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque - = tests as *mut _ as *mut libc::c_void; + let mut toc_builder = if print_toc { + Some(TocBuilder::new()) + } else { + None + }; + let mut buffer = String::new(); + let mut parser = Parser::new(s); + loop { + let next_event = parser.next(); + if let Some(event) = next_event { + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { + block(&mut parser, &*s, &mut buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + header(&mut parser, level, &mut toc_builder, &mut buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { + codespan(&mut parser, &mut buffer); + } + _ => {} + } + } else { + break + } + } + let mut ret = toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, doc.as_ptr(), - doc.len() as libc::size_t); - hoedown_document_free(document); + if ret.is_ok() { + ret = w.write_str(&buffer); + } + ret +} - hoedown_html_renderer_free(renderer); - hoedown_buffer_free(ob); +pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { + tests.set_position(position); + + let mut parser = Parser::new(doc); + let mut prev_offset = 0; + let mut nb_lines = 0; + let mut register_header = None; + 'main: loop { + let next_event = parser.next(); + if let Some(event) = next_event { + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { + let block_info = if s.is_empty() { + LangString::all_false() + } else { + LangString::parse(&*s) + }; + let mut test_s = String::new(); + let mut offset = None; + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::CodeBlock(_)) => break, + pulldown_cmark::Event::Text(ref s) => { + test_s.push_str(s); + if offset.is_none() { + offset = Some(parser.get_offset()); + } + } + _ => {} + } + } else { + break 'main; + } + } + let offset = offset.unwrap_or(0); + let lines = test_s.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); + let text = lines.collect::>().join("\n"); + nb_lines += doc[prev_offset..offset].lines().count(); + let line = tests.get_line() + (nb_lines - 1); + let filename = tests.get_filename(); + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + prev_offset = offset; + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + register_header = Some(level as u32); + } + pulldown_cmark::Event::Text(ref s) if register_header.is_some() => { + let level = register_header.unwrap(); + if s.is_empty() { + tests.register_header("", level); + } else { + tests.register_header(s, level); + } + register_header = None; + } + _ => {} + } + } else { + break + } } } @@ -589,57 +789,58 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, HOEDOWN_HTML_ESCAPE) + render(fmt, md, false, /*HOEDOWN_HTML_ESCAPE*/0) } } pub fn plain_summary_line(md: &str) -> String { - extern fn link(_ob: *mut hoedown_buffer, - _link: *const hoedown_buffer, - _title: *const hoedown_buffer, - content: *const hoedown_buffer, - data: *const hoedown_renderer_data, - _: libc::size_t) -> libc::c_int - { - unsafe { - if !content.is_null() && (*content).size > 0 { - let ob = (*data).opaque as *mut hoedown_buffer; - hoedown_buffer_put(ob, (*content).data as *const libc::c_char, - (*content).size); - } - } - 1 + struct ParserWrapper<'a> { + inner: Parser<'a>, + is_in: isize, + is_first: bool, } - extern fn normal_text(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - data: *const hoedown_renderer_data, - _: libc::size_t) - { - unsafe { - let ob = (*data).opaque as *mut hoedown_buffer; - hoedown_buffer_put(ob, (*text).data as *const libc::c_char, - (*text).size); + impl<'a> Iterator for ParserWrapper<'a> { + type Item = String; + + fn next(&mut self) -> Option { + let next_event = self.inner.next(); + if next_event.is_none() { + return None + } + let next_event = next_event.unwrap(); + let (ret, is_in) = match next_event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => (None, 1), + pulldown_cmark::Event::Start( + pulldown_cmark::Tag::Link(_, ref t)) if !self.is_first => (Some(t.as_ref().to_owned()), 1), + pulldown_cmark::Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), + pulldown_cmark::Event::End(pulldown_cmark::Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), + pulldown_cmark::Event::End(pulldown_cmark::Tag::Paragraph) => (None, -1), + _ => (None, 0), + }; + if is_in > 0 || (is_in < 0 && self.is_in > 0) { + self.is_in += is_in; + } + if ret.is_some() { + self.is_first = false; + ret + } else { + Some(String::new()) + } } } - - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed(); - let renderer: *mut hoedown_renderer = &mut plain_renderer; - (*renderer).opaque = ob as *mut libc::c_void; - (*renderer).link = Some(link); - (*renderer).normal_text = Some(normal_text); - - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, md.as_ptr(), - md.len() as libc::size_t); - hoedown_document_free(document); - let plain_slice = (*ob).as_bytes(); - let plain = str::from_utf8(plain_slice).unwrap_or("").to_owned(); - hoedown_buffer_free(ob); - plain + let mut s = String::with_capacity(md.len() * 3 / 2); + let mut p = ParserWrapper { + inner: Parser::new(md), + is_in: 0, + is_first: true, + }; + while let Some(t) = p.next() { + if !t.is_empty() { + s.push_str(&t); + } } + s } #[cfg(test)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 8dd03f6edc4d5..efb51bdf471f4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -48,6 +48,7 @@ extern crate test as testing; extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; +extern crate pulldown_cmark; extern crate serialize as rustc_serialize; // used by deriving From c9415eb98ff2a5cf679954e5eaf66274a24db1ee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Mar 2017 23:56:00 +0100 Subject: [PATCH 319/662] Remains to fix tables --- src/librustdoc/html/markdown.rs | 94 ++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a745ccc822cda..a36e99e80dfe9 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -43,7 +43,7 @@ use html::highlight; use html::escape::Escape; use test; -use pulldown_cmark::{self, Parser}; +use pulldown_cmark::{self, Event, Parser}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered @@ -467,7 +467,7 @@ pub fn render(w: &mut fmt::Formatter, PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output - let mut s = String::from("\n"); + buffer.push('\n'); let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { if url.is_empty() { return None; @@ -506,12 +506,11 @@ pub fn render(w: &mut fmt::Formatter, url, test_escaped, channel )) }); - s.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - buffer.push_str(&s); + buffer.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); }); } @@ -587,29 +586,84 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", Escape(&collapse_whitespace(&content)))); } - let mut toc_builder = if print_toc { - Some(TocBuilder::new()) - } else { - None - }; - let mut buffer = String::new(); - let mut parser = Parser::new(s); - loop { - let next_event = parser.next(); + fn link(parser: &mut Parser, buffer: &mut String, url: &str, mut title: String) { + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Link(_, _)) => break, + pulldown_cmark::Event::Text(ref s) => { + title.push_str(s); + } + _ => {} + } + } else { + break + } + } + buffer.push_str(&format!("{}", url, title)); + } + + fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Paragraph) => break, + pulldown_cmark::Event::Text(ref s) => { + content.push_str(s); + } + x => { + looper(parser, &mut content, Some(x), toc_builder); + } + } + } else { + break + } + } + buffer.push_str(&format!("

{}

", content)); + } + + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, + toc_builder: &mut Option) -> bool { if let Some(event) = next_event { match event { pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { - block(&mut parser, &*s, &mut buffer); + block(parser, &*s, buffer); } pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { - header(&mut parser, level, &mut toc_builder, &mut buffer); + header(parser, level, toc_builder, buffer); } pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { - codespan(&mut parser, &mut buffer); + codespan(parser, buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => { + paragraph(parser, buffer, toc_builder); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link(ref url, ref t)) => { + link(parser, buffer, url, t.as_ref().to_owned()); } _ => {} } + true } else { + false + } + } + + let mut toc_builder = if print_toc { + Some(TocBuilder::new()) + } else { + None + }; + let mut buffer = String::new(); + let mut parser = Parser::new(s); + loop { + let next_event = parser.next(); + if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder) { break } } From b96fef8411f26e357e31b8c1b584b6d994efafaa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 10 Mar 2017 14:06:24 +0100 Subject: [PATCH 320/662] End of pulldown switch and remove completely hoedown --- .gitmodules | 4 - src/librustdoc/Cargo.toml | 1 - src/librustdoc/build.rs | 29 -- src/librustdoc/html/markdown.rs | 661 ++++++++++---------------------- src/librustdoc/html/render.rs | 8 +- src/librustdoc/markdown.rs | 2 +- src/rt/hoedown | 1 - 7 files changed, 216 insertions(+), 490 deletions(-) delete mode 100644 src/librustdoc/build.rs delete mode 160000 src/rt/hoedown diff --git a/.gitmodules b/.gitmodules index d2e1fb868a999..53d1787492409 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,10 +5,6 @@ [submodule "src/compiler-rt"] path = src/compiler-rt url = https://github.com/rust-lang/compiler-rt.git -[submodule "src/rt/hoedown"] - path = src/rt/hoedown - url = https://github.com/rust-lang/hoedown.git - branch = rust-2015-09-21-do-not-delete [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 2222077aae80b..ff18daa7aa098 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -2,7 +2,6 @@ authors = ["The Rust Project Developers"] name = "rustdoc" version = "0.0.0" -build = "build.rs" [lib] name = "rustdoc" diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs deleted file mode 100644 index 9fa6406c1d8b6..0000000000000 --- a/src/librustdoc/build.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate build_helper; -extern crate gcc; - -fn main() { - let src_dir = std::path::Path::new("../rt/hoedown/src"); - build_helper::rerun_if_changed_anything_in_dir(src_dir); - let mut cfg = gcc::Config::new(); - cfg.file("../rt/hoedown/src/autolink.c") - .file("../rt/hoedown/src/buffer.c") - .file("../rt/hoedown/src/document.c") - .file("../rt/hoedown/src/escape.c") - .file("../rt/hoedown/src/html.c") - .file("../rt/hoedown/src/html_blocks.c") - .file("../rt/hoedown/src/html_smartypants.c") - .file("../rt/hoedown/src/stack.c") - .file("../rt/hoedown/src/version.c") - .include(src_dir) - .compile("libhoedown.a"); -} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a36e99e80dfe9..9ae6c443f9e06 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -26,7 +26,7 @@ #![allow(non_camel_case_types)] -use libc; +//use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; @@ -43,158 +43,19 @@ use html::highlight; use html::escape::Escape; use test; -use pulldown_cmark::{self, Event, Parser}; +use pulldown_cmark::{self, Event, Parser, Tag}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. -pub struct Markdown<'a>(pub &'a str); +// The second parameter is whether we need a shorter version or not. +pub struct Markdown<'a>(pub &'a str, pub bool); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); -/*const DEF_OUNIT: libc::size_t = 64; -const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11; -const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; -const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; -const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; -const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; -const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; -const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; -const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1; - -const HOEDOWN_EXTENSIONS: libc::c_uint = - HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | - HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | - HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_SUPERSCRIPT | - HOEDOWN_EXT_FOOTNOTES; - -enum hoedown_document {} - -type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_renderer_data, - libc::size_t); - -type blockquotefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - libc::c_int, *const hoedown_renderer_data, - libc::size_t); - -type blockhtmlfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t) -> libc::c_int; - -type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t) -> libc::c_int; - -type entityfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -#[repr(C)] -struct hoedown_renderer_data { - opaque: *mut libc::c_void, -} - -#[repr(C)] -struct hoedown_renderer { - opaque: *mut libc::c_void, - - blockcode: Option, - blockquote: Option, - header: Option, - - other_block_level_callbacks: [libc::size_t; 11], - - blockhtml: Option, - - /* span level callbacks - NULL or return 0 prints the span verbatim */ - autolink: libc::size_t, // unused - codespan: Option, - other_span_level_callbacks_1: [libc::size_t; 7], - link: Option, - other_span_level_callbacks_2: [libc::size_t; 6], - - /* low level callbacks - NULL copies input directly into the output */ - entity: Option, - normal_text: Option, - - /* header and footer */ - other_callbacks: [libc::size_t; 2], -} - -#[repr(C)] -struct hoedown_html_renderer_state { - opaque: *mut libc::c_void, - toc_data: html_toc_data, - flags: libc::c_uint, - link_attributes: Option, -} - -#[repr(C)] -struct html_toc_data { - header_count: libc::c_int, - current_level: libc::c_int, - level_offset: libc::c_int, - nesting_level: libc::c_int, -} - -struct MyOpaque { - dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_renderer_data, - libc::size_t), - toc_builder: Option, -} - -#[repr(C)] -struct hoedown_buffer { - data: *const u8, - size: libc::size_t, - asize: libc::size_t, - unit: libc::size_t, -} - -extern { - fn hoedown_html_renderer_new(render_flags: libc::c_uint, - nesting_level: libc::c_int) - -> *mut hoedown_renderer; - fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer); - - fn hoedown_document_new(rndr: *const hoedown_renderer, - extensions: libc::c_uint, - max_nesting: libc::size_t) -> *mut hoedown_document; - fn hoedown_document_render(doc: *mut hoedown_document, - ob: *mut hoedown_buffer, - document: *const u8, - doc_size: libc::size_t); - fn hoedown_document_free(md: *mut hoedown_document); - - fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; - /*fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, - n: libc::size_t);*/ - fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); - fn hoedown_buffer_free(b: *mut hoedown_buffer); - -} - -// hoedown_buffer helpers -impl hoedown_buffer { - fn as_bytes(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data, self.size as usize) } - } -}*/ - /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of /// `s` that should be used in tests. (None for lines that should be @@ -228,213 +89,15 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, - _html_flags: libc::c_uint) -> fmt::Result { - /*extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, - lang: *const hoedown_buffer, data: *const hoedown_renderer_data, - line: libc::size_t) { - unsafe { - if orig_text.is_null() { return } - - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque); - let text = (*orig_text).as_bytes(); - let origtext = str::from_utf8(text).unwrap(); - let origtext = origtext.trim_left(); - debug!("docblock: ==============\n{:?}\n=======", text); - let rendered = if lang.is_null() || origtext.is_empty() { - false - } else { - let rlang = (*lang).as_bytes(); - let rlang = str::from_utf8(rlang).unwrap(); - if !LangString::parse(rlang).rust { - (my_opaque.dfltblk)(ob, orig_text, lang, - opaque as *const hoedown_renderer_data, - line); - true - } else { - false - } - }; - - let lines = origtext.lines().filter(|l| { - stripped_filtered_line(*l).is_none() - }); - let text = lines.collect::>().join("\n"); - if rendered { return } - PLAYGROUND.with(|play| { - // insert newline to clearly separate it from the - // previous block so we can shorten the html output - let mut s = String::from("\n"); - let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { - if url.is_empty() { - return None; - } - let test = origtext.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }).collect::>().join("\n"); - let krate = krate.as_ref().map(|s| &**s); - let test = test::maketest(&test, krate, false, - &Default::default()); - let channel = if test.contains("#![feature(") { - "&version=nightly" - } else { - "" - }; - // These characters don't need to be escaped in a URI. - // FIXME: use a library function for percent encoding. - fn dont_escape(c: u8) -> bool { - (b'a' <= c && c <= b'z') || - (b'A' <= c && c <= b'Z') || - (b'0' <= c && c <= b'9') || - c == b'-' || c == b'_' || c == b'.' || - c == b'~' || c == b'!' || c == b'\'' || - c == b'(' || c == b')' || c == b'*' - } - let mut test_escaped = String::new(); - for b in test.bytes() { - if dont_escape(b) { - test_escaped.push(char::from(b)); - } else { - write!(test_escaped, "%{:02X}", b).unwrap(); - } - } - Some(format!( - r#"Run"#, - url, test_escaped, channel - )) - }); - s.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - let output = CString::new(s).unwrap(); - hoedown_buffer_puts(ob, output.as_ptr()); - }) - } - } - - extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data, - _: libc::size_t) { - // hoedown does this, we may as well too - unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } - - // Extract the text provided - let s = if text.is_null() { - "".to_owned() - } else { - let s = unsafe { (*text).as_bytes() }; - str::from_utf8(&s).unwrap().to_owned() - }; - - // Discard '', '' tags and some escaped characters, - // transform the contents of the header into a hyphenated string - // without non-alphanumeric characters other than '-' and '_'. - // - // This is a terrible hack working around how hoedown gives us rendered - // html for text rather than the raw text. - let mut id = s.clone(); - let repl_sub = vec!["", "", "", "", - "", "", - "<", ">", "&", "'", """]; - for sub in repl_sub { - id = id.replace(sub, ""); - } - let id = id.chars().filter_map(|c| { - if c.is_alphanumeric() || c == '-' || c == '_' { - if c.is_ascii() { - Some(c.to_ascii_lowercase()) - } else { - Some(c) - } - } else if c.is_whitespace() && c.is_ascii() { - Some('-') - } else { - None - } - }).collect::(); - - let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; - let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; - - let id = derive_id(id); - - let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { - format!("{} ", builder.push(level as u32, s.clone(), id.clone())) - }); - - // Render the HTML - let text = format!("\ - {sec}{}", - s, lvl = level, id = id, sec = sec); - - let text = CString::new(text).unwrap(); - unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } - } - - extern fn codespan( - ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - _: *const hoedown_renderer_data, - _: libc::size_t - ) -> libc::c_int { - let content = if text.is_null() { - "".to_owned() - } else { - let bytes = unsafe { (*text).as_bytes() }; - let s = str::from_utf8(bytes).unwrap(); - collapse_whitespace(s) - }; - - let content = format!("{}", Escape(&content)); - let element = CString::new(content).unwrap(); - unsafe { hoedown_buffer_puts(ob, element.as_ptr()); } - // Return anything except 0, which would mean "also print the code span verbatim". - 1 - } - - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let renderer = hoedown_html_renderer_new(html_flags, 0); - let mut opaque = MyOpaque { - dfltblk: (*renderer).blockcode.unwrap(), - toc_builder: if print_toc {Some(TocBuilder::new())} else {None} - }; - (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque - = &mut opaque as *mut _ as *mut libc::c_void; - (*renderer).blockcode = Some(block); - (*renderer).header = Some(header); - (*renderer).codespan = Some(codespan); - - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, s.as_ptr(), - s.len() as libc::size_t); - hoedown_document_free(document); - - hoedown_html_renderer_free(renderer); - - let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { - write!(w, "", builder.into_toc()) - }); - - if ret.is_ok() { - let buf = (*ob).as_bytes(); - ret = w.write_str(str::from_utf8(buf).unwrap()); - } - hoedown_buffer_free(ob); - ret - }*/ - - fn block(parser: &mut Parser, lang: &str, buffer: &mut String) { + shorter: bool) -> fmt::Result { + fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); loop { let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::CodeBlock(_)) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { origtext.push_str(s); } _ => {} @@ -445,25 +108,21 @@ pub fn render(w: &mut fmt::Formatter, } let origtext = origtext.trim_left(); debug!("docblock: ==============\n{:?}\n=======", origtext); - let rendered = if lang.is_empty() || origtext.is_empty() { - false - } else { - if !LangString::parse(lang).rust { - /*(my_opaque.dfltblk)(ob, orig_text, lang, - opaque as *const hoedown_renderer_data, - line);*/ - // true - false - } else { - false - } - }; let lines = origtext.lines().filter(|l| { stripped_filtered_line(*l).is_none() }); let text = lines.collect::>().join("\n"); - if rendered { return } + let block_info = if lang.is_empty() { + LangString::all_false() + } else { + LangString::parse(lang) + }; + if !block_info.rust { + buffer.push_str(&format!("
{}
", + lang, text)); + return + } PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output @@ -521,9 +180,8 @@ pub fn render(w: &mut fmt::Formatter, let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Header(_)) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Header(_)) => break, + Event::Text(ref s) => { ret.push_str(s); } _ => {} @@ -561,8 +219,8 @@ pub fn render(w: &mut fmt::Formatter, }); // Render the HTML - buffer.push_str(&format!("\ - {sec}{}", + buffer.push_str(&format!("\ + {sec}{}", ret, lvl = level, id = id, sec = sec)); } @@ -572,9 +230,8 @@ pub fn render(w: &mut fmt::Formatter, let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Code) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Code) => break, + Event::Text(ref s) => { content.push_str(s); } _ => {} @@ -591,9 +248,8 @@ pub fn render(w: &mut fmt::Formatter, let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Link(_, _)) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Link(_, _)) => break, + Event::Text(ref s) => { title.push_str(s); } _ => {} @@ -605,19 +261,19 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", url, title)); } - fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option) { + fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { let mut content = String::new(); loop { let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Paragraph) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Paragraph) => break, + Event::Text(ref s) => { content.push_str(s); } x => { - looper(parser, &mut content, Some(x), toc_builder); + looper(parser, &mut content, Some(x), toc_builder, shorter); } } } else { @@ -627,28 +283,135 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("

{}

", content)); } + fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell) => break, + Event::Text(ref s) => { + content.push_str(s); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } else { + break + } + } + buffer.push_str(&format!("{}", content.trim())); + } + + fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } else { + break + } + } + buffer.push_str(&format!("{}", content)); + } + + fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } else { + break + } + } + if content.is_empty() { + return + } + buffer.push_str(&format!("{}", content.replace("td>", "th>"))); + } + + fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + let mut rows = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableHead) => { + head(parser, &mut content, toc_builder, shorter); + } + Event::Start(Tag::TableRow) => { + row(parser, &mut rows, toc_builder, shorter); + } + _ => {} + } + } else { + break + } + } + buffer.push_str(&format!("{}{}
", + content, + if shorter || rows.is_empty() { + String::new() + } else { + format!("{}", rows) + })); + } + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option) -> bool { + toc_builder: &mut Option, shorter: bool) -> bool { if let Some(event) = next_event { match event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { - block(parser, &*s, buffer); + Event::Start(Tag::CodeBlock(lang)) => { + block(parser, buffer, &*lang); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + Event::Start(Tag::Header(level)) => { header(parser, level, toc_builder, buffer); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { + Event::Start(Tag::Code) => { codespan(parser, buffer); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder); + Event::Start(Tag::Paragraph) => { + paragraph(parser, buffer, toc_builder, shorter); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link(ref url, ref t)) => { + Event::Start(Tag::Link(ref url, ref t)) => { link(parser, buffer, url, t.as_ref().to_owned()); } + Event::Start(Tag::Table(_)) => { + table(parser, buffer, toc_builder, shorter); + } _ => {} } - true + shorter == false } else { false } @@ -660,10 +423,10 @@ pub fn render(w: &mut fmt::Formatter, None }; let mut buffer = String::new(); - let mut parser = Parser::new(s); + let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); loop { let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder) { + if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter) { break } } @@ -684,67 +447,64 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Sp let mut prev_offset = 0; let mut nb_lines = 0; let mut register_header = None; - 'main: loop { - let next_event = parser.next(); - if let Some(event) = next_event { - match event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { - let block_info = if s.is_empty() { - LangString::all_false() - } else { - LangString::parse(&*s) - }; - let mut test_s = String::new(); - let mut offset = None; - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::CodeBlock(_)) => break, - pulldown_cmark::Event::Text(ref s) => { - test_s.push_str(s); - if offset.is_none() { - offset = Some(parser.get_offset()); - } + 'main: while let Some(event) = parser.next() { + match event { + Event::Start(Tag::CodeBlock(s)) => { + let block_info = if s.is_empty() { + LangString::all_false() + } else { + LangString::parse(&*s) + }; + if !block_info.rust { + continue + } + let mut test_s = String::new(); + let mut offset = None; + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { + test_s.push_str(s); + if offset.is_none() { + offset = Some(parser.get_offset()); } - _ => {} } - } else { - break 'main; + _ => {} } - } - let offset = offset.unwrap_or(0); - let lines = test_s.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }); - let text = lines.collect::>().join("\n"); - nb_lines += doc[prev_offset..offset].lines().count(); - let line = tests.get_line() + (nb_lines - 1); - let filename = tests.get_filename(); - tests.add_test(text.to_owned(), - block_info.should_panic, block_info.no_run, - block_info.ignore, block_info.test_harness, - block_info.compile_fail, block_info.error_codes, - line, filename); - prev_offset = offset; - } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { - register_header = Some(level as u32); - } - pulldown_cmark::Event::Text(ref s) if register_header.is_some() => { - let level = register_header.unwrap(); - if s.is_empty() { - tests.register_header("", level); } else { - tests.register_header(s, level); + break 'main; } - register_header = None; } - _ => {} + let offset = offset.unwrap_or(0); + let lines = test_s.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); + let text = lines.collect::>().join("\n"); + nb_lines += doc[prev_offset..offset].lines().count(); + let line = tests.get_line() + (nb_lines - 1); + let filename = tests.get_filename(); + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + prev_offset = offset; } - } else { - break + Event::Start(Tag::Header(level)) => { + register_header = Some(level as u32); + } + Event::Text(ref s) if register_header.is_some() => { + let level = register_header.unwrap(); + if s.is_empty() { + tests.register_header("", level); + } else { + tests.register_header(s, level); + } + register_header = None; + } + _ => {} } } } @@ -824,17 +584,17 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md) = *self; + let Markdown(md, shorter) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, 0) + render(fmt, md, false, shorter) } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, 0) + render(fmt, md, true, false) } } @@ -843,7 +603,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, /*HOEDOWN_HTML_ESCAPE*/0) + render(fmt, md, false, false) } } @@ -864,12 +624,13 @@ pub fn plain_summary_line(md: &str) -> String { } let next_event = next_event.unwrap(); let (ret, is_in) = match next_event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => (None, 1), - pulldown_cmark::Event::Start( - pulldown_cmark::Tag::Link(_, ref t)) if !self.is_first => (Some(t.as_ref().to_owned()), 1), - pulldown_cmark::Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - pulldown_cmark::Event::End(pulldown_cmark::Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), - pulldown_cmark::Event::End(pulldown_cmark::Tag::Paragraph) => (None, -1), + Event::Start(Tag::Paragraph) => (None, 1), + Event::Start(Tag::Link(_, ref t)) if !self.is_first => { + (Some(t.as_ref().to_owned()), 1) + } + Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), + Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), + Event::End(Tag::Paragraph) => (None, -1), _ => (None, 0), }; if is_in > 0 || (is_in < 0 && self.is_in > 0) { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5c94032c6b9cf..8c1416b809799 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1650,7 +1650,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin } else { format!("{}", &plain_summary_line(Some(s))) }; - write!(w, "
{}
", Markdown(&markdown))?; + write!(w, "
{}
", Markdown(&markdown, false))?; } Ok(()) } @@ -1683,7 +1683,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
{}
", - Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), false))?; } Ok(()) } @@ -1871,7 +1871,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value).to_string())), + docs = shorter(Some(&Markdown(doc_value, true).to_string())), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2901,7 +2901,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
{}
", Markdown(dox))?; + write!(w, "
{}
", Markdown(dox, false))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index c67e2fdc2b027..a048750279e26 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -94,7 +94,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text)) + format!("{}", Markdown(text, false)) }; let err = write!( diff --git a/src/rt/hoedown b/src/rt/hoedown deleted file mode 160000 index da282f1bb7277..0000000000000 --- a/src/rt/hoedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 From f6baea23bad46050e8f0840713c9d13a40edaf68 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 10 Mar 2017 18:35:15 +0100 Subject: [PATCH 321/662] Fix external doc errors --- src/libcore/result.rs | 2 +- src/tools/error_index_generator/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 6ec8a37dfa433..c46b0c1324de6 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -838,10 +838,10 @@ impl Result { /// /// assert_eq!(1909, good_year); /// assert_eq!(0, bad_year); + /// ``` /// /// [`parse`]: ../../std/primitive.str.html#method.parse /// [`FromStr`]: ../../std/str/trait.FromStr.html - /// ``` #[inline] #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index e33df0dfbc8de..2f4a38c16c1d9 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, false))?, None => write!(output, "

No description.

\n")?, } From d5b6c046de79bf357683d9db191ed6a97c24187c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 01:43:36 +0100 Subject: [PATCH 322/662] Add missing markdown tags --- src/librustdoc/html/markdown.rs | 381 +++++++++++++++--------- src/librustdoc/html/render.rs | 13 +- src/librustdoc/markdown.rs | 4 +- src/tools/error_index_generator/main.rs | 4 +- 4 files changed, 251 insertions(+), 151 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9ae6c443f9e06..e8c95c4a21c3f 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -26,13 +26,10 @@ #![allow(non_camel_case_types)] -//use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; -//use std::ffi::CString; use std::fmt::{self, Write}; -//use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; use syntax::codemap::Span; @@ -45,11 +42,33 @@ use test; use pulldown_cmark::{self, Event, Parser, Tag}; +#[derive(Copy, Clone)] +pub enum MarkdownOutputStyle { + Compact, + Fancy, +} + +impl MarkdownOutputStyle { + pub fn is_compact(&self) -> bool { + match *self { + MarkdownOutputStyle::Compact => true, + _ => false, + } + } + + pub fn is_fancy(&self) -> bool { + match *self { + MarkdownOutputStyle::Fancy => true, + _ => false, + } + } +} + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str, pub bool); +pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); @@ -85,25 +104,19 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); - pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, - shorter: bool) -> fmt::Result { + shorter: MarkdownOutputStyle) -> fmt::Result { fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::CodeBlock(_)) => break, - Event::Text(ref s) => { - origtext.push_str(s); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { + origtext.push_str(s); } - } else { - break + _ => {} } } let origtext = origtext.trim_left(); @@ -176,20 +189,19 @@ pub fn render(w: &mut fmt::Formatter, fn header(parser: &mut Parser, level: i32, toc_builder: &mut Option, buffer: &mut String) { let mut ret = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Header(_)) => break, - Event::Text(ref s) => { - ret.push_str(s); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Header(_)) => break, + Event::Text(ref s) => { + ret.push_str(s); } - } else { - break + Event::SoftBreak | Event::HardBreak if !ret.is_empty() => { + ret.push(' '); + } + _ => {} } } + ret = ret.trim_right().to_owned(); let id = ret.clone(); // Discard '', '' tags and some escaped characters, @@ -226,169 +238,242 @@ pub fn render(w: &mut fmt::Formatter, fn codespan(parser: &mut Parser, buffer: &mut String) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Code) => break, - Event::Text(ref s) => { - content.push_str(s); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Code) => break, + Event::Text(ref s) => { + content.push_str(s); } - } else { - break + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + _ => {} } } - buffer.push_str(&format!("{}", Escape(&collapse_whitespace(&content)))); + buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } - fn link(parser: &mut Parser, buffer: &mut String, url: &str, mut title: String) { - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Link(_, _)) => break, - Event::Text(ref s) => { - title.push_str(s); - } - _ => {} + fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, url: &str, mut title: String) { + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Link(_, _)) => break, + Event::Text(ref s) => { + title.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !title.is_empty() => { + title.push(' '); + } + x => { + looper(parser, &mut title, Some(x), toc_builder, shorter); } - } else { - break } } buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Paragraph) => break, - Event::Text(ref s) => { - content.push_str(s); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Paragraph) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } - buffer.push_str(&format!("

{}

", content)); + buffer.push_str(&format!("

{}

", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell) => break, - Event::Text(ref s) => { - content.push_str(s); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } buffer.push_str(&format!("{}", content.trim())); } fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) => break, - Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } buffer.push_str(&format!("{}", content)); } fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } - if content.is_empty() { - return + if !content.is_empty() { + buffer.push_str(&format!("{}", content.replace("td>", "th>"))); } - buffer.push_str(&format!("{}", content.replace("td>", "th>"))); } fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); let mut rows = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableHead) => { - head(parser, &mut content, toc_builder, shorter); - } - Event::Start(Tag::TableRow) => { - row(parser, &mut rows, toc_builder, shorter); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableHead) => { + head(parser, &mut content, toc_builder, shorter); } - } else { - break + Event::Start(Tag::TableRow) => { + row(parser, &mut rows, toc_builder, shorter); + } + _ => {} } } buffer.push_str(&format!("{}{}
", content, - if shorter || rows.is_empty() { + if shorter.is_compact() || rows.is_empty() { String::new() } else { format!("{}", rows) })); } + fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::BlockQuote) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("
{}
", content.trim_right())); + } + + fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Item) => break, + Event::Text(ref s) => { + content.push_str(s); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("
  • {}
  • ", content)); + } + + fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::List(_)) => break, + Event::Start(Tag::Item) => { + list_item(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("
      {}
    ", content)); + } + + fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Emphasis) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("{}", content)); + } + + fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Strong) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("{}", content)); + } + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option, shorter: bool) -> bool { + toc_builder: &mut Option, shorter: MarkdownOutputStyle) -> bool { if let Some(event) = next_event { match event { Event::Start(Tag::CodeBlock(lang)) => { @@ -404,14 +489,26 @@ pub fn render(w: &mut fmt::Formatter, paragraph(parser, buffer, toc_builder, shorter); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, url, t.as_ref().to_owned()); + link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned()); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); } + Event::Start(Tag::BlockQuote) => { + blockquote(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::List(_)) => { + list(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::Emphasis) => { + emphasis(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::Strong) => { + strong(parser, buffer, toc_builder, shorter); + } _ => {} } - shorter == false + shorter.is_fancy() } else { false } @@ -594,7 +691,7 @@ impl<'a> fmt::Display for Markdown<'a> { impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, false) + render(fmt, md, true, MarkdownOutputStyle::Fancy) } } @@ -603,7 +700,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, false) + render(fmt, md, false, MarkdownOutputStyle::Fancy) } } @@ -660,7 +757,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { - use super::{LangString, Markdown, MarkdownHtml}; + use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle}; use super::plain_summary_line; use html::render::reset_ids; @@ -700,14 +797,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown)); + format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); assert_eq!(output, expect); reset_ids(true); } @@ -729,7 +826,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); assert_eq!(output, expect); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8c1416b809799..1fa348a1be4c4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -1650,7 +1650,8 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin } else { format!("{}", &plain_summary_line(Some(s))) }; - write!(w, "
    {}
    ", Markdown(&markdown, false))?; + write!(w, "
    {}
    ", + Markdown(&markdown, MarkdownOutputStyle::Fancy))?; } Ok(()) } @@ -1683,7 +1684,8 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
    {}
    ", - Markdown(&format!("{}{}", md_render_assoc_item(item), s), false))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), + MarkdownOutputStyle::Fancy))?; } Ok(()) } @@ -1871,7 +1873,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value, true).to_string())), + docs = shorter(Some(&Markdown(doc_value, + MarkdownOutputStyle::Compact).to_string())), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2901,7 +2904,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
    {}
    ", Markdown(dox, false))?; + write!(w, "
    {}
    ", Markdown(dox, MarkdownOutputStyle::Fancy))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index a048750279e26..d29e98f8fe105 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `%`. @@ -94,7 +94,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text, false)) + format!("{}", Markdown(text, MarkdownOutputStyle::Fancy)) }; let err = write!( diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 2f4a38c16c1d9..1d4f2c60d544f 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc, false))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?, None => write!(output, "

    No description.

    \n")?, } From 6d470a9c4a41e97cf7b9d9ab2cc0045d7889d01f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 16:27:54 +0100 Subject: [PATCH 323/662] Add a macro to improve code --- src/librustdoc/html/markdown.rs | 156 ++++++++------------------------ 1 file changed, 39 insertions(+), 117 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8c95c4a21c3f..3cc95260e3bd6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -104,6 +104,25 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); +macro_rules! event_loop_break { + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $($end_event:pat)|*) => {{ + while let Some(event) = $parser.next() { + match event { + $($end_event)|* => break, + Event::Text(ref s) => { + $buf.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { + $buf.push(' '); + } + x => { + looper($parser, &mut $buf, Some(x), $toc_builder, $shorter); + } + } + } + }} +} + pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, @@ -186,21 +205,10 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn header(parser: &mut Parser, level: i32, toc_builder: &mut Option, - buffer: &mut String) { + fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Header(_)) => break, - Event::Text(ref s) => { - ret.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !ret.is_empty() => { - ret.push(' '); - } - _ => {} - } - } + event_loop_break!(parser, toc_builder, shorter, ret, Event::End(Tag::Header(_))); ret = ret.trim_right().to_owned(); let id = ret.clone(); @@ -236,82 +244,35 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn codespan(parser: &mut Parser, buffer: &mut String) { + fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Code) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - _ => {} - } - } - buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Code)); + buffer.push_str(&format!("{}", + Escape(&collapse_whitespace(content.trim_right())))); } fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String) { - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Link(_, _)) => break, - Event::Text(ref s) => { - title.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !title.is_empty() => { - title.push(' '); - } - x => { - looper(parser, &mut title, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, title, Event::End(Tag::Link(_, _))); buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Paragraph) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell)); buffer.push_str(&format!("{}", content.trim())); } @@ -381,20 +342,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::BlockQuote) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } @@ -435,40 +383,14 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Emphasis) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Strong) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Strong)); buffer.push_str(&format!("{}", content)); } @@ -480,10 +402,10 @@ pub fn render(w: &mut fmt::Formatter, block(parser, buffer, &*lang); } Event::Start(Tag::Header(level)) => { - header(parser, level, toc_builder, buffer); + header(parser, buffer, toc_builder, shorter, level); } Event::Start(Tag::Code) => { - codespan(parser, buffer); + codespan(parser, buffer, toc_builder, shorter); } Event::Start(Tag::Paragraph) => { paragraph(parser, buffer, toc_builder, shorter); From 6a2190c18e53398191c9d5d9f37c8bcef296402d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 16:37:35 +0100 Subject: [PATCH 324/662] Remove unneeded comment --- src/librustdoc/html/markdown.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 3cc95260e3bd6..09006d9ef8292 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -212,12 +212,6 @@ pub fn render(w: &mut fmt::Formatter, ret = ret.trim_right().to_owned(); let id = ret.clone(); - // Discard '', '' tags and some escaped characters, - // transform the contents of the header into a hyphenated string - // without non-alphanumeric characters other than '-' and '_'. - // - // This is a terrible hack working around how hoedown gives us rendered - // html for text rather than the raw text. let id = id.chars().filter_map(|c| { if c.is_alphanumeric() || c == '-' || c == '_' { if c.is_ascii() { From e51f3253beb60a011bfccc0c5a5eaf119993f175 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 18:09:59 +0100 Subject: [PATCH 325/662] Handle html in markdown as well --- src/librustdoc/html/markdown.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 09006d9ef8292..d823e2bc1f56d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -422,6 +422,9 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::Strong) => { strong(parser, buffer, toc_builder, shorter); } + Event::Html(h) | Event::InlineHtml(h) => { + buffer.push_str(&*h); + } _ => {} } shorter.is_fancy() From 474cc0932536c3ade8609fabd9f8fd0c95fd65af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 12 Mar 2017 20:28:36 +0100 Subject: [PATCH 326/662] Update pulldown version after fix merged --- src/Cargo.lock | 17 ++++++++++++++++- src/librustdoc/Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 946818e7d2087..11c40fd7cd6c5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -68,6 +68,11 @@ name = "bitflags" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bootstrap" version = "0.0.0" @@ -358,6 +363,15 @@ dependencies = [ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pulldown-cmark" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "qemu-test-client" version = "0.1.0" @@ -773,7 +787,7 @@ dependencies = [ "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.0.0", - "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1005,6 +1019,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" +"checksum pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ba85e41d8537ec513bee33aecca3f0bceb53c239807faa09800b39017ab4a965" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index ff18daa7aa098..cd996c0ff3aff 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -25,7 +25,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -pulldown-cmark = "0.0.8" +pulldown-cmark = "0.0.9" [build-dependencies] build_helper = { path = "../build_helper" } From e133821b8914e03dcc80a2ebcf35277d9f11681e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Mar 2017 01:05:21 +0100 Subject: [PATCH 327/662] Update to last pulldown version --- src/Cargo.lock | 62 +++++++++++++++++---------------------- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/lib.rs | 2 +- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 11c40fd7cd6c5..e2965a100d55c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -27,7 +27,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -65,12 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -80,7 +75,7 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -109,12 +104,12 @@ version = "0.1.0" [[package]] name = "clap" -version = "2.21.1" +version = "2.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -127,7 +122,7 @@ name = "cmake" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -145,7 +140,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -193,7 +188,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -202,7 +197,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -220,7 +215,7 @@ version = "0.0.0" [[package]] name = "handlebars" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -277,9 +272,9 @@ name = "mdbook" version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -365,11 +360,10 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.0.9" +version = "0.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -397,7 +391,7 @@ name = "regex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -430,7 +424,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", ] @@ -607,7 +601,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -783,11 +777,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.0.0", - "pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -834,7 +826,7 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", @@ -994,19 +986,19 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" -"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e17a4a72ffea176f77d6e2db609c6c919ef221f23862c9915e687fb54d833485" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" +"checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" @@ -1018,8 +1010,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" +"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" -"checksum pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ba85e41d8537ec513bee33aecca3f0bceb53c239807faa09800b39017ab4a965" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index cd996c0ff3aff..52f5d99838dc7 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -25,7 +25,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -pulldown-cmark = "0.0.9" +pulldown-cmark = { version = "0.0.14", default-features = false } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index efb51bdf471f4..447d60018d912 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,7 +9,7 @@ // except according to those terms. #![crate_name = "rustdoc"] -#![unstable(feature = "rustdoc", issue = "27812")] +#![unstable(feature = "rustc_private", issue = "27812")] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", From cba67ad8012c63ddae8b4c540bbb6f70a93c8ddf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Mar 2017 23:53:18 +0100 Subject: [PATCH 328/662] Add feature for rustdoc binary --- src/rustc/rustdoc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rustc/rustdoc.rs b/src/rustc/rustdoc.rs index 6fecd3a27a8a4..ccedb9844bbac 100644 --- a/src/rustc/rustdoc.rs +++ b/src/rustc/rustdoc.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(rustdoc)] +#![feature(rustc_private)] extern crate rustdoc; From 47e4abf47397438ca86e96ed3f848276dddd5738 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Mar 2017 01:48:33 +0100 Subject: [PATCH 329/662] Fix plain_summary_line function --- src/librustdoc/html/markdown.rs | 84 ++++++++++++++++++++------------- src/rustc/rustdoc.rs | 1 - 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index d823e2bc1f56d..4d67e8b532999 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -106,11 +106,19 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = macro_rules! event_loop_break { ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $($end_event:pat)|*) => {{ + event_loop_break($parser, $toc_builder, $shorter, $buf, false, $($end_event:pat)|*); + }}; + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, + $($end_event:pat)|*) => {{ while let Some(event) = $parser.next() { match event { $($end_event)|* => break, Event::Text(ref s) => { - $buf.push_str(s); + if $escape { + $buf.push_str(&escape(s)); + } else { + $buf.push_str(s); + } } Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { $buf.push(' '); @@ -127,6 +135,13 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { + fn escape(entry: &str) -> String { + entry.replace("<", "<") + .replace("'", "'") + .replace(">", ">") + .replace("&", "&") + } + fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { @@ -208,7 +223,7 @@ pub fn render(w: &mut fmt::Formatter, fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, Event::End(Tag::Header(_))); + event_loop_break!(parser, toc_builder, shorter, ret, true, Event::End(Tag::Header(_))); ret = ret.trim_right().to_owned(); let id = ret.clone(); @@ -241,28 +256,28 @@ pub fn render(w: &mut fmt::Formatter, fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Code)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String) { - event_loop_break!(parser, toc_builder, shorter, title, Event::End(Tag::Link(_, _))); + event_loop_break!(parser, toc_builder, shorter, title, true, Event::End(Tag::Link(_, _))); buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Paragraph)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) | Event::End(Tag::TableRow) | @@ -336,7 +351,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::BlockQuote)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } @@ -347,7 +362,7 @@ pub fn render(w: &mut fmt::Formatter, match event { Event::End(Tag::Item) => break, Event::Text(ref s) => { - content.push_str(s); + content.push_str(&escape(s)); } x => { looper(parser, &mut content, Some(x), toc_builder, shorter); @@ -377,14 +392,14 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Emphasis)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Strong)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Strong)); buffer.push_str(&format!("{}", content)); } @@ -644,9 +659,12 @@ pub fn plain_summary_line(md: &str) -> String { Event::Start(Tag::Link(_, ref t)) if !self.is_first => { (Some(t.as_ref().to_owned()), 1) } + Event::Start(Tag::Code) => (Some("`".to_owned()), 1), + Event::End(Tag::Code) => (Some("`".to_owned()), -1), + Event::Start(Tag::Header(_)) => (None, 1), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), - Event::End(Tag::Paragraph) => (None, -1), + Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), _ => (None, 0), }; if is_in > 0 || (is_in < 0 && self.is_in > 0) { @@ -728,17 +746,17 @@ mod tests { reset_ids(true); } - t("# Foo bar", "\n

    \ - Foo bar

    "); - t("## Foo-bar_baz qux", "\n

    Foo-bar_baz qux

    "); + t("# Foo bar", "

    \ + Foo bar

    "); + t("## Foo-bar_baz qux", "

    Foo-bar_baz qux

    "); t("### **Foo** *bar* baz!?!& -_qux_-%", - "\n

    \ - Foo \ + "

    \ + Foo \ bar baz!?!& -_qux_-%

    "); t("####**Foo?** & \\*bar?!* _`baz`_ ❤ #qux", - "\n

    \ - Foo? & *bar?!* \ + "

    \ + Foo? & *bar?!* \ baz ❤ #qux

    "); } @@ -750,18 +768,18 @@ mod tests { } let test = || { - t("# Example", "\n

    \ - Example

    "); - t("# Panics", "\n

    \ - Panics

    "); - t("# Example", "\n

    \ - Example

    "); - t("# Main", "\n

    \ - Main

    "); - t("# Example", "\n

    \ - Example

    "); - t("# Panics", "\n

    \ - Panics

    "); + t("# Example", "

    \ + Example

    "); + t("# Panics", "

    \ + Panics

    "); + t("# Example", "

    \ + Example

    "); + t("# Main", "

    \ + Main

    "); + t("# Example", "

    \ + Example

    "); + t("# Panics", "

    \ + Panics

    "); }; test(); reset_ids(true); @@ -789,7 +807,7 @@ mod tests { assert_eq!(output, expect); } - t("`Struct<'a, T>`", "

    Struct<'a, T>

    \n"); - t("Struct<'a, T>", "

    Struct<'a, T>

    \n"); + t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); + t("Struct<'a, T>", "

    Struct<'a, T>

    "); } } diff --git a/src/rustc/rustdoc.rs b/src/rustc/rustdoc.rs index ccedb9844bbac..a4f43c42623d3 100644 --- a/src/rustc/rustdoc.rs +++ b/src/rustc/rustdoc.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustdoc)] #![feature(rustc_private)] extern crate rustdoc; From 286a51da9187971c2aa5bac89834f5be7cc96d86 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Mar 2017 19:07:52 +0100 Subject: [PATCH 330/662] Fix id generation --- src/Cargo.lock | 9 +-- src/librustdoc/html/markdown.rs | 98 +++++++++++++++++---------------- 2 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index e2965a100d55c..a9021dc34e207 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -218,7 +218,7 @@ name = "handlebars" version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -777,8 +777,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1001,7 +1002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" +"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" diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4d67e8b532999..e55f3fa91dcdc 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -105,17 +105,20 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = }); macro_rules! event_loop_break { - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $($end_event:pat)|*) => {{ - event_loop_break($parser, $toc_builder, $shorter, $buf, false, $($end_event:pat)|*); - }}; - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr, $($end_event:pat)|*) => {{ + fn inner(id: &mut Option<&mut String>, s: &str) { + if let Some(ref mut id) = *id { + id.push_str(s); + } + } while let Some(event) = $parser.next() { match event { $($end_event)|* => break, Event::Text(ref s) => { + inner($id, s); if $escape { - $buf.push_str(&escape(s)); + $buf.push_str(&format!("{}", Escape(s))); } else { $buf.push_str(s); } @@ -124,7 +127,7 @@ macro_rules! event_loop_break { $buf.push(' '); } x => { - looper($parser, &mut $buf, Some(x), $toc_builder, $shorter); + looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); } } } @@ -135,13 +138,6 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn escape(entry: &str) -> String { - entry.replace("<", "<") - .replace("'", "'") - .replace(">", ">") - .replace("&", "&") - } - fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { @@ -223,10 +219,11 @@ pub fn render(w: &mut fmt::Formatter, fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, true, Event::End(Tag::Header(_))); + let mut id = String::new(); + event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), + Event::End(Tag::Header(_))); ret = ret.trim_right().to_owned(); - let id = ret.clone(); let id = id.chars().filter_map(|c| { if c.is_alphanumeric() || c == '-' || c == '_' { if c.is_ascii() { @@ -254,30 +251,33 @@ pub fn render(w: &mut fmt::Formatter, } fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Code)); + event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, url: &str, mut title: String) { - event_loop_break!(parser, toc_builder, shorter, title, true, Event::End(Tag::Link(_, _))); + shorter: MarkdownOutputStyle, url: &str, mut title: String, + id: &mut Option<&mut String>) { + event_loop_break!(parser, toc_builder, shorter, title, true, id, + Event::End(Tag::Link(_, _))); buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Paragraph)); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, + event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) | Event::End(Tag::TableRow) | @@ -297,7 +297,7 @@ pub fn render(w: &mut fmt::Formatter, cell(parser, &mut content, toc_builder, shorter); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -314,7 +314,7 @@ pub fn render(w: &mut fmt::Formatter, cell(parser, &mut content, toc_builder, shorter); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -351,7 +351,8 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::BlockQuote)); + event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, + Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } @@ -362,10 +363,10 @@ pub fn render(w: &mut fmt::Formatter, match event { Event::End(Tag::Item) => break, Event::Text(ref s) => { - content.push_str(&escape(s)); + content.push_str(&format!("{}", Escape(s))); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -382,7 +383,7 @@ pub fn render(w: &mut fmt::Formatter, list_item(parser, &mut content, toc_builder, shorter); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -390,21 +391,24 @@ pub fn render(w: &mut fmt::Formatter, } fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Emphasis)); + event_loop_break!(parser, toc_builder, shorter, content, false, id, + Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Strong)); + event_loop_break!(parser, toc_builder, shorter, content, false, id, + Event::End(Tag::Strong)); buffer.push_str(&format!("{}", content)); } fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) -> bool { + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) -> bool { if let Some(event) = next_event { match event { Event::Start(Tag::CodeBlock(lang)) => { @@ -414,13 +418,13 @@ pub fn render(w: &mut fmt::Formatter, header(parser, buffer, toc_builder, shorter, level); } Event::Start(Tag::Code) => { - codespan(parser, buffer, toc_builder, shorter); + codespan(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder, shorter); + paragraph(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned()); + link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); @@ -432,10 +436,10 @@ pub fn render(w: &mut fmt::Formatter, list(parser, buffer, toc_builder, shorter); } Event::Start(Tag::Emphasis) => { - emphasis(parser, buffer, toc_builder, shorter); + emphasis(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Strong) => { - strong(parser, buffer, toc_builder, shorter); + strong(parser, buffer, toc_builder, shorter, id); } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); @@ -457,7 +461,7 @@ pub fn render(w: &mut fmt::Formatter, let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); loop { let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter) { + if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { break } } @@ -742,7 +746,7 @@ mod tests { fn test_header() { fn t(input: &str, expect: &str) { let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -751,10 +755,10 @@ mod tests { t("## Foo-bar_baz qux", "

    Foo-bar_baz qux

    "); t("### **Foo** *bar* baz!?!& -_qux_-%", - "

    \ - Foo \ - bar baz!?!& -_qux_-%

    "); - t("####**Foo?** & \\*bar?!* _`baz`_ ❤ #qux", + "

    \ + Foo \ + bar baz!?!& -qux-%

    "); + t("#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", "

    \ Foo? & *bar?!* \ baz ❤ #qux

    "); @@ -764,7 +768,7 @@ mod tests { fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } let test = || { @@ -790,7 +794,7 @@ mod tests { fn test_plain_summary_line() { fn t(input: &str, expect: &str) { let output = plain_summary_line(input); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); @@ -804,7 +808,7 @@ mod tests { fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let output = format!("{}", MarkdownHtml(input)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); From a7c6d3e16a71fc0dcce4c9be09d031d746f84a69 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Mar 2017 11:54:11 -0600 Subject: [PATCH 331/662] Improve function naming --- src/librustdoc/html/markdown.rs | 45 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e55f3fa91dcdc..117cfbabb52f7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -10,17 +10,16 @@ //! Markdown formatting for rustdoc //! -//! This module implements markdown formatting through the hoedown C-library -//! (bundled into the rust runtime). This module self-contains the C bindings -//! and necessary legwork to render markdown, and exposes all of the +//! This module implements markdown formatting through the pulldown-cmark +//! rust-library. This module exposes all of the //! functionality through a unit-struct, `Markdown`, which has an implementation //! of `fmt::Display`. Example usage: //! //! ```rust,ignore -//! use rustdoc::html::markdown::Markdown; +//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle}; //! //! let s = "My *markdown* _text_"; -//! let html = format!("{}", Markdown(s)); +//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy)); //! // ... something using html //! ``` @@ -138,7 +137,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { + fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -216,8 +215,8 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, level: i32) { + fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -250,8 +249,8 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", @@ -274,8 +273,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("

    {}

    ", content.trim_right())); } - fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -285,8 +284,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content.trim())); } - fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -294,7 +293,7 @@ pub fn render(w: &mut fmt::Formatter, Event::End(Tag::Table(_)) | Event::End(Tag::TableRow) => break, Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); + table_cell(parser, &mut content, toc_builder, shorter); } x => { looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); @@ -304,14 +303,14 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); + table_cell(parser, &mut content, toc_builder, shorter); } x => { looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); @@ -331,10 +330,10 @@ pub fn render(w: &mut fmt::Formatter, match event { Event::End(Tag::Table(_)) => break, Event::Start(Tag::TableHead) => { - head(parser, &mut content, toc_builder, shorter); + table_head(parser, &mut content, toc_builder, shorter); } Event::Start(Tag::TableRow) => { - row(parser, &mut rows, toc_builder, shorter); + table_row(parser, &mut rows, toc_builder, shorter); } _ => {} } @@ -412,13 +411,13 @@ pub fn render(w: &mut fmt::Formatter, if let Some(event) = next_event { match event { Event::Start(Tag::CodeBlock(lang)) => { - block(parser, buffer, &*lang); + code_block(parser, buffer, &*lang); } Event::Start(Tag::Header(level)) => { - header(parser, buffer, toc_builder, shorter, level); + heading(parser, buffer, toc_builder, shorter, level); } Event::Start(Tag::Code) => { - codespan(parser, buffer, toc_builder, shorter, id); + inline_code(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Paragraph) => { paragraph(parser, buffer, toc_builder, shorter, id); From 1fea03548cc9ecba3010c9e75eea0ef533ea44c9 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Fri, 24 Mar 2017 03:50:32 -0700 Subject: [PATCH 332/662] Rustdoc: memoize `pub use`-reexported macros so they don't appear twice in docs --- src/librustdoc/visit_ast.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2793307697852..c89ec5bbe15bd 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -21,7 +21,7 @@ use syntax_pos::Span; use rustc::hir::map as hir_map; use rustc::hir::def::Def; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::cstore::LoadedMacro; use rustc::middle::privacy::AccessLevel; use rustc::util::nodemap::FxHashSet; @@ -48,6 +48,7 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { inlining: bool, /// Is the current module and all of its parents public? inside_public_path: bool, + reexported_macros: FxHashSet, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -62,6 +63,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { view_item_stack: stack, inlining: false, inside_public_path: true, + reexported_macros: FxHashSet(), } } @@ -201,9 +203,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if let Some(exports) = self.cx.tcx.export_map.get(&id) { for export in exports { if let Def::Macro(def_id, ..) = export.def { - if def_id.krate == LOCAL_CRATE { + if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) { continue // These are `krate.exported_macros`, handled in `self.visit()`. } + let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { LoadedMacro::MacroDef(macro_def) => macro_def, @@ -217,6 +220,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } else { unreachable!() }; + om.macros.push(Macro { def_id: def_id, attrs: def.attrs.clone().into(), @@ -263,6 +267,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { false } + debug!("maybe_inline_local def: {:?}", def); + let tcx = self.cx.tcx; if def == Def::Err { return false; @@ -274,6 +280,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || use_attrs.lists("doc").has_word("hidden"); + // Memoize the non-inlined `pub use`'d macros so we don't push an extra + // declaration in `visit_mod_contents()` + if !def_did.is_local() { + if let Def::Macro(did, _) = def { + if please_inline { return true } + debug!("memoizing non-inlined macro export: {:?}", def); + self.reexported_macros.insert(did); + return false; + } + } + // For cross-crate impl inlining we need to know whether items are // reachable in documentation - a previously nonreachable item can be // made reachable by cross-crate inlining which we're checking here. @@ -294,6 +311,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }, _ => {}, } + return false } From d8fc5b80b61f662dd0d63d236875ade5a3f1129c Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Tue, 28 Mar 2017 00:02:19 -0700 Subject: [PATCH 333/662] Rustdoc: test proper representation for `pub use` macros --- .../auxiliary/pub-use-extern-macros.rs | 30 ++++++++++++++++++ src/test/rustdoc/pub-use-extern-macros.rs | 31 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/pub-use-extern-macros.rs create mode 100644 src/test/rustdoc/pub-use-extern-macros.rs diff --git a/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs new file mode 100644 index 0000000000000..70d174a149daa --- /dev/null +++ b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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. +#![crate_name="macros"] + +#[macro_export] +macro_rules! foo { + () => {}; +} + +#[macro_export] +macro_rules! bar { + () => {}; +} + +#[macro_export] +macro_rules! baz { + () => {}; +} + +#[macro_export] +macro_rules! quux { + () => {}; +} diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs new file mode 100644 index 0000000000000..3f8f6f9544e80 --- /dev/null +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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:pub-use-extern-macros.rs + +#![feature(use_extern_macros, macro_reexport)] + +// @has pub_use_extern_macros/macro.foo.html +// @!has pub_use_extern_macros/index.html 'pub use macros::foo;' +#[macro_reexport(foo)] extern crate macros; + +// @has pub_use_extern_macros/index.html 'pub use macros::bar;' +// @!has pub_use_extern_macros/macro.bar.html +pub use macros::bar; + +// @has pub_use_extern_macros/macro.baz.html +// @!has pub_use_extern_macros/index.html 'pub use macros::baz;' +#[doc(inline)] +pub use macros::baz; + +// @!has pub_use_extern_macros/macro.quux.html +// @!has pub_use_extern_macros/index.html 'pub use macros::quux;' +#[doc(hidden)] +pub use macros::quux; From 8206d0c54e149609617a1de57cad480bbad73970 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 28 Mar 2017 16:49:05 -0500 Subject: [PATCH 334/662] rustdoc: format fns like format rfc 39 --- src/librustdoc/html/format.rs | 36 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fc5507d4d5559..3589cc8fac617 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -945,6 +945,10 @@ impl<'a> fmt::Display for Method<'a> { let mut args = String::new(); let mut args_plain = String::new(); for (i, input) in decl.inputs.values.iter().enumerate() { + if i == 0 { + args.push_str("
    "); + } + if let Some(selfty) = input.to_self() { match selfty { clean::SelfValue => { @@ -986,8 +990,8 @@ impl<'a> fmt::Display for Method<'a> { args_plain.push_str(&format!("{:#}", input.type_)); } if i + 1 < decl.inputs.values.len() { - args.push_str(","); - args_plain.push_str(","); + args.push(','); + args_plain.push(','); } } @@ -1003,27 +1007,19 @@ impl<'a> fmt::Display for Method<'a> { format!("{}", decl.output) }; - let mut output: String; - let plain: String; let pad = repeat(" ").take(indent).collect::(); - if arrow.is_empty() { - output = format!("({})", args); - plain = format!("{}({})", pad, args_plain); + let plain = format!("{pad}({args}){arrow}", + pad = pad, + args = args_plain, + arrow = arrow_plain); + + let output = if plain.len() > 80 { + let pad = "
        "; + format!("({args}
    ){arrow}", args = args.replace("
    ", pad), arrow = arrow) } else { - output = format!("({args})
    {arrow}", args = args, arrow = arrow); - plain = format!("{pad}({args}){arrow}", - pad = pad, - args = args_plain, - arrow = arrow_plain); - } + format!("({args}){arrow}", args = args.replace("
    ", ""), arrow = arrow) + }; - if plain.len() > 80 { - let pad = repeat(" ").take(indent).collect::(); - let pad = format!("
    {}", pad); - output = output.replace("
    ", &pad); - } else { - output = output.replace("
    ", ""); - } if f.alternate() { write!(f, "{}", output.replace("
    ", "\n")) } else { From 7efbb69b99cf6b88027b3ec0a3d12771703831e7 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 29 Mar 2017 01:18:39 +0200 Subject: [PATCH 335/662] Changed cmp::Reverse to unstable --- src/libcore/cmp.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 751932a6105ae..a43c85328731f 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -330,6 +330,7 @@ impl Ordering { /// Example usage: /// /// ``` +/// #![feature(reverse_cmp_key)] /// use std::cmp::Reverse; /// /// let mut v = vec![1, 2, 3, 4, 5, 6]; @@ -337,10 +338,10 @@ impl Ordering { /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` #[derive(PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.18.0")] +#[unstable(feature = "reverse_cmp_key", issue = "40720")] pub struct Reverse(pub T); -#[stable(feature = "rust1", since = "1.18.0")] +#[unstable(feature = "reverse_cmp_key", issue = "40720")] impl PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { @@ -348,7 +349,7 @@ impl PartialOrd for Reverse { } } -#[stable(feature = "rust1", since = "1.18.0")] +#[unstable(feature = "reverse_cmp_key", issue = "40720")] impl Ord for Reverse { #[inline] fn cmp(&self, other: &Reverse) -> Ordering { From 1979f96549fc41b544d2bf05eb868f26941f2b25 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 10:23:33 +0000 Subject: [PATCH 336/662] Move `syntax::ext::hygiene` to `syntax_pos::hygiene`. --- src/librustc/hir/map/def_collector.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/libsyntax/ast.rs | 10 +++++++++- src/libsyntax/ext/expand.rs | 6 +++--- src/libsyntax/ext/placeholders.rs | 4 ++-- src/libsyntax/lib.rs | 2 +- src/{libsyntax/ext => libsyntax_pos}/hygiene.rs | 13 ++++--------- src/libsyntax_pos/lib.rs | 3 +++ 8 files changed, 24 insertions(+), 18 deletions(-) rename src/{libsyntax/ext => libsyntax_pos}/hygiene.rs (95%) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cae358a303e02..afdb9059ea7c0 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -92,7 +92,7 @@ impl<'a> DefCollector<'a> { fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) { if let Some(ref mut visit) = self.visit_macro_invoc { visit(MacroInvocationData { - mark: Mark::from_placeholder_id(id), + mark: id.placeholder_to_mark(), const_expr: const_expr, def_index: self.parent_def.unwrap(), }) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 86e0d0039d1a7..a15431afc164b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -680,7 +680,7 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { - let mark = Mark::from_placeholder_id(id); + let mark = id.placeholder_to_mark(); self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); let invocation = self.resolver.invocations[&mark]; invocation.module.set(self.resolver.current_module); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3dd4bdbd14ddb..7e2b225193f6d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,7 +20,7 @@ pub use util::ThinVec; use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; -use ext::hygiene::SyntaxContext; +use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; use rustc_data_structures::indexed_vec; @@ -256,6 +256,14 @@ impl NodeId { pub fn as_u32(&self) -> u32 { self.0 } + + pub fn placeholder_from_mark(mark: Mark) -> Self { + NodeId(mark.as_u32()) + } + + pub fn placeholder_to_mark(self) -> Mark { + Mark::from_u32(self.0) + } } impl fmt::Display for NodeId { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 6abeb4b0b2805..e258c51a3295f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Block, Ident, PatKind, Path}; +use ast::{self, Block, Ident, NodeId, PatKind, Path}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; @@ -321,7 +321,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let derives = derives.remove(&mark).unwrap_or_else(Vec::new); - placeholder_expander.add(mark.as_placeholder_id(), expansion, derives); + placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives); } } @@ -703,7 +703,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ..self.cx.current_expansion.clone() }, }); - placeholder(expansion_kind, mark.as_placeholder_id()) + placeholder(expansion_kind, NodeId::placeholder_from_mark(mark)) } fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 2d0994a7b78fb..4fb138d506a8e 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast; +use ast::{self, NodeId}; use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; @@ -88,7 +88,7 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { let mut expansion = expansion.fold_with(self); if let Expansion::Items(mut items) = expansion { for derive in derives { - match self.remove(derive.as_placeholder_id()) { + match self.remove(NodeId::placeholder_from_mark(derive)) { Expansion::Items(derived_items) => items.extend(derived_items), _ => unreachable!(), } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 4c9a5d512af02..6c975f3fc4021 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -136,12 +136,12 @@ pub mod print { } pub mod ext { + pub use syntax_pos::hygiene; pub mod base; pub mod build; pub mod derive; pub mod expand; pub mod placeholders; - pub mod hygiene; pub mod quote; pub mod source_util; diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax_pos/hygiene.rs similarity index 95% rename from src/libsyntax/ext/hygiene.rs rename to src/libsyntax_pos/hygiene.rs index 57f5ab73d3706..feebbcd6f03b6 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -15,7 +15,6 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 -use ast::NodeId; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; @@ -47,17 +46,13 @@ impl Mark { Mark(0) } - pub fn from_placeholder_id(id: NodeId) -> Self { - Mark(id.as_u32()) - } - - pub fn as_placeholder_id(self) -> NodeId { - NodeId::from_u32(self.0) - } - pub fn as_u32(self) -> u32 { self.0 } + + pub fn from_u32(raw: u32) -> Mark { + Mark(raw) + } } struct HygieneData { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3808923e7728f..1c9a05dadd15f 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -23,6 +23,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] +#![feature(const_fn)] #![feature(custom_attribute)] #![allow(unused_attributes)] #![feature(rustc_private)] @@ -41,6 +42,8 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving +pub mod hygiene; + pub type FileName = String; /// Spans represent a region of code, used for error reporting. Positions in spans From 496996c2af6174cb83a65756249d289f315dff80 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 10:31:36 +0000 Subject: [PATCH 337/662] Remove code in `syntax::codemap`. --- src/libsyntax/codemap.rs | 185 --------------------------------------- src/libsyntax_pos/lib.rs | 4 - 2 files changed, 189 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 0f4b844b0eac8..388f3cb732351 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -409,101 +409,6 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } - // Returns true if two spans have the same callee - // (Assumes the same ExpnFormat implies same callee) - fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool { - let fmt_a = self - .with_expn_info(sp_a.expn_id, - |ei| ei.map(|ei| ei.callee.format.clone())); - - let fmt_b = self - .with_expn_info(sp_b.expn_id, - |ei| ei.map(|ei| ei.callee.format.clone())); - fmt_a == fmt_b - } - - /// Returns a formatted string showing the expansion chain of a span - /// - /// Spans are printed in the following format: - /// - /// filename:start_line:col: end_line:col - /// snippet - /// Callee: - /// Callee span - /// Callsite: - /// Callsite span - /// - /// Callees and callsites are printed recursively (if available, otherwise header - /// and span is omitted), expanding into their own callee/callsite spans. - /// Each layer of recursion has an increased indent, and snippets are truncated - /// to at most 50 characters. Finally, recursive calls to the same macro are squashed, - /// with '...' used to represent any number of recursive calls. - pub fn span_to_expanded_string(&self, sp: Span) -> String { - self.span_to_expanded_string_internal(sp, "") - } - - fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String { - let mut indent = indent.to_owned(); - let mut output = "".to_owned(); - let span_str = self.span_to_string(sp); - let mut span_snip = self.span_to_snippet(sp) - .unwrap_or("Snippet unavailable".to_owned()); - - // Truncate by code points - in worst case this will be more than 50 characters, - // but ensures at least 50 characters and respects byte boundaries. - let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect(); - if char_vec.len() > 50 { - span_snip.truncate(char_vec[49].0); - span_snip.push_str("..."); - } - - output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip)); - - if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN { - return output; - } - - let mut callee = self.with_expn_info(sp.expn_id, - |ei| ei.and_then(|ei| ei.callee.span.clone())); - let mut callsite = self.with_expn_info(sp.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())); - - indent.push_str(" "); - let mut is_recursive = false; - - while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) { - callee = self.with_expn_info(callee.unwrap().expn_id, - |ei| ei.and_then(|ei| ei.callee.span.clone())); - is_recursive = true; - } - if let Some(span) = callee { - output.push_str(&indent); - output.push_str("Callee:\n"); - if is_recursive { - output.push_str(&indent); - output.push_str("...\n"); - } - output.push_str(&(self.span_to_expanded_string_internal(span, &indent))); - } - - is_recursive = false; - while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) { - callsite = self.with_expn_info(callsite.unwrap().expn_id, - |ei| ei.map(|ei| ei.call_site.clone())); - is_recursive = true; - } - if let Some(span) = callsite { - output.push_str(&indent); - output.push_str("Callsite:\n"); - if is_recursive { - output.push_str(&indent); - output.push_str("...\n"); - } - output.push_str(&(self.span_to_expanded_string_internal(span, &indent))); - } - output - } - /// Return the source span - this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(&self, sp: Span) -> Span { @@ -1069,59 +974,6 @@ mod tests { assert_eq!(sstr, "blork.rs:2:1: 2:12"); } - #[test] - fn t10() { - // Test span_to_expanded_string works in base case (no expansion) - let cm = init_code_map(); - let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - let sstr = cm.span_to_expanded_string(span); - assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n"); - - let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION }; - let sstr = cm.span_to_expanded_string(span); - assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n"); - } - - #[test] - fn t11() { - // Test span_to_expanded_string works with expansion - let cm = init_code_map(); - let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - let format = ExpnFormat::MacroBang(keywords::Invalid.name()); - let callee = NameAndSpan { format: format, - allow_internal_unstable: false, - span: None }; - - let info = ExpnInfo { call_site: root, callee: callee }; - let id = cm.record_expansion(info); - let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id }; - - let sstr = cm.span_to_expanded_string(sp); - assert_eq!(sstr, - "blork.rs:2:1: 2:12\n`second line`\n Callsite:\n \ - blork.rs:1:1: 1:12\n `first line.`\n"); - } - - /// Test merging two spans on the same line - #[test] - fn span_merging() { - let cm = CodeMap::new(); - let inputtext = "bbbb BB bb CCC\n"; - let selection1 = " ~~ \n"; - let selection2 = " ~~~\n"; - cm.new_filemap_and_lines("blork.rs", None, inputtext); - let span1 = span_from_selection(inputtext, selection1); - let span2 = span_from_selection(inputtext, selection2); - - if let Some(sp) = cm.merge_spans(span1, span2) { - let sstr = cm.span_to_expanded_string(sp); - assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n"); - } - else { - assert!(false); - } - } - /// Test failing to merge two spans on different lines #[test] fn span_merging_fail() { @@ -1221,41 +1073,4 @@ mod tests { let id_end = cm.record_expansion(info_end); Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } } - - #[test] - fn t12() { - // Test span_to_expanded_string collapses recursive macros and handles - // recursive callsite and callee expansions - let cm = init_code_map(); - let end = init_expansion_chain(&cm); - let sstr = cm.span_to_expanded_string(end); - let res_str = -r"blork2.rs:2:1: 2:12 -`second line` - Callsite: - ... - blork2.rs:1:1: 1:12 - `first line.` - Callee: - blork.rs:2:1: 2:12 - `second line` - Callee: - blork.rs:1:1: 1:12 - `first line.` - Callsite: - blork.rs:1:1: 1:12 - `first line.` - Callsite: - ... - blork.rs:2:1: 2:12 - `second line` - Callee: - blork.rs:1:1: 1:12 - `first line.` - Callsite: - blork.rs:1:1: 1:12 - `first line.` -"; - assert_eq!(sstr, res_str); - } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1c9a05dadd15f..1b62d62348bc8 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -263,10 +263,6 @@ pub const NO_EXPANSION: ExpnId = ExpnId(!0); // For code appearing from the command line pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); -// For code generated by a procedural macro, without knowing which -// Used in `qquote!` -pub const PROC_EXPN: ExpnId = ExpnId(!2); - impl ExpnId { pub fn from_u32(id: u32) -> ExpnId { ExpnId(id) From ec7c0aece17c9a11bc2eca15b994355a161bf878 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 17 Mar 2017 04:04:41 +0000 Subject: [PATCH 338/662] Merge `ExpnId` and `SyntaxContext`. --- src/librustc/hir/lowering.rs | 7 +- src/librustc/hir/mod.rs | 5 +- src/librustc/ich/caching_codemap_view.rs | 4 - src/librustc/middle/region.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_driver/driver.rs | 4 +- src/librustc_errors/emitter.rs | 22 +- src/librustc_errors/lib.rs | 4 +- .../calculate_svh/svh_visitor.rs | 17 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_plugin/load.rs | 4 +- src/librustc_save_analysis/lib.rs | 7 +- src/librustc_save_analysis/span_utils.rs | 3 +- src/librustc_trans/asm.rs | 4 +- src/librustc_trans/back/write.rs | 6 +- src/librustc_trans/mir/mod.rs | 18 +- src/librustc_typeck/check/mod.rs | 5 +- src/libsyntax/ast.rs | 57 +--- src/libsyntax/codemap.rs | 291 +----------------- src/libsyntax/ext/base.rs | 74 ++--- src/libsyntax/ext/derive.rs | 50 +-- src/libsyntax/ext/expand.rs | 111 +++---- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 14 +- src/libsyntax/feature_gate.rs | 20 +- src/libsyntax/json.rs | 2 +- src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +- src/libsyntax/std_inject.rs | 21 +- src/libsyntax/test.rs | 21 +- src/libsyntax/test_snippet.rs | 2 +- src/libsyntax/tokenstream.rs | 16 +- src/libsyntax_ext/asm.rs | 12 +- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 12 +- src/libsyntax_ext/deriving/mod.rs | 34 +- src/libsyntax_ext/format.rs | 3 +- src/libsyntax_ext/proc_macro_registrar.rs | 6 +- src/libsyntax_pos/hygiene.rs | 94 +++++- src/libsyntax_pos/lib.rs | 101 ++++-- src/{libsyntax => libsyntax_pos}/symbol.rs | 57 +++- src/test/compile-fail-fulldeps/qquote.rs | 8 - src/test/run-fail-fulldeps/qquote.rs | 8 - src/test/run-pass-fulldeps/qquote.rs | 8 - 46 files changed, 456 insertions(+), 702 deletions(-) rename src/{libsyntax => libsyntax_pos}/symbol.rs (87%) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6ca0c971ea497..786145f3091db 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -57,6 +57,7 @@ use std::mem; use syntax::attr; use syntax::ast::*; use syntax::errors; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::codemap::{self, respan, Spanned}; use syntax::std_inject; @@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> { } fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span { - span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(codemap::ExpnInfo { call_site: span, callee: codemap::NameAndSpan { format: codemap::CompilerDesugaring(Symbol::intern(reason)), @@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> { allow_internal_unstable: true, }, }); + span.ctxt = SyntaxContext::empty().apply_mark(mark); span } @@ -1986,7 +1989,7 @@ impl<'a> LoweringContext<'a> { volatile: asm.volatile, alignstack: asm.alignstack, dialect: asm.dialect, - expn_id: asm.expn_id, + ctxt: asm.ctxt, }; let outputs = asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f4f2f4cf9211b..da7e71ac07d21 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,11 +33,12 @@ use hir::def::Def; use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; @@ -1367,7 +1368,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// represents an argument in a function header diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index a71251eedf5d0..1278d9f5171b3 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> { } } - pub fn codemap(&self) -> &'tcx CodeMap { - self.codemap - } - pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> Option<(Rc, usize, BytePos)> { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index a19f15a9329fb..0676075930dc3 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -236,7 +236,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt }) } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4354ed6817ae9..2b5ea61d4e854 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -467,7 +467,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) { - if self.sess.codemap().span_allows_unstable(span) { + if span.allows_unstable() { debug!("stability: \ skipping span={:?} since it is internal", span); return; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4873b21c54874..977382b33adf7 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -580,7 +580,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.clone(); - syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); let mut addl_plugins = Some(addl_plugins); @@ -798,7 +798,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { - syntax::ext::hygiene::reset_hygiene_data(); + syntax::ext::hygiene::clear_markings(); } Ok(ExpansionResult { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 431edb3c9bc4d..367b85ac726db 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; @@ -151,7 +151,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { + if span_label.span == DUMMY_SP { continue; } let lo = cm.lookup_char_pos(span_label.span.lo); @@ -615,7 +615,7 @@ impl EmitterWriter { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP { + if primary_span != &DUMMY_SP { let hi = cm.lookup_char_pos(primary_span.hi); if hi.line > max { max = hi.line; @@ -623,7 +623,7 @@ impl EmitterWriter { } } for span_label in msp.span_labels() { - if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP { + if span_label.span != DUMMY_SP { let hi = cm.lookup_char_pos(span_label.span.hi); if hi.line > max { max = hi.line; @@ -659,20 +659,20 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) { + if *sp == DUMMY_SP { continue; } if cm.span_to_filename(sp.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp.clone()); + let v = sp.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp.clone(), use_site.call_site.clone())); } } - for trace in cm.macro_backtrace(sp.clone()).iter().rev() { + for trace in sp.macro_backtrace().iter().rev() { // Only show macro locations that are local // and display them like a span_note if let Some(def_site) = trace.def_site_span { - if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) { + if def_site == DUMMY_SP { continue; } // Check to make sure we're not in any <*macros> @@ -689,11 +689,11 @@ impl EmitterWriter { span.push_span_label(label_span, label_text); } for sp_label in span.span_labels() { - if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) { + if sp_label.span == DUMMY_SP { continue; } if cm.span_to_filename(sp_label.span.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp_label.span.clone()); + let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); } @@ -848,7 +848,7 @@ impl EmitterWriter { // Make sure our primary file comes first let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), msp.primary_span().as_ref()) { - if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + if primary_span != &&DUMMY_SP { cm.lookup_char_pos(primary_span.lo) } else { emit_to_destination(&buffer.render(), level, &mut self.dst)?; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4c889dad8ca50..2efdaa57fba36 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -48,7 +48,6 @@ pub mod styled_buffer; mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; -use syntax_pos::MacroBacktrace; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum RenderSpan { @@ -75,7 +74,6 @@ pub trait CodeMapper { fn span_to_lines(&self, sp: Span) -> FileLinesResult; fn span_to_string(&self, sp: Span) -> String; fn span_to_filename(&self, sp: Span) -> FileName; - fn macro_backtrace(&self, span: Span) -> Vec; fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; } @@ -120,7 +118,7 @@ impl CodeSuggestion { let bounding_span = Span { lo: lo, hi: hi, - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 210803c3f329c..5401b371888e9 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,9 +17,10 @@ use self::SawTraitOrImplItemComponent::*; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; use syntax::parse::token; use syntax::symbol::InternedString; -use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax_pos::{Span, BytePos}; use syntax::tokenstream; use rustc::hir; use rustc::hir::*; @@ -92,10 +93,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let expn_kind = match span.expn_id { - NO_EXPANSION => SawSpanExpnKind::NoExpansion, - COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, - _ => SawSpanExpnKind::SomeExpansion, + let expn_kind = if span.ctxt == SyntaxContext::empty() { + SawSpanExpnKind::NoExpansion + } else { + SawSpanExpnKind::SomeExpansion }; let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); @@ -121,8 +122,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { saw.hash(self.st); if expn_kind == SawSpanExpnKind::SomeExpansion { - let call_site = self.codemap.codemap().source_callsite(span); - self.hash_span(call_site); + self.hash_span(span.source_callsite()); } } @@ -483,7 +483,6 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { #[derive(Clone, Copy, Hash, Eq, PartialEq)] enum SawSpanExpnKind { NoExpansion, - CommandLine, SomeExpansion, } @@ -501,7 +500,7 @@ impl<'a> Hash for StableInlineAsm<'a> { volatile, alignstack, dialect, - expn_id: _, // This is used for error reporting + ctxt: _, // This is used for error reporting } = *self.0; asm.as_str().hash(state); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ba42804c9262f..9d236bd013c43 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } // This comes from a macro that has #[allow_internal_unstable]. - if self.tcx.sess.codemap().span_allows_unstable(self.span) { + if self.span.allows_unstable() { return; } @@ -805,7 +805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.def_id.is_local() && // this doesn't come from a macro that has #[allow_internal_unstable] - !self.tcx.sess.codemap().span_allows_unstable(self.span) + !self.span.allows_unstable() { let mut err = self.tcx.sess.struct_span_err(self.span, "const fns are an unstable feature"); diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index efe9963cecc73..e884f3bdbb122 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax_pos::{Span, COMMAND_LINE_SP}; +use syntax_pos::{Span, DUMMY_SP}; /// Pointer to a registrar function. pub type PluginRegistrarFun = @@ -81,7 +81,7 @@ pub fn load_plugins(sess: &Session, if let Some(plugins) = addl_plugins { for plugin in plugins { - loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]); + loader.load_plugin(DUMMY_SP, &plugin, vec![]); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e5c04f6b61ec2..fd6803e087a08 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -690,9 +690,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // Note we take care to use the source callsite/callee, to handle // nested expansions and ensure we only generate data for source-visible // macro uses. - let callsite = self.tcx.sess.codemap().source_callsite(span); - let callee = self.tcx.sess.codemap().source_callee(span); - let callee = option_try!(callee); + let callsite = span.source_callsite(); + let callee = option_try!(span.source_callee()); let callee_span = option_try!(callee.span); // Ignore attribute macros, their spans are usually mangled @@ -1013,5 +1012,5 @@ fn escape(s: String) -> String { // Helper function to determine if a span came from a // macro expansion or syntax extension. pub fn generated_code(span: Span) -> bool { - span.expn_id != NO_EXPANSION || span == DUMMY_SP + span.ctxt != NO_EXPANSION || span == DUMMY_SP } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 34402742e6c33..c19f805a28575 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -462,8 +462,7 @@ impl<'a> SpanUtils<'a> { // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root // callsite. This filters out macro internal variables and most malformed spans. - let span = self.sess.codemap().source_callsite(parent); - !(span.contains(parent)) + !parent.source_callsite().contains(parent) } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index b6195765b27c2..3e270b7928ebc 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -111,14 +111,14 @@ pub fn trans_inline_asm<'a, 'tcx>( bcx.store(v, val, None); } - // Store expn_id in a metadata node so we can map LLVM errors + // Store mark in a metadata node so we can map LLVM errors // back to source locations. See #17552. unsafe { let key = "srcloc"; let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx.llcx(), key.as_ptr() as *const c_char, key.len() as c_uint); - let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32); + let val: llvm::ValueRef = C_i32(bcx.ccx, ia.ctxt.outer().as_u32() as i32); llvm::LLVMSetMetadata(r, kind, llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5a017e4fb8a9a..ccb3f7ac882aa 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -371,14 +371,14 @@ struct HandlerFreeVars<'a> { unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, msg: &'b str, cookie: c_uint) { - use syntax_pos::ExpnId; + use syntax::ext::hygiene::Mark; match cgcx.lto_ctxt { Some((sess, _)) => { - sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info { + match Mark::from_u32(cookie).expn_info() { Some(ei) => sess.span_err(ei.call_site, msg), None => sess.err(msg), - }); + }; } None => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b6d..21bbbea77d442 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -26,7 +26,7 @@ use monomorphize::{self, Instance}; use abi::FnType; use type_of; -use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; +use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; use syntax::symbol::keywords; use std::iter; @@ -124,24 +124,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site // (unless the crate is being compiled with `-Z debug-macros`). - if source_info.span.expn_id == NO_EXPANSION || - source_info.span.expn_id == COMMAND_LINE_EXPN || - self.ccx.sess().opts.debugging_opts.debug_macros { - + if source_info.span.ctxt == NO_EXPANSION || + self.ccx.sess().opts.debugging_opts.debug_macros { let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo); (scope, source_info.span) } else { - let cm = self.ccx.sess().codemap(); // Walk up the macro expansion chain until we reach a non-expanded span. // We also stop at the function body level because no line stepping can occurr // at the level above that. let mut span = source_info.span; - while span.expn_id != NO_EXPANSION && - span.expn_id != COMMAND_LINE_EXPN && - span.expn_id != self.mir.span.expn_id { - if let Some(callsite_span) = cm.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite_span; + while span.ctxt != NO_EXPANSION && span.ctxt != self.mir.span.ctxt { + if let Some(info) = span.ctxt.outer().expn_info() { + span = info.call_site; } else { break; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c62fd486d45a..b95e01f4ff600 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4161,12 +4161,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } if let Some(last_stmt) = extra_semi { - let original_span = original_sp(self.tcx.sess.codemap(), - last_stmt.span, blk.span); + let original_span = original_sp(last_stmt.span, blk.span); let span_semi = Span { lo: original_span.hi - BytePos(1), hi: original_span.hi, - expn_id: original_span.expn_id + ctxt: original_span.ctxt, }; err.span_help(span_semi, "consider removing this semicolon:"); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7e2b225193f6d..a4bebd311ded2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -14,10 +14,10 @@ pub use self::TyParamBound::*; pub use self::UnsafeSource::*; pub use self::ViewPath_::*; pub use self::PathParameters::*; -pub use symbol::Symbol as Name; +pub use symbol::{Ident, Symbol as Name}; pub use util::ThinVec; -use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; @@ -27,61 +27,12 @@ use rustc_data_structures::indexed_vec; use symbol::{Symbol, keywords}; use tokenstream::{ThinTokenStream, TokenStream}; +use serialize::{self, Encoder, Decoder}; use std::collections::HashSet; use std::fmt; use std::rc::Rc; use std::u32; -use serialize::{self, Encodable, Decodable, Encoder, Decoder}; - -/// An identifier contains a Name (index into the interner -/// table) and a SyntaxContext to track renaming and -/// macro expansion per Flatt et al., "Macros That Work Together" -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Ident { - pub name: Symbol, - pub ctxt: SyntaxContext -} - -impl Ident { - pub const fn with_empty_ctxt(name: Name) -> Ident { - Ident { name: name, ctxt: SyntaxContext::empty() } - } - - /// Maps a string to an identifier with an empty syntax context. - pub fn from_str(s: &str) -> Ident { - Ident::with_empty_ctxt(Symbol::intern(s)) - } - - pub fn unhygienize(&self) -> Ident { - Ident { name: self.name, ctxt: SyntaxContext::empty() } - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{:?}", self.name, self.ctxt) - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.name, f) - } -} - -impl Encodable for Ident { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.name.encode(s) - } -} - -impl Decodable for Ident { - fn decode(d: &mut D) -> Result { - Ok(Ident::with_empty_ctxt(Name::decode(d)?)) - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, @@ -1445,7 +1396,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// An argument in a function header. diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 388f3cb732351..ba199eacb6276 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -17,6 +17,8 @@ //! within the CodeMap, which upon request can be converted to line and column //! information, source code snippets, etc. +pub use syntax_pos::*; +pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; pub use self::ExpnFormat::*; use std::cell::RefCell; @@ -26,35 +28,21 @@ use std::rc::Rc; use std::env; use std::fs; use std::io::{self, Read}; -pub use syntax_pos::*; use errors::CodeMapper; -use ast::Name; - /// Return the span itself if it doesn't come from a macro expansion, /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. -pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { - let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site)); - let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site)); +pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { + let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site); + let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site); match (call_site1, call_site2) { (None, _) => sp, (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp, - (Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp), + (Some(call_site1), _) => original_sp(call_site1, enclosing_sp), } } -/// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] -pub enum ExpnFormat { - /// e.g. #[derive(...)] - MacroAttribute(Name), - /// e.g. `format!()` - MacroBang(Name), - /// Desugaring done by the compiler during HIR lowering. - CompilerDesugaring(Name) -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub struct Spanned { pub node: T, @@ -73,47 +61,6 @@ pub fn dummy_spanned(t: T) -> Spanned { respan(DUMMY_SP, t) } -#[derive(Clone, Hash, Debug)] -pub struct NameAndSpan { - /// The format with which the macro was invoked. - pub format: ExpnFormat, - /// Whether the macro is allowed to use #[unstable]/feature-gated - /// features internally without forcing the whole crate to opt-in - /// to them. - pub allow_internal_unstable: bool, - /// The span of the macro definition itself. The macro may not - /// have a sensible definition span (e.g. something defined - /// completely inside libsyntax) in which case this is None. - pub span: Option -} - -impl NameAndSpan { - pub fn name(&self) -> Name { - match self.format { - ExpnFormat::MacroAttribute(s) | - ExpnFormat::MacroBang(s) | - ExpnFormat::CompilerDesugaring(s) => s, - } - } -} - -/// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Hash, Debug)] -pub struct ExpnInfo { - /// The location of the actual macro invocation or syntax sugar , e.g. - /// `let x = foo!();` or `if let Some(y) = x {}` - /// - /// This may recursively refer to other macro invocations, e.g. if - /// `foo!()` invoked `bar!()` internally, and there was an - /// expression inside `bar!`; the call_site of the expression in - /// the expansion would point to the `bar!` invocation; that - /// call_site span would have its own ExpnInfo, with the call_site - /// pointing to the `foo!` invocation. - pub call_site: Span, - /// Information about the expansion. - pub callee: NameAndSpan -} - // _____________________________________________________________________________ // FileMap, MultiByteChar, FileName, FileLines // @@ -161,7 +108,6 @@ impl FileLoader for RealFileLoader { pub struct CodeMap { pub files: RefCell>>, - expansions: RefCell>, file_loader: Box } @@ -169,7 +115,6 @@ impl CodeMap { pub fn new() -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: Box::new(RealFileLoader) } } @@ -177,7 +122,6 @@ impl CodeMap { pub fn with_file_loader(file_loader: Box) -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: file_loader } } @@ -353,14 +297,14 @@ impl CodeMap { /// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If /// there are gaps between lhs and rhs, the resulting union will cross these gaps. /// For this to work, the spans have to be: - /// * the expn_id of both spans much match + /// * the ctxt of both spans much match /// * the lhs span needs to end on the same line the rhs span begins /// * the lhs span must start at or before the rhs span pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { use std::cmp; // make sure we're at the same expansion id - if sp_lhs.expn_id != sp_rhs.expn_id { + if sp_lhs.ctxt != sp_rhs.ctxt { return None; } @@ -383,7 +327,7 @@ impl CodeMap { Some(Span { lo: cmp::min(sp_lhs.lo, sp_rhs.lo), hi: cmp::max(sp_lhs.hi, sp_rhs.hi), - expn_id: sp_lhs.expn_id, + ctxt: sp_lhs.ctxt, }) } else { None @@ -391,10 +335,6 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { - if sp == COMMAND_LINE_SP { - return "".to_string(); - } - if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -409,62 +349,6 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } - /// Return the source span - this is either the supplied span, or the span for - /// the macro callsite that expanded to it. - pub fn source_callsite(&self, sp: Span) -> Span { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is the first callsite, which is also source-equivalent to the span. - let mut first = true; - while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { - if let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return Span { expn_id: NO_EXPANSION, .. span }; - } - } - first = false; - span = callsite; - } - else { - break; - } - } - span - } - - /// Return the source callee. - /// - /// Returns None if the supplied span has no expansion trace, - /// else returns the NameAndSpan for the macro definition - /// corresponding to the source callsite. - pub fn source_callee(&self, sp: Span) -> Option { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is source-equivalent to the span, and the source callee is the first callee. - let mut first = true; - while let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - first = false; - if let Some(_) = self.with_expn_info(callsite.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite; - } - else { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - None - } - pub fn span_to_filename(&self, sp: Span) -> FileName { self.lookup_char_pos(sp.lo).file.name.to_string() } @@ -628,111 +512,9 @@ impl CodeMap { return a; } - pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { - let mut expansions = self.expansions.borrow_mut(); - expansions.push(expn_info); - let len = expansions.len(); - if len > u32::max_value() as usize { - panic!("too many ExpnInfo's!"); - } - ExpnId(len as u32 - 1) - } - - pub fn with_expn_info(&self, id: ExpnId, f: F) -> T where - F: FnOnce(Option<&ExpnInfo>) -> T, - { - match id { - NO_EXPANSION | COMMAND_LINE_EXPN => f(None), - ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize])) - } - } - - /// Check if a span is "internal" to a macro in which #[unstable] - /// items can be used (that is, a macro marked with - /// `#[allow_internal_unstable]`). - pub fn span_allows_unstable(&self, span: Span) -> bool { - debug!("span_allows_unstable(span = {:?})", span); - let mut allows_unstable = false; - let mut expn_id = span.expn_id; - loop { - let quit = self.with_expn_info(expn_id, |expninfo| { - debug!("span_allows_unstable: expninfo = {:?}", expninfo); - expninfo.map_or(/* hit the top level */ true, |info| { - - let span_comes_from_this_expansion = - info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| { - mac_span.contains(span) - }); - - debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", - (span.lo, span.hi), - (info.call_site.lo, info.call_site.hi), - info.callee.span.map(|x| (x.lo, x.hi))); - debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", - span_comes_from_this_expansion, - info.callee.allow_internal_unstable); - if span_comes_from_this_expansion { - allows_unstable = info.callee.allow_internal_unstable; - // we've found the right place, stop looking - true - } else { - // not the right place, keep looking - expn_id = info.call_site.expn_id; - false - } - }) - }); - if quit { - break - } - } - debug!("span_allows_unstable? {}", allows_unstable); - allows_unstable - } - pub fn count_lines(&self) -> usize { self.files.borrow().iter().fold(0, |a, f| a + f.count_lines()) } - - pub fn macro_backtrace(&self, span: Span) -> Vec { - let mut prev_span = DUMMY_SP; - let mut span = span; - let mut result = vec![]; - loop { - let span_name_span = self.with_expn_info(span.expn_id, |expn_info| { - expn_info.map(|ei| { - let (pre, post) = match ei.callee.format { - MacroAttribute(..) => ("#[", "]"), - MacroBang(..) => ("", "!"), - CompilerDesugaring(..) => ("desugaring of `", "`"), - }; - let macro_decl_name = format!("{}{}{}", - pre, - ei.callee.name(), - post); - let def_site_span = ei.callee.span; - (ei.call_site, macro_decl_name, def_site_span) - }) - }); - - match span_name_span { - None => break, - Some((call_site, macro_decl_name, def_site_span)) => { - // Don't print recursive invocations - if !call_site.source_equal(&prev_span) { - result.push(MacroBacktrace { - call_site: call_site, - macro_decl_name: macro_decl_name, - def_site_span: def_site_span, - }); - } - prev_span = span; - span = call_site; - } - } - } - result - } } impl CodeMapper for CodeMap { @@ -748,9 +530,6 @@ impl CodeMapper for CodeMap { fn span_to_filename(&self, sp: Span) -> FileName { self.span_to_filename(sp) } - fn macro_backtrace(&self, span: Span) -> Vec { - self.macro_backtrace(span) - } fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { self.merge_spans(sp_lhs, sp_rhs) } @@ -763,7 +542,6 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use symbol::keywords; use std::rc::Rc; #[test] @@ -912,7 +690,7 @@ mod tests { fn t7() { // Test span_to_lines for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let file_lines = cm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, "blork.rs"); @@ -928,7 +706,7 @@ mod tests { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); - Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } + Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION } } /// Test span_to_snippet and span_to_lines for a span coverting 3 @@ -958,7 +736,7 @@ mod tests { fn t8() { // Test span_to_snippet for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let snippet = cm.span_to_snippet(span); assert_eq!(snippet, Ok("second line".to_string())); @@ -968,7 +746,7 @@ mod tests { fn t9() { // Test span_to_str for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let sstr = cm.span_to_string(span); assert_eq!(sstr, "blork.rs:2:1: 2:12"); @@ -1022,7 +800,7 @@ mod tests { let span = Span { lo: BytePos(lo as u32 + file.start_pos.0), hi: BytePos(hi as u32 + file.start_pos.0), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); @@ -1032,45 +810,4 @@ mod tests { } } } - - fn init_expansion_chain(cm: &CodeMap) -> Span { - // Creates an expansion chain containing two recursive calls - // root -> expA -> expA -> expB -> expB -> end - let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - - let format_root = ExpnFormat::MacroBang(keywords::Invalid.name()); - let callee_root = NameAndSpan { format: format_root, - allow_internal_unstable: false, - span: Some(root) }; - - let info_a1 = ExpnInfo { call_site: root, callee: callee_root }; - let id_a1 = cm.record_expansion(info_a1); - let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 }; - - let format_a = ExpnFormat::MacroBang(keywords::As.name()); - let callee_a = NameAndSpan { format: format_a, - allow_internal_unstable: false, - span: Some(span_a1) }; - - let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() }; - let id_a2 = cm.record_expansion(info_a2); - let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 }; - - let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a }; - let id_b1 = cm.record_expansion(info_b1); - let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 }; - - let format_b = ExpnFormat::MacroBang(keywords::Box.name()); - let callee_b = NameAndSpan { format: format_b, - allow_internal_unstable: false, - span: None }; - - let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() }; - let id_b2 = cm.record_expansion(info_b2); - let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 }; - - let info_end = ExpnInfo { call_site: span_b2, callee: callee_b }; - let id_end = cm.record_expansion(info_end); - Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } - } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dc7e7673eb03c..a2d54b62ec65d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT use ast::{self, Attribute, Name, PatKind, MetaItem}; use attr::HasAttrs; -use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; -use syntax_pos::{Span, ExpnId, NO_EXPANSION}; -use errors::{DiagnosticBuilder, FatalError}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{Span, DUMMY_SP}; +use errors::DiagnosticBuilder; use ext::expand::{self, Expansion, Invocation}; -use ext::hygiene::Mark; +use ext::hygiene::{Mark, SyntaxContext}; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; @@ -56,6 +56,14 @@ impl HasAttrs for Annotatable { } impl Annotatable { + pub fn span(&self) -> Span { + match *self { + Annotatable::Item(ref item) => item.span, + Annotatable::TraitItem(ref trait_item) => trait_item.span, + Annotatable::ImplItem(ref impl_item) => impl_item.span, + } + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -602,7 +610,6 @@ pub struct ModuleData { pub struct ExpansionData { pub mark: Mark, pub depth: usize, - pub backtrace: ExpnId, pub module: Rc, pub directory_ownership: DirectoryOwnership, } @@ -633,7 +640,6 @@ impl<'a> ExtCtxt<'a> { current_expansion: ExpansionData { mark: Mark::root(), depth: 0, - backtrace: NO_EXPANSION, module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), directory_ownership: DirectoryOwnership::Owned, }, @@ -658,30 +664,30 @@ impl<'a> ExtCtxt<'a> { pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { - self.codemap().with_expn_info(self.backtrace(), |ei| match ei { + match self.current_expansion.mark.expn_info() { Some(expn_info) => expn_info.call_site, - None => self.bug("missing top span") - }) + None => DUMMY_SP, + } + } + pub fn backtrace(&self) -> SyntaxContext { + SyntaxContext::empty().apply_mark(self.current_expansion.mark) } - pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Span { - let mut expn_id = self.backtrace(); + let mut ctxt = self.backtrace(); let mut last_macro = None; loop { - if self.codemap().with_expn_info(expn_id, |info| { - info.map_or(None, |i| { - if i.callee.name() == "include" { - // Stop going up the backtrace once include! is encountered - return None; - } - expn_id = i.call_site.expn_id; - last_macro = Some(i.call_site); - return Some(()); - }) + if ctxt.outer().expn_info().map_or(None, |info| { + if info.callee.name() == "include" { + // Stop going up the backtrace once include! is encountered + return None; + } + ctxt = info.call_site.ctxt; + last_macro = Some(info.call_site); + return Some(()); }).is_none() { break } @@ -689,28 +695,6 @@ impl<'a> ExtCtxt<'a> { last_macro.expect("missing expansion backtrace") } - pub fn bt_push(&mut self, ei: ExpnInfo) { - if self.current_expansion.depth > self.ecfg.recursion_limit { - let suggested_limit = self.ecfg.recursion_limit * 2; - let mut err = self.struct_span_fatal(ei.call_site, - &format!("recursion limit reached while expanding the macro `{}`", - ei.callee.name())); - err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); - err.emit(); - panic!(FatalError); - } - - let mut call_site = ei.call_site; - call_site.expn_id = self.backtrace(); - self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo { - call_site: call_site, - callee: ei.callee - }); - } - pub fn bt_pop(&mut self) {} - pub fn struct_span_warn(&self, sp: Span, msg: &str) @@ -792,9 +776,9 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns None. pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) -> Option> { - // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. + // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { - expr.span.expn_id = cx.backtrace(); + expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark); expr }); diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 1569d9f540b8e..c79040424f619 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -9,13 +9,16 @@ // except according to those terms. use attr::HasAttrs; -use {ast, codemap}; +use ast; +use codemap::{ExpnInfo, NameAndSpan, ExpnFormat}; use ext::base::ExtCtxt; use ext::build::AstBuilder; use parse::parser::PathStyle; use symbol::Symbol; use syntax_pos::Span; +use std::collections::HashSet; + pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { @@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec result } -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span +pub fn add_derived_markers(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T + where T: HasAttrs, +{ + let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned()); + for (i, path) in traits.iter().enumerate() { + if i > 0 { + pretty_name.push_str(", "); + } + pretty_name.push_str(&path.to_string()); + names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name); } -} + pretty_name.push(')'); -pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T { - let span = match traits.get(0) { - Some(path) => path.span, - None => return item, - }; + cx.current_expansion.mark.set_expn_info(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), + span: None, + allow_internal_unstable: true, + }, + }); + let span = Span { ctxt: cx.backtrace(), ..span }; item.map_attrs(|mut attrs| { - if traits.iter().any(|path| *path == "PartialEq") && - traits.iter().any(|path| *path == "Eq") { - let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) { let meta = cx.meta_word(span, Symbol::intern("structural_match")); attrs.push(cx.attribute(span, meta)); } - if traits.iter().any(|path| *path == "Copy") && - traits.iter().any(|path| *path == "Clone") { - let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) { let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); attrs.push(cx.attribute(span, meta)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e258c51a3295f..1b3352f73ade7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,6 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use config::{is_test_or_bench, StripUnconfigured}; +use errors::FatalError; use ext::base::*; use ext::derive::{add_derived_markers, collect_derives}; use ext::hygiene::Mark; @@ -27,7 +28,7 @@ use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = item .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = - add_derived_markers(&mut self.cx, &traits, item.clone()); + add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); for path in &traits { @@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { - match invoc.kind { + let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), + }; + + if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { + let info = self.cx.current_expansion.mark.expn_info().unwrap(); + let suggested_limit = self.cx.ecfg.recursion_limit * 2; + let mut err = self.cx.struct_span_fatal(info.call_site, + &format!("recursion limit reached while expanding the macro `{}`", + info.callee.name())); + err.help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); + err.emit(); + panic!(FatalError); } + + result } fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { @@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, callee: NameAndSpan { format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: Some(attr.span), + span: None, allow_internal_unstable: false, } }); @@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtension::AttrProcMacro(ref mac) => { let item_toks = stream_for_item(&item, &self.cx.parse_sess); - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: None, - allow_internal_unstable: false, - }, - }), - ..attr.span - }; - - let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); + let span = Span { ctxt: self.cx.backtrace(), ..attr.span }; + let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks); self.parse_expansion(tok_result, kind, &attr.path, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { @@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let path = &mac.node.path; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = - noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); + let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark)); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - expanded.fold_with(&mut Marker { - mark: mark, - expn_id: Some(self.cx.backtrace()), - }) + expanded.fold_with(&mut Marker(mark)) } /// Expand a derive invocation. Returns the result of expansion. @@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> { id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, }; - self.cx.bt_push(ExpnInfo { + let mut expn_info = ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroAttribute(pretty_name), span: None, allow_internal_unstable: false, } - }); + }; match *ext { SyntaxExtension::ProcMacroDerive(ref ext, _) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: false, - }, - }), - ..span - }; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this name: keywords::Invalid.name(), span: DUMMY_SP, node: ast::MetaItemKind::Word, }; - return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)); + kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)) } SyntaxExtension::BuiltinDerive(func) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: true, - }, - }), - ..span - }; + expn_info.callee.allow_internal_unstable = true; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let mut items = Vec::new(); func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); - return kind.expect_from_annotatables(items); + kind.expect_from_annotatables(items) } _ => { let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); @@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. fn check_attributes(&mut self, attrs: &[ast::Attribute]) { - let codemap = &self.cx.parse_sess.codemap(); let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { - feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features); + feature_gate::check_attribute(&attr, &self.cx.parse_sess, features); } } } @@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> { } } -// A Marker adds the given mark to the syntax context and -// sets spans' `expn_id` to the given expn_id (unless it is `None`). -struct Marker { mark: Mark, expn_id: Option } +// A Marker adds the given mark to the syntax context. +struct Marker(Mark); impl Folder for Marker { fn fold_ident(&mut self, mut ident: Ident) -> Ident { - ident.ctxt = ident.ctxt.apply_mark(self.mark); + ident.ctxt = ident.ctxt.apply_mark(self.0); ident } - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - noop_fold_mac(mac, self) - } fn new_span(&mut self, mut span: Span) -> Span { - if let Some(expn_id) = self.expn_id { - span.expn_id = expn_id; - } + span.ctxt = span.ctxt.apply_mark(self.0); span } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + noop_fold_mac(mac, self) + } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 39b92c7d007de..0103d6ea959dd 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf { // NB: relative paths are resolved relative to the compilation unit if !arg.is_absolute() { - let callsite = cx.codemap().source_callsite(sp); + let callsite = sp.source_callsite(); let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite)); cu.pop(); cu.push(arg); diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index d56859d805c87..12e746e024d3b 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -34,17 +34,19 @@ impl Delimited { } pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9d280a413e666..12d25ca4274fe 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -28,7 +28,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; -use codemap::{CodeMap, Spanned}; +use codemap::Spanned; use syntax_pos::Span; use errors::{DiagnosticBuilder, Handler, FatalError}; use visit::{self, FnKind, Visitor}; @@ -831,7 +831,7 @@ impl GatedCfg { pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) { + if !has_feature(features) && !self.span.allows_unstable() { let explain = format!("`cfg({})` is experimental and subject to change", cfg); emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); } @@ -841,7 +841,6 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } @@ -850,7 +849,7 @@ macro_rules! gate_feature_fn { let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain); let has_feature: bool = has_feature(&$cx.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !cx.cm.span_allows_unstable(span) { + if !has_feature && !span.allows_unstable() { emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain); } }} @@ -908,12 +907,8 @@ impl<'a> Context<'a> { } } -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, - cm: &CodeMap, features: &Features) { - let cx = Context { - features: features, parse_sess: parse_sess, - cm: cm, plugin_attributes: &[] - }; +pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] }; cx.check_attribute(attr, true); } @@ -1016,7 +1011,7 @@ struct PostExpansionVisitor<'a> { macro_rules! gate_feature_post { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ let (cx, span) = ($cx, $span); - if !cx.context.cm.span_allows_unstable(span) { + if !span.allows_unstable() { gate_feature!(cx.context, $feature, span, $explain) } }} @@ -1096,7 +1091,7 @@ fn starts_with_digit(s: &str) -> bool { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - if !self.context.cm.span_allows_unstable(attr.span) { + if !attr.span.allows_unstable() { // check for gated attributes self.context.check_attribute(attr, false); } @@ -1530,7 +1525,6 @@ pub fn check_crate(krate: &ast::Crate, let ctx = Context { features: features, parse_sess: sess, - cm: sess.codemap(), plugin_attributes: plugin_attributes, }; visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index fd762552248b4..dec1b7d1d87be 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -202,7 +202,7 @@ impl DiagnosticSpan { // backtrace ourselves, but the `macro_backtrace` helper makes // some decision, such as dropping some frames, and I don't // want to duplicate that logic here. - let backtrace = je.cm.macro_backtrace(span).into_iter(); + let backtrace = span.macro_backtrace().into_iter(); DiagnosticSpan::from_span_full(span, is_primary, label, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6c975f3fc4021..86ee1c5336dfe 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -125,7 +125,7 @@ pub mod ptr; pub mod show_span; pub mod std_inject; pub mod str; -pub mod symbol; +pub use syntax_pos::symbol; pub mod test; pub mod tokenstream; pub mod visit; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43a9d8c5f787c..e9eb4fbcc9162 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5036,11 +5036,7 @@ impl<'a> Parser<'a> { the path:", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let sp = Span { - lo: start_span.lo, - hi: self.prev_span.hi, - expn_id: start_span.expn_id, - }; + let sp = start_span.to(self.prev_span); let mut err = self.span_fatal_help(sp, &msg, &suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); err.emit(); // emit diagnostic, but continue with public visibility diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index c541df9230a64..c7820a15fb3d2 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,29 +10,27 @@ use ast; use attr; +use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; -use parse::ParseSess; use ptr::P; use tokenstream::TokenStream; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. /// The expanded code uses the unstable `#[prelude_import]` attribute. -fn ignored_span(sess: &ParseSess, sp: Span) -> Span { - let info = ExpnInfo { +fn ignored_span(sp: Span) -> Span { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("std_inject")), span: None, allow_internal_unstable: true, } - }; - let expn_id = sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + }); + Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp } } pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { @@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { } } -pub fn maybe_inject_crates_ref(sess: &ParseSess, - mut krate: ast::Crate, - alt_std_name: Option) - -> ast::Crate { +pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { let name = match injected_crate_name(&krate) { Some(name) => name, None => return krate, @@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, span: DUMMY_SP, })); - let span = ignored_span(sess, DUMMY_SP); + let span = ignored_span(DUMMY_SP); krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6fb6db9ca0282..50380626d7f0d 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -31,6 +31,7 @@ use entry::{self, EntryPointType}; use ext::base::{ExtCtxt, Resolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; +use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; use util::move_map::MoveMap; use fold; @@ -62,6 +63,7 @@ struct TestCtxt<'a> { testfns: Vec, reexport_test_harness_main: Option, is_test_crate: bool, + ctxt: SyntaxContext, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); + let mark = Mark::fresh(); let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, @@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: reexport_test_harness_main, is_test_crate: is_test_crate(&krate), toplevel_reexport: None, + ctxt: SyntaxContext::empty().apply_mark(mark), }; cx.ext_cx.crate_root = Some("std"); - cx.ext_cx.bt_push(ExpnInfo { + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("test")), span: None, - allow_internal_unstable: false, + allow_internal_unstable: true, } }); @@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess, /// call to codemap's is_internal check. /// The expanded code calls some unstable functions in the test crate. fn ignored_span(cx: &TestCtxt, sp: Span) -> Span { - let info = ExpnInfo { - call_site: sp, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("test")), - span: None, - allow_internal_unstable: true, - } - }; - let expn_id = cx.sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + Span { ctxt: cx.ctxt, ..sp } } #[derive(PartialEq)] diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c6d6e6237f2ed..c537a0ee16644 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { Span { lo: BytePos(start as u32), hi: BytePos(end as u32), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index b75b3efda36c8..86bfdebe42b00 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -56,18 +56,20 @@ impl Delimited { /// Returns the opening delimiter as a token tree. pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } /// Returns the closing delimiter as a token tree. pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } @@ -425,7 +427,7 @@ mod tests { Span { lo: BytePos(a), hi: BytePos(b), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 767ec94a0ce61..923e8072f4346 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -13,7 +13,6 @@ use self::State::*; use syntax::ast; -use syntax::codemap; use syntax::ext::base; use syntax::ext::base::*; use syntax::feature_gate; @@ -240,15 +239,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, } } - let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: sp, - callee: codemap::NameAndSpan { - format: codemap::MacroBang(Symbol::intern("asm")), - span: None, - allow_internal_unstable: false, - }, - }); - MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { @@ -260,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, volatile: volatile, alignstack: alignstack, dialect: dialect, - expn_id: expn_id, + ctxt: cx.backtrace(), })), span: sp, attrs: ast::ThinVec::new(), diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index d14b59d6c70e2..1993d6ebe5b49 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -111,7 +111,7 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Clone)"); + let span = Span { ctxt: cx.backtrace(), ..span}; let assert_path = cx.path_all(span, true, cx.std_path(&["clone", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 6ab5987a159ca..eef21492debc3 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -58,7 +58,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Eq)"); + let span = Span { ctxt: cx.backtrace(), ..span }; let assert_path = cx.path_all(span, true, cx.std_path(&["cmp", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index a767716466cb1..ec4cb815960d1 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -66,8 +66,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; - // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), ..span }; + // We want to make sure we have the ctxt set so that we can use unstable methods + let span = Span { ctxt: cx.backtrace(), ..span }; let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); let builder = Ident::from_str("builder"); let builder_expr = cx.expr_ident(span, builder.clone()); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 48e7ff0d24370..1ff0fec1c96a6 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -375,7 +375,7 @@ fn find_type_parameters(ty: &ast::Ty, } fn visit_mac(&mut self, mac: &ast::Mac) { - let span = Span { expn_id: self.span.expn_id, ..mac.span }; + let span = Span { ctxt: self.span.ctxt, ..mac.span }; self.cx.span_err(span, "`derive` cannot be used on items with type macros"); } } @@ -1458,7 +1458,7 @@ impl<'a> MethodDef<'a> { .iter() .map(|v| { let ident = v.node.name; - let sp = Span { expn_id: trait_.span.expn_id, ..v.span }; + let sp = Span { ctxt: trait_.span.ctxt, ..v.span }; let summary = trait_.summarise_struct(cx, &v.node.data); (ident, sp, summary) }) @@ -1478,7 +1478,7 @@ impl<'a> TraitDef<'a> { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); for field in struct_def.fields() { - let sp = Span { expn_id: self.span.expn_id, ..field.span }; + let sp = Span { ctxt: self.span.ctxt, ..field.span }; match field.ident { Some(ident) => named_idents.push((ident, sp)), _ => just_spans.push(sp), @@ -1523,7 +1523,7 @@ impl<'a> TraitDef<'a> { let mut paths = Vec::new(); let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = Span { expn_id: self.span.expn_id, ..struct_field.span }; + let sp = Span { ctxt: self.span.ctxt, ..struct_field.span }; let ident = cx.ident_of(&format!("{}_{}", prefix, i)); paths.push(codemap::Spanned { span: sp, @@ -1544,7 +1544,7 @@ impl<'a> TraitDef<'a> { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); } codemap::Spanned { - span: Span { expn_id: self.span.expn_id, ..pat.span }, + span: Span { ctxt: self.span.ctxt, ..pat.span }, node: ast::FieldPat { ident: ident.unwrap(), pat: pat, @@ -1576,7 +1576,7 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; - let sp = Span { expn_id: self.span.expn_id, ..variant.span }; + let sp = Span { ctxt: self.span.ctxt, ..variant.span }; let variant_path = cx.path(sp, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index b51591bf89d5e..b2bb43e41ed9e 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,9 +12,9 @@ use std::rc::Rc; use syntax::ast; -use syntax::codemap; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver}; use syntax::ext::build::AstBuilder; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -74,20 +74,6 @@ pub mod ord; pub mod generic; -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span - } -} - macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn is_builtin_trait(name: ast::Name) -> bool { @@ -177,15 +163,15 @@ fn call_intrinsic(cx: &ExtCtxt, intrinsic: &str, args: Vec>) -> P { - span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern("derive")), - span: Some(span), - allow_internal_unstable: true, - }, - }); - + if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable { + span.ctxt = cx.backtrace(); + } else { // Avoid instability errors with user defined curstom derives, cc #36316 + let mut info = cx.current_expansion.mark.expn_info().unwrap(); + info.callee.allow_internal_unstable = true; + let mark = Mark::fresh(); + mark.set_expn_info(info); + span.ctxt = SyntaxContext::empty().apply_mark(mark); + } let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index d2afa08cadaf4..aeb5b1e0a532b 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -641,10 +641,11 @@ impl<'a, 'b> Context<'a, 'b> { fn format_arg(ecx: &ExtCtxt, macsp: Span, - sp: Span, + mut sp: Span, ty: &ArgumentType, arg: P) -> P { + sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 2d815b3f1bb7d..bb89caab709b0 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -17,6 +17,7 @@ use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::fold::Folder; use syntax::parse::ParseSess; use syntax::ptr::P; @@ -360,7 +361,8 @@ fn mk_registrar(cx: &mut ExtCtxt, custom_derives: &[ProcMacroDerive], custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef]) -> P { - let eid = cx.codemap().record_expansion(ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("proc_macro")), @@ -368,7 +370,7 @@ fn mk_registrar(cx: &mut ExtCtxt, allow_internal_unstable: true, } }); - let span = Span { expn_id: eid, ..DUMMY_SP }; + let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP }; let proc_macro = Ident::from_str("proc_macro"); let krate = cx.item(span, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index feebbcd6f03b6..8a9ff647b3ea1 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -15,12 +15,16 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 +use Span; +use symbol::Symbol; + +use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContext(u32); #[derive(Copy, Clone)] @@ -36,8 +40,8 @@ pub struct Mark(u32); impl Mark { pub fn fresh() -> Self { HygieneData::with(|data| { - let next_mark = Mark(data.next_mark.0 + 1); - ::std::mem::replace(&mut data.next_mark, next_mark) + data.marks.push(None); + Mark(data.marks.len() as u32 - 1) }) } @@ -53,23 +57,31 @@ impl Mark { pub fn from_u32(raw: u32) -> Mark { Mark(raw) } + + pub fn expn_info(self) -> Option { + HygieneData::with(|data| data.marks[self.0 as usize].clone()) + } + + pub fn set_expn_info(self, info: ExpnInfo) { + HygieneData::with(|data| data.marks[self.0 as usize] = Some(info)) + } } struct HygieneData { + marks: Vec>, syntax_contexts: Vec, markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, - next_mark: Mark, } impl HygieneData { fn new() -> Self { HygieneData { + marks: vec![None], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), prev_ctxt: SyntaxContext::empty(), }], markings: HashMap::new(), - next_mark: Mark(1), } } @@ -81,8 +93,8 @@ impl HygieneData { } } -pub fn reset_hygiene_data() { - HygieneData::with(|data| *data = HygieneData::new()) +pub fn clear_markings() { + HygieneData::with(|data| data.markings = HashMap::new()); } impl SyntaxContext { @@ -113,6 +125,10 @@ impl SyntaxContext { }) }) } + + pub fn outer(self) -> Mark { + HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) + } } impl fmt::Debug for SyntaxContext { @@ -120,3 +136,67 @@ impl fmt::Debug for SyntaxContext { write!(f, "#{}", self.0) } } + +/// Extra information for tracking spans of macro and syntax sugar expansion +#[derive(Clone, Hash, Debug)] +pub struct ExpnInfo { + /// The location of the actual macro invocation or syntax sugar , e.g. + /// `let x = foo!();` or `if let Some(y) = x {}` + /// + /// This may recursively refer to other macro invocations, e.g. if + /// `foo!()` invoked `bar!()` internally, and there was an + /// expression inside `bar!`; the call_site of the expression in + /// the expansion would point to the `bar!` invocation; that + /// call_site span would have its own ExpnInfo, with the call_site + /// pointing to the `foo!` invocation. + pub call_site: Span, + /// Information about the expansion. + pub callee: NameAndSpan +} + +#[derive(Clone, Hash, Debug)] +pub struct NameAndSpan { + /// The format with which the macro was invoked. + pub format: ExpnFormat, + /// Whether the macro is allowed to use #[unstable]/feature-gated + /// features internally without forcing the whole crate to opt-in + /// to them. + pub allow_internal_unstable: bool, + /// The span of the macro definition itself. The macro may not + /// have a sensible definition span (e.g. something defined + /// completely inside libsyntax) in which case this is None. + pub span: Option +} + +impl NameAndSpan { + pub fn name(&self) -> Symbol { + match self.format { + ExpnFormat::MacroAttribute(s) | + ExpnFormat::MacroBang(s) | + ExpnFormat::CompilerDesugaring(s) => s, + } + } +} + +/// The source of expansion. +#[derive(Clone, Hash, Debug, PartialEq, Eq)] +pub enum ExpnFormat { + /// e.g. #[derive(...)] + MacroAttribute(Symbol), + /// e.g. `format!()` + MacroBang(Symbol), + /// Desugaring done by the compiler during HIR lowering. + CompilerDesugaring(Symbol) +} + +impl Encodable for SyntaxContext { + fn encode(&self, _: &mut E) -> Result<(), E::Error> { + Ok(()) // FIXME(jseyfried) intercrate hygiene + } +} + +impl Decodable for SyntaxContext { + fn decode(_: &mut D) -> Result { + Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene + } +} diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1b62d62348bc8..9b45e364ecf34 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -25,6 +25,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] @@ -43,6 +44,9 @@ extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving pub mod hygiene; +pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan}; + +pub mod symbol; pub type FileName = String; @@ -60,7 +64,7 @@ pub struct Span { pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. - pub expn_id: ExpnId + pub ctxt: SyntaxContext, } /// A collection of spans. Spans have two orthogonal attributes: @@ -79,7 +83,7 @@ impl Span { /// Returns a new span representing just the end-point of this span pub fn end_point(self) -> Span { let lo = cmp::max(self.hi.0 - 1, self.lo.0); - Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} + Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. @@ -107,6 +111,69 @@ impl Span { None } } + + /// Return the source span - this is either the supplied span, or the span for + /// the macro callsite that expanded to it. + pub fn source_callsite(self) -> Span { + self.ctxt.outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + } + + /// Return the source callee. + /// + /// Returns None if the supplied span has no expansion trace, + /// else returns the NameAndSpan for the macro definition + /// corresponding to the source callsite. + pub fn source_callee(self) -> Option { + fn source_callee(info: ExpnInfo) -> NameAndSpan { + match info.call_site.ctxt.outer().expn_info() { + Some(info) => source_callee(info), + None => info.callee, + } + } + self.ctxt.outer().expn_info().map(source_callee) + } + + /// Check if a span is "internal" to a macro in which #[unstable] + /// items can be used (that is, a macro marked with + /// `#[allow_internal_unstable]`). + pub fn allows_unstable(&self) -> bool { + match self.ctxt.outer().expn_info() { + Some(info) => info.callee.allow_internal_unstable, + None => false, + } + } + + pub fn macro_backtrace(mut self) -> Vec { + let mut prev_span = DUMMY_SP; + let mut result = vec![]; + loop { + let info = match self.ctxt.outer().expn_info() { + Some(info) => info, + None => break, + }; + + let (pre, post) = match info.callee.format { + ExpnFormat::MacroAttribute(..) => ("#[", "]"), + ExpnFormat::MacroBang(..) => ("", "!"), + ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + }; + let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post); + let def_site_span = info.callee.span; + + // Don't print recursive invocations + if !info.call_site.source_equal(&prev_span) { + result.push(MacroBacktrace { + call_site: info.call_site, + macro_decl_name: macro_decl_name, + def_site_span: def_site_span, + }); + } + + prev_span = self; + self = info.call_site; + } + result + } } #[derive(Clone, Debug)] @@ -147,8 +214,8 @@ impl serialize::UseSpecializedDecodable for Span { } fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", - span.lo, span.hi, span.expn_id) + write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}", + span.lo, span.hi, span.ctxt) } impl fmt::Debug for Span { @@ -157,12 +224,7 @@ impl fmt::Debug for Span { } } -pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; - -// Generic span to be used for code originating from the command line -pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), - hi: BytePos(0), - expn_id: COMMAND_LINE_EXPN }; +pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION }; impl MultiSpan { pub fn new() -> MultiSpan { @@ -256,22 +318,7 @@ impl From for MultiSpan { } } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)] -pub struct ExpnId(pub u32); - -pub const NO_EXPANSION: ExpnId = ExpnId(!0); -// For code appearing from the command line -pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); - -impl ExpnId { - pub fn from_u32(id: u32) -> ExpnId { - ExpnId(id) - } - - pub fn into_u32(self) -> u32 { - self.0 - } -} +pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); /// Identifies an offset of a multi-byte character in a FileMap #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] @@ -651,7 +698,7 @@ thread_local!(pub static SPAN_DEBUG: Cell fmt:: /* assuming that we're not in macro expansion */ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, expn_id: NO_EXPANSION} + Span {lo: lo, hi: hi, ctxt: NO_EXPANSION} } pub struct MacroBacktrace { diff --git a/src/libsyntax/symbol.rs b/src/libsyntax_pos/symbol.rs similarity index 87% rename from src/libsyntax/symbol.rs rename to src/libsyntax_pos/symbol.rs index 2acbeee426bee..b866652c49f85 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -12,11 +12,58 @@ //! allows bidirectional lookup; i.e. given a value, one can easily find the //! type, and vice versa. +use hygiene::SyntaxContext; + use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct Ident { + pub name: Symbol, + pub ctxt: SyntaxContext, +} + +impl Ident { + pub const fn with_empty_ctxt(name: Symbol) -> Ident { + Ident { name: name, ctxt: SyntaxContext::empty() } + } + + /// Maps a string to an identifier with an empty syntax context. + pub fn from_str(string: &str) -> Ident { + Ident::with_empty_ctxt(Symbol::intern(string)) + } + + pub fn unhygienize(self) -> Ident { + Ident { name: self.name, ctxt: SyntaxContext::empty() } + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{:?}", self.name, self.ctxt) + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, f) + } +} + +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.name.encode(s) + } +} + +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(Ident::with_empty_ctxt(Symbol::decode(d)?)) + } +} + /// A symbol is an interned or gensymed string. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Symbol(u32); @@ -128,19 +175,19 @@ macro_rules! declare_keywords {( $( ($index: expr, $konst: ident, $string: expr) )* ) => { pub mod keywords { - use ast; + use super::{Symbol, Ident}; #[derive(Clone, Copy, PartialEq, Eq)] pub struct Keyword { - ident: ast::Ident, + ident: Ident, } impl Keyword { - #[inline] pub fn ident(self) -> ast::Ident { self.ident } - #[inline] pub fn name(self) -> ast::Name { self.ident.name } + #[inline] pub fn ident(self) -> Ident { self.ident } + #[inline] pub fn name(self) -> Symbol { self.ident.name } } $( #[allow(non_upper_case_globals)] pub const $konst: Keyword = Keyword { - ident: ast::Ident::with_empty_ctxt(super::Symbol($index)) + ident: Ident::with_empty_ctxt(super::Symbol($index)) }; )* } diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index bd25561065bea..272bf1150cacb 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -27,14 +27,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23"); diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index d692bb519c149..5518ab47c2bd2 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -30,14 +30,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23))); diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index b4ed57192ccf6..4a8246ec429c0 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -26,14 +26,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; macro_rules! check { From 0347ff58230af512c9521bdda7877b8bef9e9d34 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 23 Mar 2017 23:33:15 +0000 Subject: [PATCH 339/662] Attempt to cache git modules --- .travis.yml | 22 ++++++++++---- appveyor.yml | 4 ++- src/ci/docker/run.sh | 1 + src/ci/init_repo.sh | 71 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 7 deletions(-) create mode 100755 src/ci/init_repo.sh diff --git a/.travis.yml b/.travis.yml index b16957344ae1a..51e4440d58747 100644 --- a/.travis.yml +++ b/.travis.yml @@ -133,13 +133,14 @@ before_script: script: - > if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then - echo skipping, not a full build; - elif [ "$TRAVIS_OS_NAME" = "osx" ]; then - travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && - stamp src/ci/run.sh; + echo skipping, not a full build else - travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && - stamp src/ci/docker/run.sh $IMAGE; + stamp src/ci/init_repo.sh . "$HOME/rustsrc" && + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + stamp src/ci/run.sh; + else + stamp src/ci/docker/run.sh $IMAGE; + fi fi after_success: @@ -157,13 +158,21 @@ after_failure: - cat /tmp/sccache.log # Save tagged docker images we created and load them if they're available +# Travis saves caches whether the build failed or not, nuke rustsrc if +# the failure was while updating it (as it may be in an bad state) +# https://github.com/travis-ci/travis-ci/issues/4472 before_cache: - docker history -q rust-ci | grep -v missing | xargs docker save | gzip > $HOME/docker/rust-ci.tar.gz + - if [ ! -f $HOME/rustsrc/cache_valid1 ]; then + echo "WARNING rustsrc cache was invalid when saving"; + rm -rf $HOME/rustsrc && mkdir $HOME/rustsrc; + fi before_install: - zcat $HOME/docker/rust-ci.tar.gz | docker load || true + - mkdir -p $HOME/rustsrc notifications: email: false @@ -171,6 +180,7 @@ notifications: cache: directories: - $HOME/docker + - $HOME/rustsrc before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT diff --git a/appveyor.yml b/appveyor.yml index 0e7ebf12a2a91..48983513147eb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,7 +141,8 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' + - mkdir C:\cache\rustsrc + - sh src/ci/init_repo.sh . /c/cache/rustsrc - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh @@ -150,6 +151,7 @@ on_failure: - cat %CD%/sccache.log cache: + - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c418d427b15b3..71a4bfae3caf9 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -57,6 +57,7 @@ exec docker \ --env DEPLOY_ALT=$DEPLOY_ALT \ --env LOCAL_USER_ID=`id -u` \ --volume "$HOME/.cargo:/cargo" \ + --volume "$HOME/rustsrc:$HOME/rustsrc" \ --privileged \ --rm \ rust-ci \ diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh new file mode 100755 index 0000000000000..4e22907d9794c --- /dev/null +++ b/src/ci/init_repo.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# 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. + +set -o errexit +set -o pipefail +set -o nounset + +set -o xtrace + +ci_dir=$(cd $(dirname $0) && pwd) +. "$ci_dir/shared.sh" + +REPO_DIR="$1" +CACHE_DIR="$2" + +cache_src_dir="$CACHE_DIR/src" +# If the layout of the cache directory changes, bump the number here +# (and anywhere else this file is referenced) so the cache is wiped +cache_valid_file="$CACHE_DIR/cache_valid1" + +if [ ! -d "$REPO_DIR" -o ! -d "$REPO_DIR/.git" ]; then + echo "Error: $REPO_DIR does not exist or is not a git repo" + exit 1 +fi +cd $REPO_DIR +if [ ! -d "$CACHE_DIR" ]; then + echo "Error: $CACHE_DIR does not exist or is not an absolute path" + exit 1 +fi + +# Wipe the cache if it's not valid, or mark it as invalid while we update it +if [ ! -f "$cache_valid_file" ]; then + rm -rf "$CACHE_DIR" && mkdir "$CACHE_DIR" +else + rm "$cache_valid_file" +fi + +# Update the cache (a pristine copy of the rust source master) +if [ ! -d "$cache_src_dir/.git" ]; then + retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ + git clone https://github.com/rust-lang/rust.git $cache_src_dir" +fi +retry sh -c "cd $cache_src_dir && git reset --hard && git pull" +retry sh -c "cd $cache_src_dir && \ + git submodule deinit -f . && git submodule sync && git submodule update --init" + +# Cache was updated without errors, mark it as valid +touch "$cache_valid_file" + +# Update the submodules of the repo we're in, using the pristine repo as +# a cache for any object files +# No, `git submodule foreach` won't work: +# http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository +modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" +for module in $modules; do + if [ ! -d "$cache_src_dir/$module" ]; then + echo "WARNING: $module not found in pristine repo" + retry sh -c "git submodule deinit -f $module && git submodule update --init $module" + continue + fi + retry sh -c "git submodule deinit -f $module && \ + git submodule update --init --reference $cache_src_dir/$module $module" +done From 872d3bc0d713a85f2050f99d0cf33dd060318411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Mar 2017 14:54:15 -0700 Subject: [PATCH 340/662] Simplify labels and move tests to ui --- src/librustc_typeck/check/method/suggest.rs | 8 +- .../confuse-field-and-method}/issue-18343.rs | 2 +- .../issue-18343.stderr | 10 +++ .../confuse-field-and-method}/issue-2392.rs | 22 ++--- .../issue-2392.stderr | 90 +++++++++++++++++++ .../confuse-field-and-method}/issue-32128.rs | 2 +- .../issue-32128.stderr | 10 +++ .../confuse-field-and-method}/issue-33784.rs | 0 .../issue-33784.stderr | 26 ++++++ 9 files changed, 150 insertions(+), 20 deletions(-) rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-18343.rs (91%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-2392.rs (81%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-32128.rs (91%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-33784.rs (100%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b458c1af71d06..67ee7ef586530 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -202,19 +202,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { stored in the `{1}` field", expr_string, item_name)); - err.span_label(span, - &format!("`{}` is a field storing a \ - function, not a method", - item_name)); } else { err.help(&format!("did you mean to write `{0}.{1}` \ instead of `{0}.{1}(...)`?", expr_string, item_name)); - err.span_label(span, - &format!("`{}` is a field, not a method", - item_name)); } + err.span_label(span, &"field, not a method"); break; } } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs similarity index 91% rename from src/test/compile-fail/issue-18343.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs index a095bb4812610..fc3c58e5223a3 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs @@ -17,5 +17,5 @@ fn main() { o.closure(); //~^ ERROR no method named `closure` found //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method } diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr new file mode 100644 index 0000000000000..9e5e4adb180d5 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr @@ -0,0 +1,10 @@ +error: no method named `closure` found for type `Obj<[closure@$DIR/issue-18343.rs:16:28: 16:33]>` in the current scope + --> $DIR/issue-18343.rs:17:7 + | +17 | o.closure(); + | ^^^^^^^ field, not a method + | + = help: use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs similarity index 81% rename from src/test/compile-fail/issue-2392.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs index 12389f885364d..f84f35ce84bf9 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs @@ -49,43 +49,43 @@ fn main() { let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method o_closure.not_closure(); //~^ ERROR no method named `not_closure` found - //~| NOTE `not_closure` is a field, not a method + //~| NOTE field, not a method //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored - //~| NOTE `boxed_closure` is a field storing a function, not a method + //~| NOTE field, not a method let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored - //~| NOTE `boxed_closure` is a field storing a function, not a method + //~| NOTE field, not a method // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method w.wrap.not_closure(); //~^ ERROR no method named `not_closure` found - //~| NOTE `not_closure` is a field, not a method + //~| NOTE field, not a method //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? check_expression().closure();//~ ERROR no method named `closure` found //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method } impl FuncContainerOuter { @@ -93,13 +93,13 @@ impl FuncContainerOuter { unsafe { (*self.container).f1(1); //~ ERROR no method named `f1` found //~^ HELP use `((*self.container).f1)(...)` - //~| NOTE `f1` is a field storing a function, not a method + //~| NOTE field, not a method (*self.container).f2(1); //~ ERROR no method named `f2` found //~^ HELP use `((*self.container).f2)(...)` - //~| NOTE `f2` is a field storing a function, not a method + //~| NOTE field, not a method (*self.container).f3(1); //~ ERROR no method named `f3` found //~^ HELP use `((*self.container).f3)(...)` - //~| NOTE `f3` is a field storing a function, not a method + //~| NOTE field, not a method } } } diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr new file mode 100644 index 0000000000000..56e1060bdb95a --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr @@ -0,0 +1,90 @@ +error: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:49:36: 49:41]>` in the current scope + --> $DIR/issue-2392.rs:50:15 + | +50 | o_closure.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:49:36: 49:41]>` in the current scope + --> $DIR/issue-2392.rs:54:15 + | +54 | o_closure.not_closure(); + | ^^^^^^^^^^^ field, not a method + | + = help: did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? + +error: no method named `closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:60:12 + | +60 | o_func.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `boxed_closure` found for type `BoxedObj` in the current scope + --> $DIR/issue-2392.rs:65:14 + | +65 | boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found + | ^^^^^^^^^^^^^ field, not a method + | + = help: use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field + +error: no method named `boxed_closure` found for type `BoxedObj` in the current scope + --> $DIR/issue-2392.rs:70:19 + | +70 | boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found + | ^^^^^^^^^^^^^ field, not a method + | + = help: use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field + +error: no method named `closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:77:12 + | +77 | w.wrap.closure();//~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `not_closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:81:12 + | +81 | w.wrap.not_closure(); + | ^^^^^^^^^^^ field, not a method + | + = help: did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? + +error: no method named `closure` found for type `Obj + 'static>>` in the current scope + --> $DIR/issue-2392.rs:86:24 + | +86 | check_expression().closure();//~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `f1` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:94:31 + | +94 | (*self.container).f1(1); //~ ERROR no method named `f1` found + | ^^ field, not a method + | + = help: use `((*self.container).f1)(...)` if you meant to call the function stored in the `f1` field + +error: no method named `f2` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:97:31 + | +97 | (*self.container).f2(1); //~ ERROR no method named `f2` found + | ^^ field, not a method + | + = help: use `((*self.container).f2)(...)` if you meant to call the function stored in the `f2` field + +error: no method named `f3` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:100:31 + | +100 | (*self.container).f3(1); //~ ERROR no method named `f3` found + | ^^ field, not a method + | + = help: use `((*self.container).f3)(...)` if you meant to call the function stored in the `f3` field + +error: aborting due to 11 previous errors + diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs similarity index 91% rename from src/test/compile-fail/issue-32128.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs index 74fbb33296e4b..2fd7dc246c206 100644 --- a/src/test/compile-fail/issue-32128.rs +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs @@ -22,6 +22,6 @@ fn main() { demo.example(1); //~^ ERROR no method named `example` //~| HELP use `(demo.example)(...)` - //~| NOTE `example` is a field storing a function, not a method + //~| NOTE field, not a method // (demo.example)(1); } diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr new file mode 100644 index 0000000000000..0d2a895bad16d --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr @@ -0,0 +1,10 @@ +error: no method named `example` found for type `Example` in the current scope + --> $DIR/issue-32128.rs:22:10 + | +22 | demo.example(1); + | ^^^^^^^ field, not a method + | + = help: use `(demo.example)(...)` if you meant to call the function stored in the `example` field + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs similarity index 100% rename from src/test/compile-fail/issue-33784.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr new file mode 100644 index 0000000000000..70d64e3ffa331 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr @@ -0,0 +1,26 @@ +error: no method named `closure` found for type `&Obj<[closure@$DIR/issue-33784.rs:35:43: 35:48]>` in the current scope + --> $DIR/issue-33784.rs:37:7 + | +37 | p.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:35:43: 35:48]>` in the current scope + --> $DIR/issue-33784.rs:41:7 + | +41 | q.fn_ptr(); //~ ERROR no method named `fn_ptr` found + | ^^^^^^ field, not a method + | + = help: use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + +error: no method named `c_fn_ptr` found for type `&D` in the current scope + --> $DIR/issue-33784.rs:46:7 + | +46 | s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found + | ^^^^^^^^ field, not a method + | + = help: use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` field + +error: aborting due to 3 previous errors + From 2040daee472033ae5a0d369ae05bd07706595854 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 23 Mar 2017 23:05:30 -0400 Subject: [PATCH 341/662] Make the rustdoc sidebar white on `src` pages Fixes #40724 --- src/librustdoc/html/layout.rs | 4 ++-- src/librustdoc/html/static/rustdoc.css | 6 +++--- src/librustdoc/html/static/styles/main.css | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 06a816412969b..d6033a69da786 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -54,7 +54,7 @@ r##" {favicon} {in_header} - + $DIR/macro_path_as_generic_bound.rs:17:6 | 17 | foo!(m::m2::A); - | -----^^^^^^^^-- - | | | - | | Use of undeclared type or module `m` - | in this macro invocation + | ^^^^^^^^ Use of undeclared type or module `m` error: cannot continue compilation due to previous error From 3783c44eac713028969ac3cbdad6f30a3dbbbf97 Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Wed, 29 Mar 2017 16:50:09 +0530 Subject: [PATCH 350/662] Fix typo in libcore/char.rs --- src/libcore/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 19e69ca296d8f..b27c801cf89d5 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -187,7 +187,7 @@ impl From for u32 { /// with the character encoding that IANA calls ISO-8859-1. /// This encoding is compatible with ASCII. /// -/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hypen), +/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), /// which leaves some "blanks", byte values that are not assigned to any character. /// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. /// From 950d669a981bed04dcf9d7c172f468c2fbd1d6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malo=20Jaffr=C3=A9?= Date: Wed, 29 Mar 2017 14:31:00 +0200 Subject: [PATCH 351/662] Remove unused feature from error index generator Remove feature `rustdoc`. --- src/tools/error_index_generator/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 1d4f2c60d544f..5db2ad83a0a7a 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private, rustdoc)] +#![feature(rustc_private)] extern crate syntax; extern crate rustdoc; From 4ef554206c060eaa0eb75852a7a59e05478143a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malo=20Jaffr=C3=A9?= Date: Wed, 29 Mar 2017 15:38:47 +0200 Subject: [PATCH 352/662] Avoid linking to a moved page in rust.html --- src/doc/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rust.md b/src/doc/rust.md index 7f02260cd2cd4..5008b228c5c85 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1,3 +1,3 @@ % The Rust Reference Manual -The manual has moved, and is now called [the reference](reference.html). +The manual has moved, and is now called [the reference](reference/index.html). From 022bae8a4a9254fbdb4217e86927809f0ad996d6 Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 29 Mar 2017 15:59:22 +0200 Subject: [PATCH 353/662] Add example to std::process::abort --- src/libstd/process.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d46cf7a26daf0..32b52d1f77a01 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1056,6 +1056,19 @@ pub fn exit(code: i32) -> ! { /// will be run. If a clean shutdown is needed it is recommended to only call /// this function at a known point where there are no more destructors left /// to run. +/// +/// # Examples +/// ``` +/// use std::process; +/// +/// fn main() { +/// println!("aborting"); +/// +/// process::abort(); +/// +/// // execution never gets here +/// } +/// ``` #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; From 3ac27c3e54f3f5477ea907246c872523f14ef6df Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 29 Mar 2017 16:19:23 +0200 Subject: [PATCH 354/662] adding /// --- src/libstd/process.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 32b52d1f77a01..83d34f71a70a2 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1058,6 +1058,7 @@ pub fn exit(code: i32) -> ! { /// to run. /// /// # Examples +/// /// ``` /// use std::process; /// From 5a7e9ad64a160c9ebfb35969f2bdd1065bc154bb Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 29 Mar 2017 16:30:39 +0200 Subject: [PATCH 355/662] Removing trailing spaces --- src/libstd/process.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 83d34f71a70a2..a86dba97f7865 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1061,12 +1061,12 @@ pub fn exit(code: i32) -> ! { /// /// ``` /// use std::process; -/// +/// /// fn main() { /// println!("aborting"); -/// +/// /// process::abort(); -/// +/// /// // execution never gets here /// } /// ``` From c033942925baccfed375a75fa5e4c2a26fd7dcc5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 Mar 2017 12:22:38 -0700 Subject: [PATCH 356/662] rustbuild: Update bootstrap compiler Now that we've also updated cargo's release process this commit also changes the download location of Cargo from Cargos archives back to the static.r-l.o archives. This should ensure that the Cargo download is the exact Cargo paired with the rustc that we release. --- src/bootstrap/bootstrap.py | 17 +- src/bootstrap/channel.rs | 2 +- src/librustc/lib.rs | 1 - src/librustc_asan/lib.rs | 4 +- src/librustc_data_structures/lib.rs | 1 - src/librustc_incremental/lib.rs | 1 - src/librustc_lsan/lib.rs | 4 +- src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 3 +- src/librustc_msan/lib.rs | 4 +- src/librustc_privacy/lib.rs | 1 - src/librustc_trans/lib.rs | 1 - src/librustc_tsan/lib.rs | 4 +- src/librustc_typeck/lib.rs | 1 - src/stage0.txt | 3 +- src/tools/cargotest/lockfiles/iron-Cargo.lock | 359 +++++++++++------- src/tools/cargotest/main.rs | 2 +- src/tools/compiletest/src/main.rs | 1 - 18 files changed, 243 insertions(+), 167 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index b326f95e505fb..d5bc6127a1e7f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -160,11 +160,8 @@ class RustBuild(object): def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date()) - cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev()) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - if not os.path.exists(cargo_cache): - os.makedirs(cargo_cache) if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): @@ -195,15 +192,15 @@ def download_stage0(self): if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() - filename = "cargo-nightly-{}.tar.gz".format(self.build) - url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev() - tarball = os.path.join(cargo_cache, filename) + filename = "cargo-{}-{}.tar.gz".format(channel, self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose) self.fix_executable(self.bin_root() + "/bin/cargo") with open(self.cargo_stamp(), 'w') as f: - f.write(self.stage0_cargo_rev()) + f.write(self.stage0_rustc_date()) def fix_executable(self, fname): # If we're on NixOS we need to change the path to the dynamic loader @@ -258,9 +255,6 @@ def fix_executable(self, fname): print("warning: failed to call patchelf: %s" % e) return - def stage0_cargo_rev(self): - return self._cargo_rev - def stage0_rustc_date(self): return self._rustc_date @@ -283,7 +277,7 @@ def cargo_out_of_date(self): if not os.path.exists(self.cargo_stamp()) or self.clean: return True with open(self.cargo_stamp(), 'r') as f: - return self.stage0_cargo_rev() != f.read() + return self.stage0_rustc_date() != f.read() def bin_root(self): return os.path.join(self.build_dir, self.build, "stage0") @@ -578,7 +572,6 @@ def bootstrap(): data = stage0_data(rb.rust_root) rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) - rb._cargo_rev = data['cargo'] # Fetch/build the bootstrap rb.build = rb.build_triple() diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 2607ce412f108..a95bdcb3d2608 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -23,7 +23,7 @@ use build_helper::output; use Build; // The version number -pub const CFG_RELEASE_NUM: &'static str = "1.17.0"; +pub const CFG_RELEASE_NUM: &'static str = "1.18.0"; // An optional number to put after the label, e.g. '.2' -> '-beta.2' // Be sure to make this starts with a dot to conform to semver pre-release diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c1c945d4e6063..294f80d7d2301 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,6 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(i128_type)] #![feature(libc)] #![feature(loop_break_value)] diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 71a166b91ebcb..54941362e8450 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 8ecfd75dc95a9..9ccd95dd8d805 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -27,7 +27,6 @@ #![feature(shared)] #![feature(collections_range)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 3b61cc1464a91..477777c975db2 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -24,7 +24,6 @@ #![feature(rand)] #![feature(core_intrinsics)] #![feature(conservative_impl_trait)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![cfg_attr(stage0, feature(pub_restricted))] extern crate graphviz; diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index 71a166b91ebcb..54941362e8450 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 0ce886ce9e9df..2fbdb8c0de676 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -20,7 +20,6 @@ #![feature(box_patterns)] #![feature(conservative_impl_trait)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(i128_type)] #![feature(proc_macro_internals)] #![feature(quote)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 590c6a430b98a..8b55cdf06d208 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -23,7 +23,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(i128_type)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -61,4 +60,4 @@ pub fn provide(providers: &mut Providers) { mir_map::provide(providers); shim::provide(providers); transform::qualify_consts::provide(providers); -} \ No newline at end of file +} diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index 71a166b91ebcb..54941362e8450 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 64821f5d44bf4..300848fe8f25e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,7 +17,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f3e30ed4839ae..5c3b17c889760 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -28,7 +28,6 @@ #![feature(box_syntax)] #![feature(const_fn)] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![allow(unused_attributes)] #![feature(i128_type)] #![feature(libc)] diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs index 71a166b91ebcb..54941362e8450 100644 --- a/src/librustc_tsan/lib.rs +++ b/src/librustc_tsan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index df1c94dc19b59..4c772843afb2c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,7 +77,6 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(loop_break_value)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/stage0.txt b/src/stage0.txt index 772029ab0c253..60fbcadf49157 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,5 +12,4 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: beta-2017-02-01 -cargo: 407edef22e894266eb562618cba5ca9757051946 +rustc: beta-2017-03-21 diff --git a/src/tools/cargotest/lockfiles/iron-Cargo.lock b/src/tools/cargotest/lockfiles/iron-Cargo.lock index 843f2dcea512a..3aa3883b701d1 100644 --- a/src/tools/cargotest/lockfiles/iron-Cargo.lock +++ b/src/tools/cargotest/lockfiles/iron-Cargo.lock @@ -1,23 +1,38 @@ [root] name = "iron" -version = "0.3.0" +version = "0.5.1" dependencies = [ "conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "advapi32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "antidote" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" -version = "0.4.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -25,82 +40,104 @@ name = "conduit-mime-types" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "cookie" -version = "0.2.2" +name = "core-foundation" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "error" -version = "0.1.9" +name = "core-foundation-sys" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "gcc" -version = "0.3.26" +name = "crypt32-sys" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "gdi32-sys" -version = "0.1.1" +name = "foreign-types" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] -name = "hpack" +name = "gcc" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gdi32-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "httparse" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.8.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-native-tls" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel32-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -111,41 +148,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.1.15" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.8" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libressl-pnacl-sys" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "matches" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mime" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -154,51 +180,52 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "num_cpus" -version = "0.2.11" +name = "native-tls" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "openssl" -version = "0.7.8" +name = "num_cpus" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys-extras 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "openssl-sys" -version = "0.7.8" +name = "openssl" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "openssl-sys-extras" -version = "0.7.8" +name = "openssl-sys" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pkg-config" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -210,24 +237,21 @@ dependencies = [ ] [[package]] -name = "pnacl-build-helper" -version = "1.4.10" +name = "rand" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.3.14" +name = "redox_syscall" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rustc-serialize" -version = "0.3.18" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -239,45 +263,75 @@ dependencies = [ ] [[package]] -name = "semver" -version = "0.1.20" +name = "schannel" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "solicit" -version = "0.4.4" +name = "secur32-sys" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tempdir" -version = "0.3.4" +name = "security-framework" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "time" -version = "0.1.34" +name = "security-framework-sys" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "traitobject" -version = "0.0.1" +name = "semver" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "tempdir" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "traitobject" -version = "0.0.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -303,15 +357,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-normalization" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -319,42 +373,30 @@ name = "unsafe-any" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "url" -version = "0.5.7" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "user32-sys" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "uuid" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -362,3 +404,54 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[metadata] +"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" +"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8" +"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" +"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" +"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" +"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" +"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" +"checksum httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e7a63e511f9edffbab707141fbb8707d1a3098615fb2adbd5769cdfcc9b17d" +"checksum hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "43a15e3273b2133aaac0150478ab443fb89f15c3de41d8d93d8f3bb14bf560f6" +"checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409" +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +"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 matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" +"checksum mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5514f038123342d01ee5f95129e4ef1e0470c93bc29edf058a46f9ee3ba6737e" +"checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" +"checksum native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b805ee0e8fa268f67a4e5c7f4f80adb8af1fc4428ea0ce5b0ecab1430ef17ec0" +"checksum num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18c392466409c50b87369414a2680c93e739aedeb498eb2bff7d7eb569744e2" +"checksum openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8aa0eb7aad44f0da6f7dda13ddb4559d91a0f40cfab150b1f76ad5b39ec523f" +"checksum openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "14f5bfd12054d764510b887152d564ba11d99ae24ea7d740781778f646620576" +"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" +"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" +"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +"checksum schannel 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b291854e37196c2b67249e09d6bdeff410b19e1acf05558168e9c4413b4e95" +"checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" +"checksum security-framework 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2a8396fe671bb1f80fa3f4ff2aae0e968de16ef18d37a4e5e514771a1f07726e" +"checksum security-framework-sys 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "573b031c5f672b298cca566fac71aceea00e41bc925e75b5ec7b44dc7237180a" +"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" +"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" +"checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" +"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" +"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" +"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" +"checksum unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b351086021ebc264aea3ab4f94d61d889d98e5e9ec2d985d993f50133537fd3a" +"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" +"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 786b3192e0675..c7113edbf9e68 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -31,7 +31,7 @@ const TEST_REPOS: &'static [Test] = &[ Test { name: "iron", repo: "https://github.com/iron/iron", - sha: "16c858ec2901e2992fe5e529780f59fa8ed12903", + sha: "21c7dae29c3c214c08533c2a55ac649b418f2fe3", lock: Some(include_str!("lockfiles/iron-Cargo.lock")), }, Test { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 657739c65b1f5..09d21221a8395 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -12,7 +12,6 @@ #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(static_in_const)] #![feature(test)] #![feature(libc)] From 19b98f3027181a81d168f5f3648fa055ed862539 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Wed, 29 Mar 2017 13:21:31 -0400 Subject: [PATCH 357/662] Linked str in from_utf_unchecked --- src/libcore/str/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 0d66d0e93aa85..857eeb26af078 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -327,7 +327,9 @@ unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { /// /// This function is unsafe because it does not check that the bytes passed to /// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that `&str`s are valid UTF-8. +/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. +/// +/// [`&str`]: ../../std/primitive.str.html /// /// # Examples /// From 1eaa113581f39d41bc179e300d275cfaab91bd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Wed, 29 Mar 2017 20:43:01 +0200 Subject: [PATCH 358/662] Emit proper lifetime start intrinsics for personality slots We currently only emit a single call to the lifetime start intrinsic for the personality slot alloca. This happens because we create that call at the time that we create the alloca, instead of creating it each time we start using it. Because LLVM usually removes the alloca before the lifetime intrinsics are even considered, this didn't cause any problems yet, but we should fix this anyway. --- src/librustc_trans/mir/block.rs | 2 +- src/test/codegen/personality_lifetimes.rs | 39 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/personality_lifetimes.rs diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 226d40948c4dc..d69f31a45048d 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -762,7 +762,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); let slot = bcx.alloca(llretty, "personalityslot"); self.llpersonalityslot = Some(slot); - Lifetime::Start.call(bcx, slot); slot } } @@ -794,6 +793,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn); bcx.set_cleanup(llretval); let slot = self.get_personality_slot(&bcx); + Lifetime::Start.call(&bcx, slot); bcx.store(llretval, slot, None); bcx.br(target_bb); bcx.llbb() diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs new file mode 100644 index 0000000000000..1d07a2f104082 --- /dev/null +++ b/src/test/codegen/personality_lifetimes.rs @@ -0,0 +1,39 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O -C no-prepopulate-passes + +#![crate_type="lib"] + +struct S; + +impl Drop for S { + fn drop(&mut self) { + } +} + +fn might_unwind() { +} + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { + let _s = S; + // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just + // in the first one. + // CHECK-LABEL: cleanup: + // CHECK: bitcast{{.*}}personalityslot + // CHECK-NEXT: call void @llvm.lifetime.start + // CHECK-LABEL: cleanup1: + // CHECK: bitcast{{.*}}personalityslot + // CHECK-NEXT: call void @llvm.lifetime.start + might_unwind(); + might_unwind(); +} From 1e3bc5ac4fcacac584a39a061e9b1cffbcb9f713 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 29 Mar 2017 23:01:34 +0300 Subject: [PATCH 359/662] Allow using Vec::::place_back for T: !Clone The place_back was likely put into block with `T: Clone` bound by mistake. --- src/libcollections/vec.rs | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e00341..59186a2d50185 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -972,6 +972,29 @@ impl Vec { } } + /// Returns a place for insertion at the back of the `Vec`. + /// + /// Using this method with placement syntax is equivalent to [`push`](#method.push), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// let mut vec = vec![1, 2]; + /// vec.place_back() <- 3; + /// vec.place_back() <- 4; + /// assert_eq!(&vec, &[1, 2, 3, 4]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_back(&mut self) -> PlaceBack { + PlaceBack { vec: self } + } + /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// @@ -1266,29 +1289,6 @@ impl Vec { pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) } - - /// Returns a place for insertion at the back of the `Vec`. - /// - /// Using this method with placement syntax is equivalent to [`push`](#method.push), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// let mut vec = vec![1, 2]; - /// vec.place_back() <- 3; - /// vec.place_back() <- 4; - /// assert_eq!(&vec, &[1, 2, 3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack { - PlaceBack { vec: self } - } } // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. From b36cff5c4f9dd65cc48e7cc2f833dd4d6b449749 Mon Sep 17 00:00:00 2001 From: Camille TJHOA Date: Mon, 27 Mar 2017 22:42:29 +0200 Subject: [PATCH 360/662] Improve os::linux documentation (#29367) --- src/libstd/os/linux/fs.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 11c41816cec86..7ebda5ed744fd 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -34,36 +34,55 @@ pub trait MetadataExt { #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat; + /// Returns the device ID on which this file resides. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; + /// Returns the inode number. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ino(&self) -> u64; + /// Returns the file type and mode. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_size(&self) -> u64; + /// Returns the last access time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; + /// Returns the last access time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; + /// Returns the last modification time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; + /// Returns the last status change time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" blocksize for efficient filesystem I/O. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; } From e3acebff66c89e2a50c8bfcd08fbe221265b30b0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 30 Mar 2017 12:14:04 +1300 Subject: [PATCH 361/662] save-analysis: track associated types --- src/librustc_save_analysis/dump_visitor.rs | 30 +++++++++++++++++++--- src/test/run-make/save-analysis/foo.rs | 17 ++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f2aa89ba4b66e..7a7fa4eda05a6 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1149,8 +1149,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &trait_item.attrs, trait_item.span); } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Type(ref _bounds, ref default_ty) => { + // FIXME do something with _bounds (for type refs) + let name = trait_item.ident.name.to_string(); + let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); + let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type); + + if !self.span.filter_generated(sub_span, trait_item.span) { + self.dumper.typedef(TypeDefData { + span: sub_span.expect("No span found for assoc type"), + name: name, + id: trait_item.id, + qualname: qualname, + value: self.span.snippet(trait_item.span), + visibility: Visibility::Public, + parent: Some(trait_id), + docs: docs_for_attrs(&trait_item.attrs), + sig: None, + attributes: trait_item.attrs.clone(), + }.lower(self.tcx)); + } + + if let &Some(ref default_ty) = default_ty { + self.visit_ty(default_ty) + } + } + ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty), ast::TraitItemKind::Macro(_) => {} } } @@ -1177,7 +1201,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &impl_item.attrs, impl_item.span); } - ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty), ast::ImplItemKind::Macro(_) => {} } } diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index e8b69729af673..3fe1479f5f2ec 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -11,6 +11,7 @@ #![ crate_name = "test" ] #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(associated_type_defaults)] extern crate graphviz; // A simple rust project @@ -441,3 +442,19 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +struct FrameBuffer; + +struct SilenceGenerator; + +impl Iterator for SilenceGenerator { + type Item = FrameBuffer; + + fn next(&mut self) -> Option { + panic!(); + } +} + +trait Foo { + type Bar = FrameBuffer; +} From fe0fbbff5c67177e7e39869dc18c33e95bfcf0dc Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 30 Mar 2017 01:33:45 +0100 Subject: [PATCH 362/662] Disable appveyor cache --- appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fa599a00c4de3..68b2a239aff1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,8 +141,7 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - mkdir C:\cache\rustsrc - - sh src/ci/init_repo.sh . /c/cache/rustsrc + - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh @@ -151,7 +150,6 @@ on_failure: - cat %CD%/sccache.log cache: - - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" From 08a741eabf3c223650bb29c5df30c8fd414cd86a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Mar 2017 19:48:06 -0600 Subject: [PATCH 363/662] Add support for image, rules and footnotes --- src/librustdoc/html/markdown.rs | 139 ++++++++++++++---- src/test/rustdoc/check-rule-image-footnote.rs | 35 +++++ 2 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 src/test/rustdoc/check-rule-image-footnote.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 117cfbabb52f7..6c82dab94bcb3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -133,11 +133,37 @@ macro_rules! event_loop_break { }} } +struct ParserWrapper<'a> { + parser: Parser<'a>, + footnotes: Vec, + current_footnote_id: u16, +} + +impl<'a> ParserWrapper<'a> { + pub fn new(s: &'a str) -> ParserWrapper<'a> { + ParserWrapper { + parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | + pulldown_cmark::OPTION_ENABLE_FOOTNOTES), + footnotes: Vec::new(), + current_footnote_id: 1, + } + } + pub fn next(&mut self) -> Option> { + self.parser.next() + } + + pub fn get_next_footnote_id(&mut self) -> u16 { + let tmp = self.current_footnote_id; + self.current_footnote_id += 1; + tmp + } +} + pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { + fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -215,8 +241,8 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, level: i32) { + fn heading(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -249,32 +275,48 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } - fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, url: &str, title: &str, + id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Link(_, _))); + if title.is_empty() { + buffer.push_str(&format!("{}", url, content)); + } else { + buffer.push_str(&format!("{}", + url, Escape(title), content)); + } + } + + fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String, id: &mut Option<&mut String>) { event_loop_break!(parser, toc_builder, shorter, title, true, id, - Event::End(Tag::Link(_, _))); - buffer.push_str(&format!("{}", url, title)); + Event::End(Tag::Image(_, _))); + buffer.push_str(&format!("\"{}\"", url, title)); } - fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } - fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -284,8 +326,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content.trim())); } - fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_row(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -303,8 +345,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_head(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -322,7 +364,7 @@ pub fn render(w: &mut fmt::Formatter, } } - fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); let mut rows = String::new(); @@ -347,16 +389,16 @@ pub fn render(w: &mut fmt::Formatter, })); } - fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } - fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn list_item(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -372,7 +414,7 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("
  • {}
  • ", content)); } - fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { @@ -389,15 +431,16 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("
      {}
    ", content)); } - fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } - fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, @@ -405,7 +448,23 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, + fn footnote(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + mut definition: String, id: &mut Option<&mut String>) { + event_loop_break!(parser, toc_builder, shorter, definition, true, id, + Event::End(Tag::FootnoteDefinition(_))); + buffer.push_str(&definition); + } + + fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Rule)); + buffer.push_str("
    "); + } + + fn looper<'a>(parser: &'a mut ParserWrapper, buffer: &mut String, next_event: Option>, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) -> bool { if let Some(event) = next_event { @@ -423,7 +482,10 @@ pub fn render(w: &mut fmt::Formatter, paragraph(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); + link(parser, buffer, toc_builder, shorter, url, t.as_ref(), id); + } + Event::Start(Tag::Image(ref url, ref t)) => { + image(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); @@ -440,6 +502,23 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::Strong) => { strong(parser, buffer, toc_builder, shorter, id); } + Event::Start(Tag::Rule) => { + rule(parser, buffer, toc_builder, shorter, id); + } + Event::Start(Tag::FootnoteDefinition(ref def)) => { + let mut content = String::new(); + footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), + id); + let cur_len = parser.footnotes.len() + 1; + parser.footnotes.push(format!("
  • {}
  • ", + cur_len, content)); + } + Event::FootnoteReference(_) => { + buffer.push_str(&format!("{0}\ + ", + parser.get_next_footnote_id())); + } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); } @@ -457,13 +536,17 @@ pub fn render(w: &mut fmt::Formatter, None }; let mut buffer = String::new(); - let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); + let mut parser = ParserWrapper::new(s); loop { let next_event = parser.next(); if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { break } } + if !parser.footnotes.is_empty() { + buffer.push_str(&format!("

      {}
    ", + parser.footnotes.join(""))); + } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) }); diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs new file mode 100644 index 0000000000000..629e1a64e6fd0 --- /dev/null +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -0,0 +1,35 @@ +// Copyright 2017 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. + +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - '

    hard break: after hard break


    ' +// @has - 'Rust' +// @has - '
  • ' +// @has - '1' +/// markdown test +/// +/// this is a [link]. +/// +/// [link]: https://example.com "this is a title" +/// +/// hard break: +/// after hard break +/// +/// ----------- +/// +/// a footnote[^footnote]. +/// +/// [^footnote]: Thing +/// +/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) +#[deprecated(note = "Struct")] +pub fn f() {} From 8fde04b4a295792249d4a01f87a9f66143aa7c83 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 29 Mar 2017 07:17:18 +0000 Subject: [PATCH 364/662] Improve `Path` spans. --- src/libsyntax/attr.rs | 7 ++-- src/libsyntax/ext/base.rs | 21 ++++++++++- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 13 ++++--- src/libsyntax/ext/tt/transcribe.rs | 9 +---- src/libsyntax/parse/mod.rs | 4 +- src/libsyntax/parse/parser.rs | 56 +++++++++++++++++----------- src/libsyntax/parse/token.rs | 48 ++++++++++++------------ 9 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 5dcce2572af87..6f5f52ff1e953 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -1015,9 +1015,10 @@ impl MetaItem { { let (mut span, name) = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), - Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt { - token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()), - _ => None, + Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt { + token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name), + token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + _ => return None, }, _ => return None, }; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a2d54b62ec65d..fda026fec64ef 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -209,7 +209,26 @@ impl TTMacroExpander for F { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) -> Box { - (*self)(ecx, span, &input.trees().collect::>()) + struct AvoidInterpolatedIdents; + + impl Folder for AvoidInterpolatedIdents { + fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree { + if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt { + if let token::NtIdent(ident) = **nt { + return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node)); + } + } + fold::noop_fold_tt(tt, self) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } + } + + let input: Vec<_> = + input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect(); + (*self)(ecx, span, &input) } } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 9ee427eed3556..6cd1fea2e75e2 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -492,7 +492,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { _ => {} } // check at the beginning and the parser checks after each bump - p.check_unknown_macro_variable(); + p.process_potential_macro_variable(); match name { "item" => match panictry!(p.parse_item()) { Some(i) => token::NtItem(i), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 66f5520b88263..93348c8f08376 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -121,7 +121,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, p.root_module_name = cx.current_expansion.module.mod_path.last() .map(|id| id.name.as_str().to_string()); - p.check_unknown_macro_variable(); + p.process_potential_macro_variable(); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return Box::new(ParserAnyMacro { diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 12e746e024d3b..d216effbd4508 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -136,11 +136,14 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => { let span = match trees.next() { Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() { - Some(tokenstream::TokenTree::Token(end_sp, token::Ident(kind))) => { - let span = Span { lo: start_sp.lo, ..end_sp }; - result.push(TokenTree::MetaVarDecl(span, ident, kind)); - continue - } + Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() { + Some(kind) => { + let span = Span { lo: start_sp.lo, ..end_sp }; + result.push(TokenTree::MetaVarDecl(span, ident, kind)); + continue + } + _ => end_sp, + }, tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span), }, tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 24004492be2a0..947089b0b9ac4 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -12,7 +12,7 @@ use ast::Ident; use errors::Handler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::quoted; -use parse::token::{self, SubstNt, Token, NtIdent, NtTT}; +use parse::token::{self, SubstNt, Token, NtTT}; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{TokenStream, TokenTree, Delimited}; use util::small_vector::SmallVector; @@ -154,13 +154,6 @@ pub fn transcribe(sp_diag: &Handler, None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()), Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched { match **nt { - // sidestep the interpolation tricks for ident because - // (a) idents can be in lots of places, so it'd be a pain - // (b) we actually can, since it's a token. - NtIdent(ref sn) => { - let token = TokenTree::Token(sn.span, token::Ident(sn.node)); - result.push(token.into()); - } NtTT(ref tt) => result.push(tt.clone().into()), _ => { let token = TokenTree::Token(sp, token::Interpolated(nt.clone())); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b5d0a46de4926..c63a6524f7459 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -218,9 +218,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc) -> TokenStream /// Given stream and the ParseSess, produce a parser pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> { - let mut p = Parser::new(sess, stream, None, false); - p.check_unknown_macro_variable(); - p + Parser::new(sess, stream, None, false) } /// Parse a string representing a character literal into its final form. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b0611d7529062..db2878c6b1e72 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -160,6 +160,7 @@ pub struct Parser<'a> { /// the span of the current token: pub span: Span, /// the span of the previous token: + pub meta_var_span: Option, pub prev_span: Span, /// the previous token kind prev_token_kind: PrevTokenKind, @@ -417,6 +418,7 @@ impl<'a> Parser<'a> { token: token::Underscore, span: syntax_pos::DUMMY_SP, prev_span: syntax_pos::DUMMY_SP, + meta_var_span: None, prev_token_kind: PrevTokenKind::Other, restrictions: Restrictions::empty(), obsolete_set: HashSet::new(), @@ -443,6 +445,7 @@ impl<'a> Parser<'a> { parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span)); parser.directory.path.pop(); } + parser.process_potential_macro_variable(); parser } @@ -1012,7 +1015,7 @@ impl<'a> Parser<'a> { self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.prev_span = self.span; + self.prev_span = self.meta_var_span.take().unwrap_or(self.span); // Record last token kind for possible error recovery. self.prev_token_kind = match self.token { @@ -1028,7 +1031,7 @@ impl<'a> Parser<'a> { self.token = next.tok; self.expected_tokens.clear(); // check after each token - self.check_unknown_macro_variable(); + self.process_potential_macro_variable(); } /// Advance the parser using provided token as a next one. Use this when @@ -1722,7 +1725,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span; + let lo = self.meta_var_span.unwrap_or(self.span); let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1744,13 +1747,9 @@ impl<'a> Parser<'a> { segments.insert(0, PathSegment::crate_root()); } - // Assemble the span. - // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = lo.to(self.prev_span); - // Assemble the result. Ok(ast::Path { - span: span, + span: lo.to(self.prev_span), segments: segments, }) } @@ -1763,8 +1762,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1831,8 +1830,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { @@ -1873,10 +1872,11 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(PathSegment::from_ident(identifier, self.prev_span)); + segments.push(PathSegment::from_ident(identifier, ident_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -1896,8 +1896,9 @@ impl<'a> Parser<'a> { fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { + let ident_span = self.span; self.bump(); - Lifetime { name: ident.name, span: self.prev_span, id: ast::DUMMY_NODE_ID } + Lifetime { name: ident.name, span: ident_span, id: ast::DUMMY_NODE_ID } } _ => self.span_bug(self.span, "not a lifetime") } @@ -2568,10 +2569,23 @@ impl<'a> Parser<'a> { return Ok(e); } - pub fn check_unknown_macro_variable(&mut self) { - if let token::SubstNt(name) = self.token { - self.fatal(&format!("unknown macro variable `{}`", name)).emit() - } + pub fn process_potential_macro_variable(&mut self) { + let ident = match self.token { + token::SubstNt(name) => { + self.fatal(&format!("unknown macro variable `{}`", name)).emit(); + return + } + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.span); + match **nt { + token::NtIdent(ident) => ident, + _ => return, + } + } + _ => return, + }; + self.token = token::Ident(ident.node); + self.span = ident.span; } /// parse a single token tree from the input. @@ -2589,9 +2603,9 @@ impl<'a> Parser<'a> { }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = mem::replace(&mut self.token, token::Underscore); + let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span); self.bump(); - TokenTree::Token(self.prev_span, token) + TokenTree::Token(span, token) } } } @@ -3489,9 +3503,9 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) -> PResult<'a, PatKind> { + let ident_span = self.span; let ident = self.parse_ident()?; - let prev_span = self.prev_span; - let name = codemap::Spanned{span: prev_span, node: ident}; + let name = codemap::Spanned{span: ident_span, node: ident}; let sub = if self.eat(&token::At) { Some(self.parse_pat()?) } else { @@ -4364,7 +4378,7 @@ impl<'a> Parser<'a> { fn parse_self_arg(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. - token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) } + token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) } _ => unreachable!() }; let isolated_self = |this: &mut Self, n| { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 519d5bd98e47f..74aa3984a9a42 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -211,9 +211,7 @@ impl Token { ModSep => true, // global path Pound => true, // expression attributes Interpolated(ref nt) => match **nt { - NtExpr(..) => true, - NtBlock(..) => true, - NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -236,8 +234,7 @@ impl Token { Lt | BinOp(Shl) => true, // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtTy(..) => true, - NtPath(..) => true, + NtIdent(..) | NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -252,14 +249,22 @@ impl Token { } } - /// Returns `true` if the token is an identifier. - pub fn is_ident(&self) -> bool { + pub fn ident(&self) -> Option { match *self { - Ident(..) => true, - _ => false, + Ident(ident) => Some(ident), + Interpolated(ref nt) => match **nt { + NtIdent(ident) => Some(ident.node), + _ => None, + }, + _ => None, } } + /// Returns `true` if the token is an identifier. + pub fn is_ident(&self) -> bool { + self.ident().is_some() + } + /// Returns `true` if the token is a documentation comment. pub fn is_doc_comment(&self) -> bool { match *self { @@ -311,18 +316,15 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { - match *self { - Ident(id) => id.name == kw.name(), - _ => false, - } + self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false) } pub fn is_path_segment_keyword(&self) -> bool { - match *self { - Ident(id) => id.name == keywords::Super.name() || - id.name == keywords::SelfValue.name() || - id.name == keywords::SelfType.name(), - _ => false, + match self.ident() { + Some(id) => id.name == keywords::Super.name() || + id.name == keywords::SelfValue.name() || + id.name == keywords::SelfType.name(), + None => false, } } @@ -333,18 +335,16 @@ impl Token { /// Returns `true` if the token is a strict keyword. pub fn is_strict_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::As.name() && - id.name <= keywords::While.name(), + match self.ident() { + Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), _ => false, } } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_reserved_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::Abstract.name() && - id.name <= keywords::Yield.name(), + match self.ident() { + Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), _ => false, } } From 1be84cee75687856c0032ad0fd5ea96945c067b7 Mon Sep 17 00:00:00 2001 From: raph Date: Thu, 30 Mar 2017 09:55:44 +0200 Subject: [PATCH 365/662] Update process.rs --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a86dba97f7865..7f1a00c707c20 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1059,7 +1059,7 @@ pub fn exit(code: i32) -> ! { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::process; /// /// fn main() { From b3763862280946cab09cbedc4ad5626ebd95a5b2 Mon Sep 17 00:00:00 2001 From: Thomas Jespersen Date: Fri, 17 Mar 2017 23:11:27 +0100 Subject: [PATCH 366/662] Replace hardcoded forward slash with path::MAIN_SEPARATOR Fixes #40149 --- src/libstd/sys_common/backtrace.rs | 4 +-- src/libsyntax/parse/parser.rs | 9 +++--- src/test/parse-fail/mod_file_not_exist.rs | 2 ++ .../parse-fail/mod_file_not_exist_windows.rs | 32 +++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/test/parse-fail/mod_file_not_exist_windows.rs diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 99297b781e443..f5c188f7a7537 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -19,7 +19,7 @@ use io; use libc; use str; use sync::atomic::{self, Ordering}; -use path::Path; +use path::{self, Path}; use sys::mutex::Mutex; use ptr; @@ -262,7 +262,7 @@ fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int, if let Ok(cwd) = env::current_dir() { if let Ok(stripped) = file_path.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { - write!(w, " at ./{}:{}", s, line)?; + write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; already_printed = true; } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db2878c6b1e72..c2c3e5a6855af 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -59,7 +59,7 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; bitflags! { flags Restrictions: u8 { @@ -5146,7 +5146,7 @@ impl<'a> Parser<'a> { pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { let mod_name = id.to_string(); let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); + let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5224,8 +5224,9 @@ impl<'a> Parser<'a> { }; err.span_note(id_sp, &format!("maybe move this module `{0}` to its own directory \ - via `{0}/mod.rs`", - this_module)); + via `{0}{1}mod.rs`", + this_module, + path::MAIN_SEPARATOR)); if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ diff --git a/src/test/parse-fail/mod_file_not_exist.rs b/src/test/parse-fail/mod_file_not_exist.rs index 7736394a6f5d0..4bc6e706d4284 100644 --- a/src/test/parse-fail/mod_file_not_exist.rs +++ b/src/test/parse-fail/mod_file_not_exist.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-windows + // compile-flags: -Z parse-only mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` diff --git a/src/test/parse-fail/mod_file_not_exist_windows.rs b/src/test/parse-fail/mod_file_not_exist_windows.rs new file mode 100644 index 0000000000000..c58603b43989f --- /dev/null +++ b/src/test/parse-fail/mod_file_not_exist_windows.rs @@ -0,0 +1,32 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-gnu +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// compile-flags: -Z parse-only + +mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` +//~^ HELP name the file either not_a_real_file.rs or not_a_real_file\mod.rs inside the directory + +fn main() { + assert_eq!(mod_file_aux::bar(), 10); +} From 276bba9039e90a2c06ec0c811d80108a52a26e0b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 09:53:00 -0500 Subject: [PATCH 367/662] refactor if so that the "then type" is an expression --- src/librustc/cfg/construct.rs | 4 +-- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/lowering.rs | 5 +++- src/librustc/hir/mod.rs | 2 +- src/librustc/hir/print.rs | 6 ++--- src/librustc/middle/expr_use_visitor.rs | 4 +-- src/librustc/middle/liveness.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_typeck/check/mod.rs | 35 ++++++++----------------- 9 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 189a7344c3130..388d019f654a4 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // [..expr..] // let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 + let then_exit = self.expr(&then, cond_exit); // 2 self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4 } @@ -215,7 +215,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // [..expr..] // let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 + let then_exit = self.expr(&then, cond_exit); // 2 let else_exit = self.expr(&otherwise, cond_exit); // 3 self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5 } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f59b8b757f5cc..c7ad143c94979 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -960,7 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } ExprIf(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); - visitor.visit_block(if_block); + visitor.visit_expr(if_block); walk_list!(visitor, visit_expr, optional_else); } ExprWhile(ref subexpression, ref block, ref opt_sp_name) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 029b27b40f04d..fbc8a97dacc4c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1856,7 +1856,10 @@ impl<'a> LoweringContext<'a> { } }); - hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) + let then_blk = self.lower_block(blk, None); + let then_expr = self.expr_block(then_blk, ThinVec::new()); + + hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt) } ExprKind::While(ref cond, ref body, opt_ident) => { self.with_loop_scope(e.id, |this| diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3ca75dc6c00c9..59cefa36cbf1d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -994,7 +994,7 @@ pub enum Expr_ { /// An `if` block, with an optional else block /// /// `if expr { block } else { expr }` - ExprIf(P, P, Option>), + ExprIf(P, P, Option>), /// A while loop, with an optional label /// /// `'label: while expr { block }` diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 3411de9bb5df1..04a65fd5e3aa4 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1036,7 +1036,7 @@ impl<'a> State<'a> { word(&mut self.s, " else if ")?; self.print_expr(&i)?; space(&mut self.s)?; - self.print_block(&then)?; + self.print_expr(&then)?; self.print_else(e.as_ref().map(|e| &**e)) } // "final else" @@ -1058,13 +1058,13 @@ impl<'a> State<'a> { pub fn print_if(&mut self, test: &hir::Expr, - blk: &hir::Block, + blk: &hir::Expr, elseopt: Option<&hir::Expr>) -> io::Result<()> { self.head("if")?; self.print_expr(test)?; space(&mut self.s)?; - self.print_block(blk)?; + self.print_expr(blk)?; self.print_else(elseopt) } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a44679b0b3e0e..c7cf4a35a4bc7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -414,9 +414,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_exprs(exprs); } - hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => { + hir::ExprIf(ref cond_expr, ref then_expr, ref opt_else_expr) => { self.consume_expr(&cond_expr); - self.walk_block(&then_blk); + self.walk_expr(&then_expr); if let Some(ref else_expr) = *opt_else_expr { self.consume_expr(&else_expr); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 769dc8aeb54dd..e146663d4c8d6 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // ( succ ) // let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ); - let then_ln = self.propagate_through_block(&then, succ); + let then_ln = self.propagate_through_expr(&then, succ); let ln = self.live_node(expr.id, expr.span); self.init_from_succ(ln, else_ln); self.merge_from_succ(ln, then_ln, false); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 44858a98e36f9..d9b8d04ad386f 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -636,7 +636,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprIf(ref cond, ref then, ref otherwise) => { ExprKind::If { condition: cond.to_ref(), - then: block::to_expr_ref(cx, then), + then: then.to_ref(), otherwise: otherwise.to_ref(), } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index afa1e0557dc8b..54da0b2b0047e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2739,7 +2739,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // or if-else. fn check_then_else(&self, cond_expr: &'gcx hir::Expr, - then_blk: &'gcx hir::Block, + then_expr: &'gcx hir::Expr, opt_else_expr: Option<&'gcx hir::Expr>, sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { @@ -2748,7 +2748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); let expected = expected.adjust_for_branches(self); - let then_ty = self.check_block_with_expected(then_blk, expected); + let then_ty = self.check_expr_with_expectation(then_expr, expected); let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -2763,26 +2763,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to assign coercions to, otherwise it's () or diverging. expected_ty = then_ty; found_ty = else_ty; - result = if let Some(ref then) = then_blk.expr { - let res = self.try_find_coercion_lub(&cause, || Some(&**then), - then_ty, else_expr, else_ty); - - // In case we did perform an adjustment, we have to update - // the type of the block, because old trans still uses it. - if res.is_ok() { - let adj = self.tables.borrow().adjustments.get(&then.id).cloned(); - if let Some(adj) = adj { - self.write_ty(then_blk.id, adj.target); - } - } - res - } else { - self.commit_if_ok(|_| { - let trace = TypeTrace::types(&cause, true, then_ty, else_ty); - self.lub(true, trace, &then_ty, &else_ty) - .map(|ok| self.register_infer_ok_obligations(ok)) - }) + let coerce_to = expected.only_has_type(self).unwrap_or(then_ty); + result = { + self.try_coerce(then_expr, then_ty, coerce_to) + .and_then(|t| { + self.try_find_coercion_lub(&cause, || Some(then_expr), t, else_expr, else_ty) + }) }; // We won't diverge unless both branches do (or the condition does). @@ -3587,9 +3574,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } } - hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => { - self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), - expr.span, expected) + hir::ExprIf(ref cond, ref then_expr, ref opt_else_expr) => { + self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e), + expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { let unified = self.tcx.mk_nil(); From 6c022729264a54f1b90ab8801000dc783cdf1e6d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 09:57:26 -0500 Subject: [PATCH 368/662] update comment --- src/librustc/hir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 59cefa36cbf1d..560fa18a40502 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -993,7 +993,7 @@ pub enum Expr_ { ExprType(P, P), /// An `if` block, with an optional else block /// - /// `if expr { block } else { expr }` + /// `if expr { expr } else { expr }` ExprIf(P, P, Option>), /// A while loop, with an optional label /// From 6a47fa1d3d4594ddd3077d0e73d29aa056493b0d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 29 Mar 2017 23:52:45 -0400 Subject: [PATCH 369/662] remove unneeded `&` that now fails to coerce cc https://github.com/rust-lang/rust/issues/40924 --- src/librustc_trans/abi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 1530708b4b888..453f65eb762f8 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -369,7 +369,7 @@ impl FnType { match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments, _) => { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - &tupled_arguments + tupled_arguments } _ => { bug!("argument to function with \"rust-call\" ABI \ From 066d44bc0d1680e2094867631920104049fd4948 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 22 Mar 2017 11:40:29 -0400 Subject: [PATCH 370/662] refactor the `targeted_by_break` field In master, this field was an arbitrary node-id (in fact, an id for something that doesn't even exist in the HIR -- the `catch` node). Breaks targeting this block used that id. In the newer system, this field is a boolean, and any breaks targeted this block will use the id of the block. --- src/librustc/cfg/construct.rs | 4 +- src/librustc/hir/lowering.rs | 36 +++--- src/librustc/hir/mod.rs | 8 +- src/librustc/middle/liveness.rs | 4 +- src/librustc_mir/build/block.rs | 170 ++++++++++++++++------------ src/librustc_mir/build/expr/into.rs | 14 +-- src/librustc_mir/hair/cx/block.rs | 1 + src/librustc_mir/hair/mod.rs | 1 + src/librustc_typeck/check/mod.rs | 36 +++--- 9 files changed, 143 insertions(+), 131 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 388d019f654a4..20b322ec18951 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -74,11 +74,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { - if let Some(break_to_expr_id) = blk.break_to_expr_id { + if blk.targeted_by_break { let expr_exit = self.add_ast_node(blk.id, &[]); self.breakable_block_scopes.push(BlockScope { - block_expr_id: break_to_expr_id, + block_expr_id: blk.id, break_index: expr_exit, }); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index fbc8a97dacc4c..17185a6ab69f4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1156,7 +1156,7 @@ impl<'a> LoweringContext<'a> { bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() } - fn lower_block(&mut self, b: &Block, break_to: Option) -> P { + fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P { let mut expr = None; let mut stmts = vec![]; @@ -1179,7 +1179,7 @@ impl<'a> LoweringContext<'a> { expr: expr, rules: self.lower_block_check_mode(&b.rules), span: b.span, - break_to_expr_id: break_to, + targeted_by_break: targeted_by_break, }) } @@ -1274,7 +1274,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { self.with_new_scopes(|this| { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); hir::ItemFn(this.lower_fn_decl(decl), @@ -1368,7 +1368,7 @@ impl<'a> LoweringContext<'a> { hir::TraitMethod::Required(names)) } TraitItemKind::Method(ref sig, Some(ref body)) => { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::TraitItemKind::Method(this.lower_method_sig(sig), @@ -1424,7 +1424,7 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), body_id) } ImplItemKind::Method(ref sig, ref body) => { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) @@ -1848,7 +1848,7 @@ impl<'a> LoweringContext<'a> { id: id, rules: hir::DefaultBlock, span: span, - break_to_expr_id: None, + targeted_by_break: false, }); P(self.expr_block(blk, ThinVec::new())) } @@ -1856,7 +1856,7 @@ impl<'a> LoweringContext<'a> { } }); - let then_blk = self.lower_block(blk, None); + let then_blk = self.lower_block(blk, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt) @@ -1865,18 +1865,18 @@ impl<'a> LoweringContext<'a> { self.with_loop_scope(e.id, |this| hir::ExprWhile( this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body, None), + this.lower_block(body, false), this.lower_opt_sp_ident(opt_ident))) } ExprKind::Loop(ref body, opt_ident) => { self.with_loop_scope(e.id, |this| - hir::ExprLoop(this.lower_block(body, None), + hir::ExprLoop(this.lower_block(body, false), this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } ExprKind::Catch(ref body) => { - self.with_catch_scope(e.id, |this| - hir::ExprBlock(this.lower_block(body, Some(e.id)))) + self.with_catch_scope(body.id, |this| + hir::ExprBlock(this.lower_block(body, true))) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), @@ -1894,7 +1894,7 @@ impl<'a> LoweringContext<'a> { }) }) } - ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)), ExprKind::Assign(ref el, ref er) => { hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) } @@ -2040,7 +2040,7 @@ impl<'a> LoweringContext<'a> { // ` => ` { - let body = self.lower_block(body, None); + let body = self.lower_block(body, false); let body_expr = P(self.expr_block(body, ThinVec::new())); let pat = self.lower_pat(pat); arms.push(self.arm(hir_vec![pat], body_expr)); @@ -2112,7 +2112,7 @@ impl<'a> LoweringContext<'a> { let (guard, body) = if let ExprKind::If(ref cond, ref then, _) = else_expr.node { - let then = self.lower_block(then, None); + let then = self.lower_block(then, false); (Some(cond), self.expr_block(then, ThinVec::new())) } else { @@ -2162,7 +2162,7 @@ impl<'a> LoweringContext<'a> { // Note that the block AND the condition are evaluated in the loop scope. // This is done to allow `break` from inside the condition of the loop. let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( - this.lower_block(body, None), + this.lower_block(body, false), this.expr_break(e.span, ThinVec::new()), this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), )); @@ -2223,7 +2223,7 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::Some() => ` let pat_arm = { let body_block = self.with_loop_scope(e.id, - |this| this.lower_block(body, None)); + |this| this.lower_block(body, false)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); let pat = self.lower_pat(pat); let some_pat = self.pat_some(e.span, pat); @@ -2655,7 +2655,7 @@ impl<'a> LoweringContext<'a> { id: self.next_id(), rules: hir::DefaultBlock, span: span, - break_to_expr_id: None, + targeted_by_break: false, } } @@ -2763,7 +2763,7 @@ impl<'a> LoweringContext<'a> { id: id, stmts: stmts, expr: Some(expr), - break_to_expr_id: None, + targeted_by_break: false, }); self.expr_block(block, attrs) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 560fa18a40502..d5000ac9c1866 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -549,9 +549,11 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, - /// The id of the expression that `break` breaks to if the block can be broken out of. - /// Currently only `Some(_)` for `catch {}` blocks - pub break_to_expr_id: Option, + /// If true, then there may exist `break 'a` values that aim to + /// break out of this block early. As of this writing, this is not + /// currently permitted in Rust itself, but it is generated as + /// part of `catch` statements. + pub targeted_by_break: bool, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index e146663d4c8d6..7cae08efc0de0 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -821,8 +821,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { - if let Some(break_to_expr_id) = blk.break_to_expr_id { - self.breakable_block_ln.insert(break_to_expr_id, succ); + if blk.targeted_by_break { + self.breakable_block_ln.insert(blk.id, succ); } let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); blk.stmts.iter().rev().fold(succ, |succ, stmt| { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 3305cfc0dfe1a..7739766182cfa 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -12,90 +12,116 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; use rustc::mir::*; use rustc::hir; +use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn ast_block(&mut self, destination: &Lvalue<'tcx>, - mut block: BasicBlock, - ast_block: &'tcx hir::Block) + block: BasicBlock, + ast_block: &'tcx hir::Block, + source_info: SourceInfo) -> BlockAnd<()> { - let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block); + let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block); self.in_scope(extent, block, move |this| { - // This convoluted structure is to avoid using recursion as we walk down a list - // of statements. Basically, the structure we get back is something like: - // - // let x = in { - // expr1; - // let y = in { - // expr2; - // expr3; - // ... - // } - // } - // - // The let bindings are valid till the end of block so all we have to do is to pop all - // the let-scopes at the end. - // - // First we build all the statements in the block. - let mut let_extent_stack = Vec::with_capacity(8); - let outer_visibility_scope = this.visibility_scope; - for stmt in stmts { - let Stmt { span: _, kind } = this.hir.mirror(stmt); - match kind { - StmtKind::Expr { scope, expr } => { - unpack!(block = this.in_scope(scope, block, |this| { - let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr) - })); - } - StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => { - let tcx = this.hir.tcx(); + if targeted_by_break { + // This is a `break`-able block (currently only `catch { ... }`) + let exit_block = this.cfg.start_new_block(); + let block_exit = this.in_breakable_scope(None, exit_block, + destination.clone(), |this| { + this.ast_block_stmts(destination, block, span, stmts, expr) + }); + this.cfg.terminate(unpack!(block_exit), source_info, + TerminatorKind::Goto { target: exit_block }); + exit_block.unit() + } else { + this.ast_block_stmts(destination, block, span, stmts, expr) + } + }) + } - // Enter the remainder scope, i.e. the bindings' destruction scope. - this.push_scope(remainder_scope); - let_extent_stack.push(remainder_scope); + fn ast_block_stmts(&mut self, + destination: &Lvalue<'tcx>, + mut block: BasicBlock, + span: Span, + stmts: Vec>, + expr: Option>) + -> BlockAnd<()> { + let this = self; + + // This convoluted structure is to avoid using recursion as we walk down a list + // of statements. Basically, the structure we get back is something like: + // + // let x = in { + // expr1; + // let y = in { + // expr2; + // expr3; + // ... + // } + // } + // + // The let bindings are valid till the end of block so all we have to do is to pop all + // the let-scopes at the end. + // + // First we build all the statements in the block. + let mut let_extent_stack = Vec::with_capacity(8); + let outer_visibility_scope = this.visibility_scope; + for stmt in stmts { + let Stmt { span: _, kind } = this.hir.mirror(stmt); + match kind { + StmtKind::Expr { scope, expr } => { + unpack!(block = this.in_scope(scope, block, |this| { + let expr = this.hir.mirror(expr); + this.stmt_expr(block, expr) + })); + } + StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => { + let tcx = this.hir.tcx(); - // Declare the bindings, which may create a visibility scope. - let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir); - let remainder_span = remainder_span.unwrap_or(span); - let scope = this.declare_bindings(None, remainder_span, &pattern); + // Enter the remainder scope, i.e. the bindings' destruction scope. + this.push_scope(remainder_scope); + let_extent_stack.push(remainder_scope); - // Evaluate the initializer, if present. - if let Some(init) = initializer { - unpack!(block = this.in_scope(init_scope, block, move |this| { - // FIXME #30046 ^~~~ - this.expr_into_pattern(block, pattern, init) - })); - } else { - this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { - this.storage_live_binding(block, node, span); - this.schedule_drop_for_binding(node, span); - }) - } + // Declare the bindings, which may create a visibility scope. + let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir); + let remainder_span = remainder_span.unwrap_or(span); + let scope = this.declare_bindings(None, remainder_span, &pattern); - // Enter the visibility scope, after evaluating the initializer. - if let Some(visibility_scope) = scope { - this.visibility_scope = visibility_scope; - } + // Evaluate the initializer, if present. + if let Some(init) = initializer { + unpack!(block = this.in_scope(init_scope, block, move |this| { + // FIXME #30046 ^~~~ + this.expr_into_pattern(block, pattern, init) + })); + } else { + this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { + this.storage_live_binding(block, node, span); + this.schedule_drop_for_binding(node, span); + }) + } + + // Enter the visibility scope, after evaluating the initializer. + if let Some(visibility_scope) = scope { + this.visibility_scope = visibility_scope; } } } - // Then, the block may have an optional trailing expression which is a “return” value - // of the block. - if let Some(expr) = expr { - unpack!(block = this.into(destination, block, expr)); - } else { - let source_info = this.source_info(span); - this.cfg.push_assign_unit(block, source_info, destination); - } - // Finally, we pop all the let scopes before exiting out from the scope of block - // itself. - for extent in let_extent_stack.into_iter().rev() { - unpack!(block = this.pop_scope(extent, block)); - } - // Restore the original visibility scope. - this.visibility_scope = outer_visibility_scope; - block.unit() - }) + } + // Then, the block may have an optional trailing expression which is a “return” value + // of the block. + if let Some(expr) = expr { + unpack!(block = this.into(destination, block, expr)); + } else { + let source_info = this.source_info(span); + this.cfg.push_assign_unit(block, source_info, destination); + } + // Finally, we pop all the let scopes before exiting out from the scope of block + // itself. + for extent in let_extent_stack.into_iter().rev() { + unpack!(block = this.pop_scope(extent, block)); + } + // Restore the original visibility scope. + this.visibility_scope = outer_visibility_scope; + block.unit() } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index e1b0c6a6f042e..a5a114c61bcf6 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -40,19 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { - if let Some(_) = ast_block.break_to_expr_id { - // This is a `break`-able block (currently only `catch { ... }`) - let exit_block = this.cfg.start_new_block(); - let block_exit = this.in_breakable_scope(None, exit_block, - destination.clone(), |this| { - this.ast_block(destination, block, ast_block) - }); - this.cfg.terminate(unpack!(block_exit), source_info, - TerminatorKind::Goto { target: exit_block }); - exit_block.unit() - } else { - this.ast_block(destination, block, ast_block) - } + this.ast_block(destination, block, ast_block, source_info) } ExprKind::Match { discriminant, arms } => { this.match_expr(destination, expr_span, block, discriminant, arms) diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index ba6b9361a83f4..d2465331df353 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -23,6 +23,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { // in order to get the lexical scoping correctly. let stmts = mirror_stmts(cx, self.id, &*self.stmts); Block { + targeted_by_break: self.targeted_by_break, extent: cx.tcx.region_maps.node_extent(self.id), span: self.span, stmts: stmts, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2ee375dee08ac..a3982efd2d695 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -31,6 +31,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt #[derive(Clone, Debug)] pub struct Block<'tcx> { + pub targeted_by_break: bool, pub extent: CodeExtent, pub span: Span, pub stmts: Vec>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 54da0b2b0047e..000398a4bce9f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -416,15 +416,11 @@ pub struct EnclosingBreakables<'gcx, 'tcx> { } impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { - fn find_breakable(&mut self, target: hir::ScopeTarget) - -> Option<&mut BreakableCtxt<'gcx, 'tcx>> - { - let opt_index = target.opt_id().and_then(|id| self.by_id.get(&id).cloned()); - if let Some(ix) = opt_index { - Some(&mut self.stack[ix]) - } else { - None - } + fn find_breakable(&mut self, target_id: ast::NodeId) -> &mut BreakableCtxt<'gcx, 'tcx> { + let ix = *self.by_id.get(&target_id).unwrap_or_else(|| { + bug!("could not find enclosing breakable with id {}", target_id); + }); + &mut self.stack[ix] } } @@ -3472,12 +3468,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } hir::ExprBreak(destination, ref expr_opt) => { - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables - .find_breakable(destination.target_id).map(|ctxt| ctxt.coerce_to) - }; - if let Some(coerce_to) = coerce_to { + if let Some(target_id) = destination.target_id.opt_id() { + let coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable(target_id).coerce_to + }; + let e_ty; let cause; if let Some(ref e) = *expr_opt { @@ -3492,7 +3488,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(destination.target_id).unwrap(); + let ctxt = enclosing_breakables.find_breakable(target_id); let result = if let Some(ref e) = *expr_opt { // Special-case the first element, as it has no "previous expressions". @@ -4024,7 +4020,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut ty = if let Some(break_to_expr_id) = blk.break_to_expr_id { + let mut ty = if blk.targeted_by_break { let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(blk.span)); let coerce_to = expected.only_has_type(self).unwrap_or(unified); let ctxt = BreakableCtxt { @@ -4034,15 +4030,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { may_break: false, }; - let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(break_to_expr_id, ctxt, || { + let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(blk.id, ctxt, || { for s in &blk.stmts { self.check_stmt(s); } let coerce_to = { let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable( - hir::ScopeTarget::Block(break_to_expr_id) - ).unwrap().coerce_to + enclosing_breakables.find_breakable(blk.id).coerce_to }; let e_ty; let cause; From 4c6c26eba1ca315677b024026a54001a5ab96cd0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 Mar 2017 21:15:26 -0500 Subject: [PATCH 371/662] change the strategy for diverging types The new strategy is as follows. First, the `!` type is assigned in two cases: - a block with a diverging statement and no tail expression (e.g., `{return;}`); - any expression with the type `!` is considered diverging. Second, we track when we are in a diverging state, and we permit a value of any type to be coerced **into** `!` if the expression that produced it is diverging. This means that `fn foo() -> ! { panic!(); 22 }` type-checks, even though the block has a type of `usize`. Finally, coercions **from** the `!` type to any other are always permitted. Fixes #39808. --- src/librustc_typeck/check/demand.rs | 24 +++++++++++++++++- src/librustc_typeck/check/mod.rs | 24 ++++++++++-------- .../diverging-tuple-parts-39485.rs | 25 +++++++++++++++++++ .../compile-fail/never-assign-wrong-type.rs | 1 + src/test/run-pass/issue-39808.rs | 21 ++++++++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/diverging-tuple-parts-39485.rs create mode 100644 src/test/run-pass/issue-39808.rs diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 232c4c4db7c97..25d689b3c2c45 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -67,8 +67,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Checks that the type of `expr` can be coerced to `expected`. - pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { + // + // NB: This code relies on `self.diverges` to be accurate. In + // particular, assignments to `!` will be permitted if the + // diverges flag is currently "always". + pub fn demand_coerce(&self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); + + // If we are "assigning" to a `!` location, then we can permit + // any type to be assigned there, so long as we are in + // dead-code. This applies to e.g. `fn foo() -> ! { return; 22 + // }` but also `fn foo() { let x: ! = { return; 22 }; }`. + // + // You might imagine that we could just *always* bail if we + // are in dead-code, but we don't want to do that, because + // that leaves a lot of type variables unconstrained. See + // e.g. #39808 and #39984. + let in_dead_code = self.diverges.get().always(); + if expected.is_never() && in_dead_code { + return; + } + if let Err(e) = self.try_coerce(expr, checked_ty, expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 000398a4bce9f..5d002dba78c24 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1533,18 +1533,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", - node_id, ty, self.tag()); + node_id, self.resolve_type_vars_if_possible(&ty), self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); if ty.references_error() { self.has_errors.set(true); self.set_tainted_by_errors(); } - - // FIXME(canndrew): This is_never should probably be an is_uninhabited - if ty.is_never() || self.type_var_diverges(ty) { - self.diverges.set(self.diverges.get() | Diverges::Always); - } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -3282,6 +3277,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => self.warn_if_unreachable(expr.id, expr.span, "expression") } + // Any expression that produces a value of type `!` must have diverged + if ty.is_never() { + self.diverges.set(self.diverges.get() | Diverges::Always); + } + // Record the type, which applies it effects. // We need to do this after the warning above, so that // we don't warn for the diverging expression itself. @@ -3967,7 +3967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let (node_id, span) = match stmt.node { + let (node_id, _span) = match stmt.node { hir::StmtDecl(ref decl, id) => { let span = match decl.node { hir::DeclLocal(ref l) => { @@ -3993,9 +3993,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if self.has_errors.get() { self.write_error(node_id); - } else if self.diverges.get().always() { - self.write_ty(node_id, self.next_diverging_ty_var( - TypeVariableOrigin::DivergingStmt(span))); } else { self.write_nil(node_id); } @@ -4046,7 +4043,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause = self.misc(e.span); }, None => { - e_ty = self.tcx.mk_nil(); + e_ty = if self.diverges.get().always() { + self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)) + } else { + self.tcx.mk_nil() + }; cause = self.misc(blk.span); } }; @@ -4054,6 +4055,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (e_ty, cause) }); + if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { let result = if !ctxt.may_break { self.try_coerce(e, e_ty, ctxt.coerce_to) diff --git a/src/test/compile-fail/diverging-tuple-parts-39485.rs b/src/test/compile-fail/diverging-tuple-parts-39485.rs new file mode 100644 index 0000000000000..eedad08ab5536 --- /dev/null +++ b/src/test/compile-fail/diverging-tuple-parts-39485.rs @@ -0,0 +1,25 @@ +// 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. + +// After #39485, this test used to pass, but that change was reverted +// due to numerous inference failures like #39808, so it now fails +// again. #39485 made it so that diverging types never propagate +// upward; but we now do propagate such types upward in many more +// cases. + +fn g() { + &panic!() //~ ERROR mismatched types +} + +fn f() -> isize { + (return 1, return 2) //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index 53d96aaf4fe89..d854e6eb20388 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -11,6 +11,7 @@ // Test that we can't use another type in place of ! #![feature(never_type)] +#![deny(warnings)] fn main() { let x: ! = "hello"; //~ ERROR mismatched types diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs new file mode 100644 index 0000000000000..f83e9328e5879 --- /dev/null +++ b/src/test/run-pass/issue-39808.rs @@ -0,0 +1,21 @@ +// 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. + +// Regression test: even though `Ok` is dead-code, its type needs to +// be influenced by the result of `Err` or else we get a "type +// variable unconstrained" error. + +fn main() { + let _ = if false { + Ok(return) + } else { + Err("") + }; +} From 555b6d69b2420862388e36992d7e099625ca6fe4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:35:50 -0400 Subject: [PATCH 372/662] add some debug logs to type_variable.rs --- src/librustc/infer/type_variable.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 9c8419d9546d2..5aab0fdf6c951 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -30,6 +30,7 @@ pub struct TypeVariableTable<'tcx> { } /// Reasons to create a type inference variable +#[derive(Debug)] pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), @@ -196,6 +197,7 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: bool, origin: TypeVariableOrigin, default: Option>,) -> ty::TyVid { + debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); let index = self.values.push(TypeVariableData { value: Bounded { relations: vec![], default: default }, @@ -203,7 +205,7 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: diverging }); let v = ty::TyVid { index: index as u32 }; - debug!("new_var() -> {:?}", v); + debug!("new_var: diverging={:?} index={:?}", diverging, v); v } From 27f4b57602a01c2b49c09b161e1ddca26752fec8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:36:44 -0400 Subject: [PATCH 373/662] add a `TypeVariableOrigin` we'll use later (`DerivingFn`) --- src/librustc/infer/type_variable.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 5aab0fdf6c951..67f37e5f9272e 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -42,6 +42,7 @@ pub enum TypeVariableOrigin { AdjustmentType(Span), DivergingStmt(Span), DivergingBlockExpr(Span), + DivergingFn(Span), LatticeVariable(Span), } From eeb6447bbfbb34ec093b723ff6a9dd40df2287bb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:37:18 -0400 Subject: [PATCH 374/662] add an `ObligationCauseCode` we'll use later (`ReturnNoExpression`) --- src/librustc/traits/error_reporting.rs | 1 + src/librustc/traits/mod.rs | 3 +++ src/librustc/traits/structural_impls.rs | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 27525d550ff20..152dd6ac3000f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -904,6 +904,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::StartFunctionType | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | + ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::MiscObligation => { } ObligationCauseCode::SliceOrArrayElem => { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c71fc28b4d6b3..47cbccdd2ab10 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -173,6 +173,9 @@ pub enum ObligationCauseCode<'tcx> { // method receiver MethodReceiver, + + // `return` with no expression + ReturnNoExpression, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 717c171db2ac7..44ef461327ddb 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -167,6 +167,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { type Lifted = traits::ObligationCauseCode<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { + super::ReturnNoExpression => Some(super::ReturnNoExpression), super::MiscObligation => Some(super::MiscObligation), super::SliceOrArrayElem => Some(super::SliceOrArrayElem), super::TupleElem => Some(super::TupleElem), @@ -489,6 +490,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::StructInitializerSized | super::VariableType(_) | super::ReturnType | + super::ReturnNoExpression | super::RepeatVec | super::FieldSized | super::ConstSized | @@ -533,6 +535,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::StructInitializerSized | super::VariableType(_) | super::ReturnType | + super::ReturnNoExpression | super::RepeatVec | super::FieldSized | super::ConstSized | From dad314040764122fc78a7f8b70ffa9ef77bde3c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:39:13 -0400 Subject: [PATCH 375/662] introduce (but do not yet use) a `CoerceMany` API The existing pattern for coercions is fairly complex. `CoerceMany` enapsulates it better into a helper. --- src/librustc_typeck/check/coercion.rs | 227 ++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c43291557f7fa..40ae169a94e0d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -837,3 +837,230 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + +/// CoerceMany encapsulates the pattern you should use when you have +/// many expressions that are all getting coerced to a common +/// type. This arises, for example, when you have a match (the result +/// of each arm is coerced to a common type). It also arises in less +/// obvious places, such as when you have many `break foo` expressions +/// that target the same loop, or the various `return` expressions in +/// a function. +/// +/// The basic protocol is as follows: +/// +/// - Instantiate the `CoerceMany` with an initial `expected_ty`. +/// This will also serve as the "starting LUB". The expectation is +/// that this type is something which all of the expressions *must* +/// be coercible to. Use a fresh type variable if needed. +/// - For each expression whose result is to be coerced, invoke `coerce()` with. +/// - In some cases we wish to coerce "non-expressions" whose types are implicitly +/// unit. This happens for example if you have a `break` with no expression, +/// or an `if` with no `else`. In that case, invoke `coerce_forced_unit()`. +/// - `coerce()` and `coerce_forced_unit()` may report errors. They hide this +/// from you so that you don't have to worry your pretty head about it. +/// But if an error is reported, the final type will be `err`. +/// - Invoking `coerce()` may cause us to go and adjust the "adjustments" on +/// previously coerced expressions. +/// - When all done, invoke `complete()`. This will return the LUB of +/// all your expressions. +/// - WARNING: I don't believe this final type is guaranteed to be +/// related to your initial `expected_ty` in any particular way, +/// although it will typically be a subtype, so you should check it. +/// - Invoking `complete()` may cause us to go and adjust the "adjustments" on +/// previously coerced expressions. +/// +/// Example: +/// +/// ``` +/// let mut coerce = CoerceMany::new(expected_ty); +/// for expr in exprs { +/// let expr_ty = fcx.check_expr_with_expectation(expr, expected); +/// coerce.coerce(fcx, &cause, expr, expr_ty); +/// } +/// let final_ty = coerce.complete(fcx); +/// ``` +#[derive(Clone)] // (*) +pub struct CoerceMany<'gcx: 'tcx, 'tcx> { + expected_ty: Ty<'tcx>, + final_ty: Option>, + expressions: Vec<&'gcx hir::Expr>, +} + +// (*) this is clone because `FnCtxt` is clone, but it seems dubious -- nmatsakis + +impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { + pub fn new(expected_ty: Ty<'tcx>) -> Self { + CoerceMany { + expected_ty, + final_ty: None, + expressions: vec![], + } + } + + pub fn is_empty(&self) -> bool { + self.expressions.is_empty() + } + + /// Return the "expected type" with which this coercion was + /// constructed. This represents the "downward propagated" type + /// that was given to us at the start of typing whatever construct + /// we are typing (e.g., the match expression). + /// + /// Typically, this is used as the expected type when + /// type-checking each of the alternative expressions whose types + /// we are trying to merge. + pub fn expected_ty(&self) -> Ty<'tcx> { + self.expected_ty + } + + /// Returns the current "merged type", representing our best-guess + /// at the LUB of the expressions we've seen so far (if any). This + /// isn't *final* until you call `self.final()`, which will return + /// the merged type. + pub fn merged_ty(&self) -> Ty<'tcx> { + self.final_ty.unwrap_or(self.expected_ty) + } + + /// Indicates that the value generated by `expression`, which is + /// of type `expression_ty`, is one of the possibility that we + /// could coerce from. This will record `expression` and later + /// calls to `coerce` may come back and add adjustments and things + /// if necessary. + pub fn coerce<'a>(&mut self, + fcx: &FnCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + expression: &'gcx hir::Expr, + expression_ty: Ty<'tcx>) + { + self.coerce_inner(fcx, cause, Some(expression), expression_ty) + } + + /// Indicates that one of the inputs is a "forced unit". This + /// occurs in a case like `if foo { ... };`, where the issing else + /// generates a "forced unit". Another example is a `loop { break; + /// }`, where the `break` has no argument expression. We treat + /// these cases slightly differently for error-reporting + /// purposes. Note that these tend to correspond to cases where + /// the `()` expression is implicit in the source, and hence we do + /// not take an expression argument. + pub fn coerce_forced_unit<'a>(&mut self, + fcx: &FnCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>) + { + self.coerce_inner(fcx, + cause, + None, + fcx.tcx.mk_nil()) + } + + /// The inner coercion "engine". If `expression` is `None`, this + /// is a forced-unit case, and hence `expression_ty` must be + /// `Nil`. + fn coerce_inner<'a>(&mut self, + fcx: &FnCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + expression: Option<&'gcx hir::Expr>, + mut expression_ty: Ty<'tcx>) + { + // Incorporate whatever type inference information we have + // until now; in principle we might also want to process + // pending obligations, but doing so should only improve + // compatibility (hopefully that is true) by helping us + // uncover never types better. + if expression_ty.is_ty_var() { + expression_ty = fcx.infcx.shallow_resolve(expression_ty); + } + + // If we see any error types, just propagate that error + // upwards. + if expression_ty.references_error() || self.merged_ty().references_error() { + self.final_ty = Some(fcx.tcx.types.err); + return; + } + + // Handle the actual type unification etc. + let result = if let Some(expression) = expression { + if self.expressions.is_empty() { + // Special-case the first expression we are coercing. + // To be honest, I'm not entirely sure why we do this. + fcx.try_coerce(expression, expression_ty, self.expected_ty) + } else { + fcx.try_find_coercion_lub(cause, + || self.expressions.iter().cloned(), + self.merged_ty(), + expression, + expression_ty) + } + } else { + // this is a hack for cases where we default to `()` because + // the expression etc has been omitted from the source. An + // example is an `if let` without an else: + // + // if let Some(x) = ... { } + // + // we wind up with a second match arm that is like `_ => + // ()`. That is the case we are considering here. We take + // a different path to get the right "expected, found" + // message and so forth (and because we know that + // `expression_ty` will be unit). + // + // Another example is `break` with no argument expression. + assert!(expression_ty.is_nil()); + assert!(expression_ty.is_nil(), "if let hack without unit type"); + fcx.eq_types(true, cause, expression_ty, self.merged_ty()) + .map(|infer_ok| { + fcx.register_infer_ok_obligations(infer_ok); + expression_ty + }) + }; + + match result { + Ok(v) => { + self.final_ty = Some(v); + self.expressions.extend(expression); + } + Err(err) => { + let (expected, found) = if expression.is_none() { + // In the case where this is a "forced unit", like + // `break`, we want to call the `()` "expected" + // since it is implied by the syntax. + assert!(expression_ty.is_nil()); + (expression_ty, self.final_ty.unwrap_or(self.expected_ty)) + } else { + // Otherwise, the "expected" type for error + // reporting is the current unification type, + // which is basically the LUB of the expressions + // we've seen so far (combined with the expected + // type) + (self.final_ty.unwrap_or(self.expected_ty), expression_ty) + }; + + match cause.code { + ObligationCauseCode::ReturnNoExpression => { + struct_span_err!(fcx.tcx.sess, cause.span, E0069, + "`return;` in a function whose return type is not `()`") + .span_label(cause.span, &format!("return type is not ()")) + .emit(); + } + _ => { + fcx.report_mismatched_types(cause, expected, found, err) + .emit(); + } + } + + self.final_ty = Some(fcx.tcx.types.err); + } + } + } + + pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + if let Some(final_ty) = self.final_ty { + final_ty + } else { + // If we only had inputs that were of type `!` (or no + // inputs at all), then the final type is `!`. + assert!(self.expressions.is_empty()); + fcx.tcx.types.never + } + } +} From 56847af9163284f928d5632a3d0d29399716414f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:51:31 -0400 Subject: [PATCH 376/662] port the match code to use `CoerceMany` `match { }` now (correctly?) indicates divergence, which results in more unreachable warnings. We also avoid fallback to `!` if there is just one arm (see new test: `match-unresolved-one-arm.rs`). --- src/librustc_typeck/check/_match.rs | 90 ++++++++----------- src/libsyntax/parse/obsolete.rs | 1 + .../match-no-arms-unreachable-after.rs | 22 +++++ ...eachable-warning-with-diverging-discrim.rs | 16 ++++ .../compile-fail/match-unresolved-one-arm.rs | 17 ++++ 5 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 src/test/compile-fail/match-no-arms-unreachable-after.rs create mode 100644 src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs create mode 100644 src/test/compile-fail/match-unresolved-one-arm.rs diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index feed5752cf8fb..f0d2598a0fb2a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -16,6 +16,7 @@ use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; +use check::coercion::CoerceMany; use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -414,6 +415,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type(discrim, discrim_ty); }; + + // If the discriminant diverges, the match is pointless (e.g., + // `match (return) { }`). + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // If there are no arms, that is a diverging match; a special case. + if arms.is_empty() { + self.diverges.set(self.diverges.get() | Diverges::Always); + return tcx.types.never; + } + + // Otherwise, we have to union together the types that the + // arms produce and so forth. + let discrim_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -426,6 +441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&p, discrim_ty); all_pats_diverge &= self.diverges.get(); } + // As discussed with @eddyb, this is for disabling unreachable_code // warnings on patterns (they're now subsumed by unreachable_patterns // warnings). @@ -444,20 +460,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // on any empty type and is therefore unreachable; should the flow // of execution reach it, we will panic, so bottom is an appropriate // type in that case) - let expected = expected.adjust_for_branches(self); - let mut result_ty = self.next_diverging_ty_var( - TypeVariableOrigin::DivergingBlockExpr(expr.span)); let mut all_arms_diverge = Diverges::WarnedAlways; - let coerce_first = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { - ety - } - _ => result_ty + + let expected = expected.adjust_for_branches(self); + + let mut coercion = { + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, + _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + }; + CoerceMany::new(coerce_first) }; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { @@ -470,11 +487,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - if result_ty.references_error() || arm_ty.references_error() { - result_ty = tcx.types.err; - continue; - } - // Handle the fallback arm of a desugared if-let like a missing else. let is_if_let_fallback = match match_src { hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { @@ -483,47 +495,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false }; - let cause = if is_if_let_fallback { - self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse) + if is_if_let_fallback { + let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); + assert!(arm_ty.is_nil()); + coercion.coerce_forced_unit(self, &cause); } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, source: match_src - }) - }; - - let result = if is_if_let_fallback { - self.eq_types(true, &cause, arm_ty, result_ty) - .map(|infer_ok| { - self.register_infer_ok_obligations(infer_ok); - arm_ty - }) - } else if i == 0 { - // Special-case the first arm, as it has no "previous expressions". - self.try_coerce(&arm.body, arm_ty, coerce_first) - } else { - let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty) - }; - - result_ty = match result { - Ok(ty) => ty, - Err(e) => { - let (expected, found) = if is_if_let_fallback { - (arm_ty, result_ty) - } else { - (result_ty, arm_ty) - }; - self.report_mismatched_types(&cause, expected, found, e).emit(); - self.tcx.types.err - } - }; + }); + coercion.coerce(self, &cause, &arm.body, arm_ty); + } } // We won't diverge unless the discriminant or all arms diverge. self.diverges.set(discrim_diverges | all_arms_diverge); - result_ty + coercion.complete(self) } fn check_pat_struct(&self, diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a46a788ca0808..d5baec675e44f 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. #[allow(unused_variables)] + #[allow(unreachable_code)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { // Nothing here at the moment diff --git a/src/test/compile-fail/match-no-arms-unreachable-after.rs b/src/test/compile-fail/match-no-arms-unreachable-after.rs new file mode 100644 index 0000000000000..db08f5e5e66a3 --- /dev/null +++ b/src/test/compile-fail/match-no-arms-unreachable-after.rs @@ -0,0 +1,22 @@ +// 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. + +#![allow(warnings)] +#![deny(unreachable_code)] + +enum Void { } + +fn foo(v: Void) { + match v { } + let x = 2; //~ ERROR unreachable +} + +fn main() { +} diff --git a/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs new file mode 100644 index 0000000000000..aae0f3135d8f5 --- /dev/null +++ b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.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. + +#![allow(unused_parens)] +#![deny(unreachable_code)] + +fn main() { + match (return) { } //~ ERROR unreachable expression +} diff --git a/src/test/compile-fail/match-unresolved-one-arm.rs b/src/test/compile-fail/match-unresolved-one-arm.rs new file mode 100644 index 0000000000000..ea0f8db99e893 --- /dev/null +++ b/src/test/compile-fail/match-unresolved-one-arm.rs @@ -0,0 +1,17 @@ +// 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. + +fn foo() -> T { panic!("Rocks for my pillow") } + +fn main() { + let x = match () { //~ ERROR type annotations needed + () => foo() // T here should be unresolved + }; +} From b725272b265268fbe4f3220111ae1a053b3a37a7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:52:38 -0400 Subject: [PATCH 377/662] port if-then-else to use `CoerceMany` --- src/librustc_typeck/check/mod.rs | 71 +++++++++++++++----------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5d002dba78c24..69f1466c47518 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,6 +77,7 @@ type parameter). */ pub use self::Expectation::*; +use self::coercion::CoerceMany; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; @@ -299,12 +300,23 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { } } + /// It sometimes happens that we want to turn an expectation into + /// a **hard constraint** (i.e., something that must be satisfied + /// for the program to type-check). `only_has_type` will return + /// such a constraint, if it exists. fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { match self.resolve(fcx) { ExpectHasType(ty) => Some(ty), _ => None } } + + /// Like `only_has_type`, but instead of returning `None` if no + /// hard constraint exists, creates a fresh type variable. + fn only_has_type_or_fresh_var(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { + self.only_has_type(fcx) + .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span))) + } } #[derive(Copy, Clone)] @@ -2743,54 +2755,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); - let unit = self.tcx.mk_nil(); - let (cause, expected_ty, found_ty, result); + // We've already taken the expected type's preferences + // into account when typing the `then` branch. To figure + // out the initial shot at a LUB, we thus only consider + // `expected` if it represents a *hard* constraint + // (`only_has_type`); otherwise, we just go with a + // fresh type variable. + let coerce_to_ty = expected.only_has_type_or_fresh_var(self, sp); + let mut coerce = CoerceMany::new(coerce_to_ty); + + let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); + coerce.coerce(self, &if_cause, then_expr, then_ty); + if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - cause = self.cause(sp, ObligationCauseCode::IfExpression); - - // Only try to coerce-unify if we have a then expression - // to assign coercions to, otherwise it's () or diverging. - expected_ty = then_ty; - found_ty = else_ty; - - let coerce_to = expected.only_has_type(self).unwrap_or(then_ty); - result = { - self.try_coerce(then_expr, then_ty, coerce_to) - .and_then(|t| { - self.try_find_coercion_lub(&cause, || Some(then_expr), t, else_expr, else_ty) - }) - }; + + coerce.coerce(self, &if_cause, else_expr, else_ty); // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); } else { + let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); + coerce.coerce_forced_unit(self, &else_cause); + // If the condition is false we can't diverge. self.diverges.set(cond_diverges); - - cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - expected_ty = unit; - found_ty = then_ty; - result = self.eq_types(true, &cause, unit, then_ty) - .map(|ok| { - self.register_infer_ok_obligations(ok); - unit - }); } - match result { - Ok(ty) => { - if cond_ty.references_error() { - self.tcx.types.err - } else { - ty - } - } - Err(e) => { - self.report_mismatched_types(&cause, expected_ty, found_ty, e).emit(); - self.tcx.types.err - } + let result_ty = coerce.complete(self); + if cond_ty.references_error() { + self.tcx.types.err + } else { + result_ty } } From a6e6be5f88bc773f50016cc1cf1baaa7b3e6cd11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:54:26 -0400 Subject: [PATCH 378/662] port `return` expressions to use `CoerceMany` This slightly affects the error messages in one particular compile-fail test. --- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/mod.rs | 85 +++++++++++++++------ src/librustc_typeck/check/wfcheck.rs | 2 +- src/test/compile-fail/regions-bounds.rs | 10 +-- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 0e9abaf1cf955..905d8688ea194 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -362,7 +362,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id); + let fcx = FnCtxt::new(&inh, impl_m_body_id); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 69f1466c47518..619f4fb10c544 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -448,7 +448,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_ty: Option>, + ret_coercion: Option>>, ps: RefCell, @@ -679,7 +679,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_fn(&inh, fn_sig, decl, id, body) } else { - let fcx = FnCtxt::new(&inh, None, body.value.id); + let fcx = FnCtxt::new(&inh, body.value.id); let expected_type = tcx.item_type(def_id); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -800,15 +800,16 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, None, body.value.id); - let ret_ty = fn_sig.output(); + let mut fcx = FnCtxt::new(inherited, body.value.id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + let ret_ty = fn_sig.output(); fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty)); + let ret_ty = fcx.instantiate_anon_types(&ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), - fcx.ret_ty.unwrap(), + ret_ty, fn_sig.variadic, fn_sig.unsafety, fn_sig.abi @@ -833,7 +834,38 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap()); + fcx.check_return_expr(&body.value); + + // Finalize the return check by taking the LUB of the return types + // we saw and assigning it to the expected return type. This isn't + // really expected to fail, since the coercions would have failed + // earlier when trying to find a LUB. + // + // However, the behavior around `!` is sort of complex. In the + // event that the `actual_return_ty` comes back as `!`, that + // indicates that the fn either does not return or "returns" only + // values of type `!`. In this case, if there is an expected + // return type that is *not* `!`, that should be ok. But if the + // return type is being inferred, we want to "fallback" to `!`: + // + // let x = move || panic!(); + // + // To allow for that, I am creating a type variable with diverging + // fallback. This was deemed ever so slightly better than unifying + // the return value with `!` because it allows for the caller to + // make more assumptions about the return type (e.g., they could do + // + // let y: Option = Some(x()); + // + // which would then cause this return type to become `u32`, not + // `!`). + let coercion = fcx.ret_coercion.take().unwrap().into_inner(); + let mut actual_return_ty = coercion.complete(&fcx); + if actual_return_ty.is_never() { + actual_return_ty = fcx.next_diverging_ty_var( + TypeVariableOrigin::DivergingFn(body.value.span)); + } + fcx.demand_suptype(body.value.span, ret_ty, actual_return_ty); fcx } @@ -1429,14 +1461,13 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - rty: Option>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { ast_ty_to_ty_cache: RefCell::new(NodeMap()), body_id: body_id, err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: rty, + ret_coercion: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -2738,6 +2769,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty } + fn check_return_expr(&self, return_expr: &'gcx hir::Expr) { + let ret_coercion = + self.ret_coercion + .as_ref() + .unwrap_or_else(|| span_bug!(return_expr.span, + "check_return_expr called outside fn body")); + + let ret_ty = ret_coercion.borrow().expected_ty(); + let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); + ret_coercion.borrow_mut() + .coerce(self, + &self.misc(return_expr.span), + return_expr, + return_expr_ty); + } + + // A generic function for checking the then and else in an if // or if-else. fn check_then_else(&self, @@ -3522,24 +3570,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { - if self.ret_ty.is_none() { + if self.ret_coercion.is_none() { struct_span_err!(self.tcx.sess, expr.span, E0572, "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); + self.check_return_expr(e); } else { - match self.eq_types(false, - &self.misc(expr.span), - self.ret_ty.unwrap(), - tcx.mk_nil()) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - struct_span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(expr.span, &format!("return type is not ()")) - .emit(); - } - } + let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); + let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); + coercion.coerce_forced_unit(self, &cause); } tcx.types.never } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a4cb4071b4d88..85c87adf9be68 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, None, id); + let fcx = FnCtxt::new(&inh, id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { tcx: fcx.tcx.global_tcx(), code: code diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 64dbf27b78e48..810a8671c536b 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,17 +16,11 @@ struct an_enum<'a>(&'a isize); struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~ ERROR mismatched types - //~| expected type `an_enum<'b>` - //~| found type `an_enum<'a>` - //~| lifetime mismatch + return e; //~^ ERROR mismatched types } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~ ERROR mismatched types - //~| expected type `a_class<'b>` - //~| found type `a_class<'a>` - //~| lifetime mismatch + return e; //~^ ERROR mismatched types } fn main() { } From 4967f1ae57120b02639f3d1493e8f0c9e168b0dc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:10:12 -0400 Subject: [PATCH 379/662] document the diverges flag etc --- src/librustc_typeck/check/mod.rs | 43 +++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 619f4fb10c544..e186daf9f408e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -360,11 +360,12 @@ impl UnsafetyState { } } -/// Whether a node ever exits normally or not. -/// Tracked semi-automatically (through type variables -/// marked as diverging), with some manual adjustments -/// for control-flow primitives (approximating a CFG). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Tracks whether executing a node may exit normally (versus +/// return/break/panic, which "diverge", leaving dead code in their +/// wake). Tracked semi-automatically (through type variables marked +/// as diverging), with some manual adjustments for control-flow +/// primitives (approximating a CFG). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] enum Diverges { /// Potentially unknown, some cases converge, /// others require a CFG to determine them. @@ -452,7 +453,37 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, - /// Whether the last checked node can ever exit. + /// Whether the last checked node generates a divergence (e.g., + /// `return` will set this to Always). In general, this is + /// typically set to *Maybe* on the way **down** the tree, and + /// then values are propagated **up** the tree. In a block, we + /// combine the results from statements and propagate the + /// end-result up. + /// + /// We use this flag for two purposes: + /// + /// - To warn about unreachable code: if, after processing a + /// sub-expression but before we have applied the effects of the + /// current node, we see that the flag is set to `Always`, we + /// can issue a warning. This corresponds to something like + /// `foo(return)`; we warn on the `foo()` expression. (We then + /// update the flag to `WarnedAlways` to suppress duplicate + /// reports.) Similarly, if we traverse to a fresh statement (or + /// tail expression) from a `Always` setting, we will isssue a + /// warning. This corresponds to something like `{return; + /// foo();}` or `{return; 22}`, where we would warn on the + /// `foo()` or `22`. + /// + /// - To permit assignment into a local variable or other lvalue + /// (including the "return slot") of type `!`. This is allowed + /// if **either** the type of value being assigned is `!`, which + /// means the current code is dead, **or** the expression's + /// divering flag is true, which means that a divering value was + /// wrapped (e.g., `let x: ! = foo(return)`). + /// + /// To repeat the last point: an expression represents dead-code + /// if, after checking it, **either** its type is `!` OR the + /// diverges flag is set to something other than `Maybe`. diverges: Cell, /// Whether any child nodes have any type errors. From 1ae620bbebadbe4362a28b37bcecd41cfed66cea Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:48:18 -0400 Subject: [PATCH 380/662] do not eagerly convert `!` to a diverging variable Instead, wait until coercion time. This has some small effects on a few tests (one less temporary, generally better errors when trying to call methods or otherwise "force" the type). --- src/librustc_typeck/check/coercion.rs | 26 +++++++-- src/librustc_typeck/check/mod.rs | 79 +++++++++++++++------------ src/test/compile-fail/index-bot.rs | 2 +- src/test/compile-fail/issue-13847.rs | 2 +- src/test/compile-fail/issue-15207.rs | 2 +- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-17373.rs | 2 +- src/test/compile-fail/issue-18532.rs | 3 +- 8 files changed, 71 insertions(+), 47 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 40ae169a94e0d..a08faf2610e33 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -169,7 +169,23 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } if a.is_never() { - return success(Adjust::NeverToAny, b, vec![]); + // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound + // type variable, we want `?T` to fallback to `!` if not + // otherwise constrained. An example where this arises: + // + // let _: Option = Some({ return; }); + // + // here, we would coerce from `!` to `?T`. + let b = self.shallow_resolve(b); + return if self.shallow_resolve(b).is_ty_var() { + // micro-optimization: no need for this if `b` is + // already resolved in some way. + let diverging_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(self.cause.span)); + self.unify_and(&b, &diverging_ty, Adjust::NeverToAny) + } else { + success(Adjust::NeverToAny, b, vec![]) + }; } // Consider coercing the subtype to a DST @@ -687,11 +703,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); - match self.tables.borrow().adjustments.get(&expr.id) { - None | - Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (), - _ => bug!("expr already has an adjustment on it!"), - }; + if self.tables.borrow().adjustments.get(&expr.id).is_some() { + bug!("expr already has an adjustment on it!"); + } self.write_adjustment(expr.id, adjustment); } Ok(adjustment.target) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e186daf9f408e..ae0ed81ac778b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2664,7 +2664,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_has_type(&self, expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.check_expr_with_hint(expr, expected); + let mut ty = self.check_expr_with_hint(expr, expected); + + // While we don't allow *arbitrary* coercions here, we *do* allow + // coercions from ! to `expected`. + if ty.is_never() { + assert!(!self.tables.borrow().adjustments.contains_key(&expr.id), + "expression with never type wound up being adjusted"); + let adj_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(expr.span)); + self.write_adjustment(expr.id, adjustment::Adjustment { + kind: adjustment::Adjust::NeverToAny, + target: adj_ty + }); + ty = adj_ty; + } + self.demand_suptype(expr.span, expected, ty); ty } @@ -3370,18 +3385,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("type of {} is...", self.tcx.hir.node_to_string(expr.id)); debug!("... {:?}, expected is {:?}", ty, expected); - // Add adjustments to !-expressions - if ty.is_never() { - if let Some(hir::map::NodeExpr(node_expr)) = self.tcx.hir.find(expr.id) { - let adj_ty = self.next_diverging_ty_var( - TypeVariableOrigin::AdjustmentType(node_expr.span)); - self.write_adjustment(expr.id, adjustment::Adjustment { - kind: adjustment::Adjust::NeverToAny, - target: adj_ty - }); - return adj_ty; - } - } ty } @@ -4072,7 +4075,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { let unit = self.tcx.mk_nil(); let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); - self.demand_suptype(blk.span, unit, ty); + + // if the block produces a `!` value, that can always be + // (effectively) coerced to unit. + if !ty.is_never() { + self.demand_suptype(blk.span, unit, ty); + } } fn check_block_with_expected(&self, @@ -4111,7 +4119,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, None => { e_ty = if self.diverges.get().always() { - self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)) + self.tcx.types.never } else { self.tcx.mk_nil() }; @@ -4135,6 +4143,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(err) => self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(), } + } else if self.diverges.get().always() { + // No tail expression and the body diverges; ignore + // the expected type, and keep `!` as the type of the + // block. } else { self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty); }; @@ -4147,33 +4159,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut ty = match blk.expr { Some(ref e) => self.check_expr_with_expectation(e, expected), - None => self.tcx.mk_nil() + None => if self.diverges.get().always() { + self.tcx.types.never + } else { + self.tcx.mk_nil() + }, }; - if self.diverges.get().always() { - if let ExpectHasType(ety) = expected { - // Avoid forcing a type (only `!` for now) in unreachable code. - // FIXME(aburka) do we need this special case? and should it be is_uninhabited? - if !ety.is_never() { - if let Some(ref e) = blk.expr { - // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); - } - } - } - - ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); - } else if let ExpectHasType(ety) = expected { + if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { // Coerce the tail expression to the right type. self.demand_coerce(e, ty, ety); + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } else if self.diverges.get().always() { + // No tail expression and the body diverges; ignore + // the expected type, and keep `!` as the type of the + // block. } else { self.check_block_no_expr(blk, ty, ety); - } - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } } ty }; diff --git a/src/test/compile-fail/index-bot.rs b/src/test/compile-fail/index-bot.rs index 70c362303ae30..05b0472330048 100644 --- a/src/test/compile-fail/index-bot.rs +++ b/src/test/compile-fail/index-bot.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - (return)[0]; //~ ERROR the type of this value must be known in this context + (return)[0]; //~ ERROR cannot index a value of type `!` } diff --git a/src/test/compile-fail/issue-13847.rs b/src/test/compile-fail/issue-13847.rs index aa823d9a70e7c..0314f109a7c81 100644 --- a/src/test/compile-fail/issue-13847.rs +++ b/src/test/compile-fail/issue-13847.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - return.is_failure //~ ERROR the type of this value must be known in this context + return.is_failure //~ ERROR no field `is_failure` on type `!` } diff --git a/src/test/compile-fail/issue-15207.rs b/src/test/compile-fail/issue-15207.rs index 61877775269d1..70da8cf4169bd 100644 --- a/src/test/compile-fail/issue-15207.rs +++ b/src/test/compile-fail/issue-15207.rs @@ -10,7 +10,7 @@ fn main() { loop { - break.push(1) //~ ERROR the type of this value must be known in this context + break.push(1) //~ ERROR no method named `push` found for type `!` ; } } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 08b896f387bbe..d5d597c190ea0 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR the type of this value must be known in this context +//~^ ERROR expected function, found `!` () ; } diff --git a/src/test/compile-fail/issue-17373.rs b/src/test/compile-fail/issue-17373.rs index 6895893adc4d0..f6e6a8a0852dd 100644 --- a/src/test/compile-fail/issue-17373.rs +++ b/src/test/compile-fail/issue-17373.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - *return //~ ERROR the type of this value must be known in this context + *return //~ ERROR type `!` cannot be dereferenced ; } diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 94eab97c42a19..2be5fdcac4ede 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -13,6 +13,5 @@ // into it. fn main() { - (return)((),()); - //~^ ERROR the type of this value must be known + (return)((),()); //~ ERROR expected function, found `!` } From 16a71cce514f29cb8c532248cf749e26972afb01 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:49:53 -0400 Subject: [PATCH 381/662] rework how we handle the type of loops First, we keep a `CoerceMany` now to find the LUB of all the break expressions. Second, this `CoerceMany` is actually an `Option`, and we store `None` for loops where "break with an expression" is disallowed. This avoids silly duplicate errors about a type mismatch, since the loops pass already reports an error that the break cannot have an expression. Finally, since we now detect an invalid break target during HIR lowering, refactor `find_loop` to be infallible. Adjust tests as needed: - some spans from breaks are slightly different - break up a single loop into multiple since `CoerceMany` silences redundant and derived errors - add a ui test that we only give on error for loop-break-value --- src/librustc_typeck/check/mod.rs | 207 ++++++++++-------- src/test/compile-fail/issue-27042.rs | 8 +- src/test/compile-fail/loop-break-value.rs | 23 +- src/test/ui/loop-break-value-no-repeat.rs | 25 +++ src/test/ui/loop-break-value-no-repeat.stderr | 8 + 5 files changed, 161 insertions(+), 110 deletions(-) create mode 100644 src/test/ui/loop-break-value-no-repeat.rs create mode 100644 src/test/ui/loop-break-value-no-repeat.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae0ed81ac778b..59f3ac739e0a2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -415,15 +415,16 @@ impl Diverges { } #[derive(Clone)] -pub struct BreakableCtxt<'gcx, 'tcx> { - unified: Ty<'tcx>, - coerce_to: Ty<'tcx>, - break_exprs: Vec<&'gcx hir::Expr>, +pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { may_break: bool, + + // this is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let` + coerce: Option>, } #[derive(Clone)] -pub struct EnclosingBreakables<'gcx, 'tcx> { +pub struct EnclosingBreakables<'gcx: 'tcx, 'tcx> { stack: Vec>, by_id: NodeMap, } @@ -3547,60 +3548,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } hir::ExprBreak(destination, ref expr_opt) => { - if let Some(target_id) = destination.target_id.opt_id() { - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable(target_id).coerce_to - }; - - let e_ty; - let cause; - if let Some(ref e) = *expr_opt { - // Recurse without `enclosing_loops` borrowed. - e_ty = self.check_expr_with_hint(e, coerce_to); - cause = self.misc(e.span); - // Notably, the recursive call may alter coerce_to - must not keep using it! - } else { - // `break` without argument acts like `break ()`. - e_ty = tcx.mk_nil(); - cause = self.misc(expr.span); - } - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(target_id); + if let Some(target_id) = destination.target_id.opt_id() { + let (e_ty, cause); + if let Some(ref e) = *expr_opt { + // If this is a break with a value, we need to type-check + // the expression. Get an expected type from the loop context. + let opt_coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable(target_id) + .coerce + .as_ref() + .map(|coerce| coerce.expected_ty()) + }; + + // If the loop context is not a `loop { }`, then break with + // a value is illegal, and `opt_coerce_to` will be `None`. + // Just set expectation to error in that case. + let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); + + // Recurse without `enclosing_breakables` borrowed. + e_ty = self.check_expr_with_hint(e, coerce_to); + cause = self.misc(e.span); + } else { + // Otherwise, this is a break *without* a value. That's + // always legal, and is equivalent to `break ()`. + e_ty = tcx.mk_nil(); + cause = self.misc(expr.span); + } - let result = if let Some(ref e) = *expr_opt { - // Special-case the first element, as it has no "previous expressions". - let result = if !ctxt.may_break { - self.try_coerce(e, e_ty, ctxt.coerce_to) - } else { - self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(), - ctxt.unified, e, e_ty) - }; + // Now that we have type-checked `expr_opt`, borrow + // the `enclosing_loops` field and let's coerce the + // type of `expr_opt` into what is expected. + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(target_id); + if let Some(ref mut coerce) = ctxt.coerce { + if let Some(ref e) = *expr_opt { + coerce.coerce(self, &cause, e, e_ty); + } else { + assert!(e_ty.is_nil()); + coerce.coerce_forced_unit(self, &cause); + } + } else { + // If `ctxt.coerce` is `None`, we can just ignore + // the type of the expresison. This is because + // either this was a break *without* a value, in + // which case it is always a legal type (`()`), or + // else an error would have been flagged by the + // `loops` pass for using break with an expression + // where you are not supposed to. + assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0); + } - ctxt.break_exprs.push(e); - result - } else { - self.eq_types(true, &cause, e_ty, ctxt.unified) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - e_ty - }) - }; - match result { - Ok(ty) => ctxt.unified = ty, - Err(err) => { - self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(); - } - } + ctxt.may_break = true; + } else { + // Otherwise, we failed to find the enclosing loop; this can only happen if the + // `break` was not inside a loop at all, which is caught by the loop-checking pass. + assert!(self.tcx.sess.err_count() > 0); + } - ctxt.may_break = true; - } - // Otherwise, we failed to find the enclosing breakable; this can only happen if the - // `break` target was not found, which is caught in HIR lowering and reported by the - // loop-checking pass. - tcx.types.never + // the type of a `break` is always `!`, since it diverges + tcx.types.never } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { @@ -3645,51 +3652,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - let unified = self.tcx.mk_nil(); - let coerce_to = unified; - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: true, - }; - self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_expr_has_type(&cond, tcx.types.bool); - let cond_diverging = self.diverges.get(); - self.check_block_no_value(&body); + let ctxt = BreakableCtxt { + // cannot use break with a value from a while loop + coerce: None, + may_break: true, + }; - // We may never reach the body so it diverging means nothing. - self.diverges.set(cond_diverging); - }); + self.with_breakable_ctxt(expr.id, ctxt, || { + self.check_expr_has_type(&cond, tcx.types.bool); + let cond_diverging = self.diverges.get(); + self.check_block_no_value(&body); - if self.has_errors.get() { - tcx.types.err - } else { - tcx.mk_nil() - } + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + }); + + self.tcx.mk_nil() } - hir::ExprLoop(ref body, _, _) => { - let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(body.span)); - let coerce_to = expected.only_has_type(self).unwrap_or(unified); - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: false, - }; + hir::ExprLoop(ref body, _, source) => { + let coerce = match source { + // you can only use break with a value from a normal `loop { }` + hir::LoopSource::Loop => { + let coerce_to = expected.only_has_type_or_fresh_var(self, body.span); + Some(CoerceMany::new(coerce_to)) + } - let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_block_no_value(&body); - }); - if ctxt.may_break { - // No way to know whether it's diverging because - // of a `break` or an outer `break` or `return. - self.diverges.set(Diverges::Maybe); + hir::LoopSource::WhileLet | + hir::LoopSource::ForLoop => { + None + } + }; - ctxt.unified - } else { - tcx.types.never - } + let ctxt = BreakableCtxt { + coerce: coerce, + may_break: false, // will get updated if/when we find a `break` + }; + + let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { + self.check_block_no_value(&body); + }); + + if ctxt.may_break { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return. + self.diverges.set(Diverges::Maybe); + } + + // If we permit break with a value, then result type is + // the LUB of the breaks (possibly ! if none); else, it + // is nil. This makes sense because infinite loops + // (which would have type !) are only possible iff we + // permit break with a value [1]. + assert!(ctxt.coerce.is_some() || ctxt.may_break); // [1] + ctxt.coerce.map(|c| c.complete(self)).unwrap_or(self.tcx.mk_nil()) } hir::ExprMatch(ref discrim, ref arms, match_src) => { self.check_match(expr, &discrim, arms, expected, match_src) diff --git a/src/test/compile-fail/issue-27042.rs b/src/test/compile-fail/issue-27042.rs index f31389f1337dd..23afa4b629636 100644 --- a/src/test/compile-fail/issue-27042.rs +++ b/src/test/compile-fail/issue-27042.rs @@ -12,14 +12,14 @@ fn main() { let _: i32 = - 'a: //~ ERROR mismatched types - loop { break }; + 'a: // in this case, the citation is just the `break`: + loop { break }; //~ ERROR mismatched types let _: i32 = 'b: //~ ERROR mismatched types - while true { break }; + while true { break }; // but here we cite the whole loop let _: i32 = 'c: //~ ERROR mismatched types - for _ in None { break }; + for _ in None { break }; // but here we cite the whole loop let _: i32 = 'd: //~ ERROR mismatched types while let Some(_) = None { break }; diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index d4f2959748698..a414321899203 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -40,37 +40,40 @@ fn main() { loop { break 'while_loop 123; //~^ ERROR `break` with value from a `while` loop - //~| ERROR mismatched types break 456; break 789; }; } - 'while_let_loop: while let Some(_) = Some(()) { + while let Some(_) = Some(()) { if break () { //~ ERROR `break` with value from a `while let` loop - break; - break None; - //~^ ERROR `break` with value from a `while let` loop - //~| ERROR mismatched types } + } + + while let Some(_) = Some(()) { + break None; + //~^ ERROR `break` with value from a `while let` loop + } + + 'while_let_loop: while let Some(_) = Some(()) { loop { break 'while_let_loop "nope"; //~^ ERROR `break` with value from a `while let` loop - //~| ERROR mismatched types break 33; }; } - 'for_loop: for _ in &[1,2,3] { + for _ in &[1,2,3] { break (); //~ ERROR `break` with value from a `for` loop break [()]; //~^ ERROR `break` with value from a `for` loop - //~| ERROR mismatched types + } + + 'for_loop: for _ in &[1,2,3] { loop { break Some(3); break 'for_loop Some(17); //~^ ERROR `break` with value from a `for` loop - //~| ERROR mismatched types }; } diff --git a/src/test/ui/loop-break-value-no-repeat.rs b/src/test/ui/loop-break-value-no-repeat.rs new file mode 100644 index 0000000000000..790f796fae07f --- /dev/null +++ b/src/test/ui/loop-break-value-no-repeat.rs @@ -0,0 +1,25 @@ +// 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. + +#![feature(loop_break_value)] +#![allow(unused_variables)] + +use std::ptr; + +// Test that we only report **one** error here and that is that +// `break` with an expression is illegal in this context. In +// particular, we don't report any mismatched types error, which is +// besides the point. + +fn main() { + for _ in &[1,2,3] { + break 22 + } +} diff --git a/src/test/ui/loop-break-value-no-repeat.stderr b/src/test/ui/loop-break-value-no-repeat.stderr new file mode 100644 index 0000000000000..0d99abd3907d8 --- /dev/null +++ b/src/test/ui/loop-break-value-no-repeat.stderr @@ -0,0 +1,8 @@ +error[E0571]: `break` with value from a `for` loop + --> $DIR/loop-break-value-no-repeat.rs:23:9 + | +23 | break 22 + | ^^^^^^^^ can only break with a value inside `loop` + +error: aborting due to previous error + From 140165f22e5614a4f14e9f7175c5607dfaf12363 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:52:37 -0400 Subject: [PATCH 382/662] rewrite `ExprArray` processing to use `CoerceMany` --- src/librustc_typeck/check/mod.rs | 49 +++++++++++++------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 59f3ac739e0a2..73d4e7db1d842 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3752,36 +3752,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { typ } hir::ExprArray(ref args) => { - let uty = expected.to_option(self).and_then(|uty| { - match uty.sty { - ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), - _ => None - } - }); - - let mut unified = self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)); - let coerce_to = uty.unwrap_or(unified); - - for (i, e) in args.iter().enumerate() { - let e_ty = self.check_expr_with_hint(e, coerce_to); - let cause = self.misc(e.span); - - // Special-case the first element, as it has no "previous expressions". - let result = if i == 0 { - self.try_coerce(e, e_ty, coerce_to) - } else { - let prev_elems = || args[..i].iter().map(|e| &*e); - self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty) - }; + let uty = expected.to_option(self).and_then(|uty| { + match uty.sty { + ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), + _ => None + } + }); - match result { - Ok(ty) => unified = ty, - Err(e) => { - self.report_mismatched_types(&cause, unified, e_ty, e).emit(); - } - } - } - tcx.mk_array(unified, args.len()) + let element_ty = if !args.is_empty() { + let coerce_to = uty.unwrap_or_else( + || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); + let mut coerce = CoerceMany::new(coerce_to); + for e in args { + let e_ty = self.check_expr_with_hint(e, coerce_to); + let cause = self.misc(e.span); + coerce.coerce(self, &cause, e, e_ty); + } + coerce.complete(self) + } else { + self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)) + }; + tcx.mk_array(element_ty, args.len()) } hir::ExprRepeat(ref element, count) => { let count = eval_length(self.tcx.global_tcx(), count, "repeat count") From cecccd9bef2ce56b91b7ac3b067f0afa2e7846db Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:53:02 -0400 Subject: [PATCH 383/662] whitespace changes, debug message --- src/librustc_typeck/check/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 73d4e7db1d842..21eaa0c2120d5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1526,6 +1526,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if self.diverges.get() == Diverges::Always { self.diverges.set(Diverges::WarnedAlways); + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); + self.tables.borrow_mut().lints.add_lint( lint::builtin::UNREACHABLE_CODE, id, span, @@ -2545,8 +2547,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Expectation::rvalue_hint(self, ty) }); - let checked_ty = self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); + let checked_ty = self.check_expr_with_expectation( + &arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced // to, which is `expected_ty` if `rvalue_hint` returns an // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. From 52e524a3578b7661d6430735c7cd51eeccdacb0b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:53:15 -0400 Subject: [PATCH 384/662] make `try_find_coercion_lub` private; we always use `CoerceMany` --- src/librustc_typeck/check/coercion.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a08faf2610e33..c420449cea092 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -715,13 +715,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). - pub fn try_find_coercion_lub<'b, E, I>(&self, - cause: &ObligationCause<'tcx>, - exprs: E, - prev_ty: Ty<'tcx>, - new: &'b hir::Expr, - new_ty: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> + /// + /// This is really an internal helper. From outside the coercion + /// module, you should instantiate a `CoerceMany` instance. + fn try_find_coercion_lub<'b, E, I>(&self, + cause: &ObligationCause<'tcx>, + exprs: E, + prev_ty: Ty<'tcx>, + new: &'b hir::Expr, + new_ty: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> where E: Fn() -> I, I: IntoIterator { From 5cd99aa1677075baecbd5224861b36a7719e0f25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 14:10:00 -0400 Subject: [PATCH 385/662] more detailed tests around diverging type variables --- .../compile-fail/defaulted-unit-warning.rs | 12 +- src/test/compile-fail/never-fallback.rs | 41 ------- .../diverging-fallback-control-flow.rs | 106 ++++++++++++++++++ ....rs => diverging-fallback-method-chain.rs} | 33 ++---- .../run-pass/diverging-fallback-option.rs | 22 ++++ 5 files changed, 140 insertions(+), 74 deletions(-) delete mode 100644 src/test/compile-fail/never-fallback.rs create mode 100644 src/test/run-pass/diverging-fallback-control-flow.rs rename src/test/run-pass/{unit-fallback.rs => diverging-fallback-method-chain.rs} (51%) create mode 100644 src/test/run-pass/diverging-fallback-option.rs diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs index 5213a189714dd..ed6263d0fdbd1 100644 --- a/src/test/compile-fail/defaulted-unit-warning.rs +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -22,16 +22,6 @@ impl Deserialize for () { } } -fn doit() -> Result<(), String> { - let _ = match Deserialize::deserialize() { - //~^ ERROR code relies on type - //~| WARNING previously accepted - Ok(x) => x, - Err(e) => return Err(e), - }; - Ok(()) -} - trait ImplementedForUnitButNotNever {} impl ImplementedForUnitButNotNever for () {} @@ -46,6 +36,6 @@ fn smeg() { } fn main() { - let _ = doit(); + smeg(); } diff --git a/src/test/compile-fail/never-fallback.rs b/src/test/compile-fail/never-fallback.rs deleted file mode 100644 index a43b1a45fe939..0000000000000 --- a/src/test/compile-fail/never-fallback.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that diverging types default to ! when feature(never_type) is enabled. This test is the -// same as run-pass/unit-fallback.rs except that ! is enabled. - -#![feature(never_type)] - -trait Balls: Sized { - fn smeg() -> Result; -} - -impl Balls for () { - fn smeg() -> Result<(), ()> { Ok(()) } -} - -struct Flah; - -impl Flah { - fn flah(&self) -> Result { - T::smeg() - } -} - -fn doit() -> Result<(), ()> { - // The type of _ is unconstrained here and should default to ! - let _ = try!(Flah.flah()); //~ ERROR the trait bound - Ok(()) -} - -fn main() { - let _ = doit(); -} - diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs new file mode 100644 index 0000000000000..656e90d2d52d7 --- /dev/null +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -0,0 +1,106 @@ +// 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 various cases where we permit an unconstrained variable +// to fallback based on control-flow. +// +// These represent current behavior, but are pretty dubious. I would +// like to revisit these and potentially change them. --nmatsakis + +#![feature(never_type)] +#![feature(loop_break_value)] + +trait BadDefault { + fn default() -> Self; +} + +impl BadDefault for u32 { + fn default() -> Self { + 0 + } +} + +impl BadDefault for ! { + fn default() -> ! { + panic!() + } +} + +fn assignment() { + let x; + + if true { + x = BadDefault::default(); + } else { + x = return; + } +} + +fn assignment_rev() { + let x; + + if true { + x = return; + } else { + x = BadDefault::default(); + } +} + +fn if_then_else() { + let _x = if true { + BadDefault::default() + } else { + return; + }; +} + +fn if_then_else_rev() { + let _x = if true { + return; + } else { + BadDefault::default() + }; +} + +fn match_arm() { + let _x = match Ok(BadDefault::default()) { + Ok(v) => v, + Err(()) => return, + }; +} + +fn match_arm_rev() { + let _x = match Ok(BadDefault::default()) { + Err(()) => return, + Ok(v) => v, + }; +} + +fn loop_break() { + let _x = loop { + if false { + break return; + } else { + break BadDefault::default(); + } + }; +} + +fn loop_break_rev() { + let _x = loop { + if false { + break return; + } else { + break BadDefault::default(); + } + }; +} + +fn main() { } diff --git a/src/test/run-pass/unit-fallback.rs b/src/test/run-pass/diverging-fallback-method-chain.rs similarity index 51% rename from src/test/run-pass/unit-fallback.rs rename to src/test/run-pass/diverging-fallback-method-chain.rs index 2babc6348e107..664a329c228ae 100644 --- a/src/test/run-pass/unit-fallback.rs +++ b/src/test/run-pass/diverging-fallback-method-chain.rs @@ -8,31 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that diverging types default to () (with feature(never_type) disabled). +// Test a regression found when building compiler. The `produce()` +// error type `T` winds up getting unified with result of `x.parse()`; +// the type of the closure given to `unwrap_or_else` needs to be +// inferred to `usize`. -trait Balls: Sized { - fn smeg() -> Result; -} - -impl Balls for () { - fn smeg() -> Result<(), ()> { Ok(()) } -} - -struct Flah; +use std::num::ParseIntError; -impl Flah { - fn flah(&self) -> Result { - T::smeg() - } -} - -fn doit() -> Result<(), ()> { - // The type of _ is unconstrained here and should default to () - let _ = try!(Flah.flah()); - Ok(()) +fn produce() -> Result<&'static str, T> { + Ok("22") } fn main() { - let _ = doit(); + let x: usize = produce() + .and_then(|x| x.parse()) + .unwrap_or_else(|_| panic!()); + println!("{}", x); } - diff --git a/src/test/run-pass/diverging-fallback-option.rs b/src/test/run-pass/diverging-fallback-option.rs new file mode 100644 index 0000000000000..49f90e7c91f34 --- /dev/null +++ b/src/test/run-pass/diverging-fallback-option.rs @@ -0,0 +1,22 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] + +// Here the type of `c` is `Option`, where `?T` is unconstrained. +// Because there is data-flow from the `{ return; }` block, which +// diverges and hence has type `!`, into `c`, we will default `?T` to +// `!`, and hence this code compiles rather than failing and requiring +// a type annotation. + +fn main() { + let c = Some({ return; }); + c.unwrap(); +} From 2f526cc89773d3b14c3d909152697678bc8fa7a1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:54:23 -0400 Subject: [PATCH 386/662] we now get an extra unreachable code warning in this test --- src/test/compile-fail/never-assign-dead-code.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 57e0bca6a6d77..d8752e1c050fc 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -16,5 +16,6 @@ fn main() { let x: ! = panic!("aah"); //~ ERROR unused drop(x); //~ ERROR unreachable + //~^ ERROR unreachable } From f11b7d33bb71a78beb6a4671d53d2e89a2afc0ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 15:22:48 -0400 Subject: [PATCH 387/662] add regression test for #39808 Fixes #39808 --- src/test/run-pass/issue-39808.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs index f83e9328e5879..00c2bdc8cc99d 100644 --- a/src/test/run-pass/issue-39808.rs +++ b/src/test/run-pass/issue-39808.rs @@ -8,14 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test: even though `Ok` is dead-code, its type needs to -// be influenced by the result of `Err` or else we get a "type -// variable unconstrained" error. +#![allow(unreachable_code)] + +// Regression test for #39808. The type parameter of `Owned` was +// considered to be "unconstrained" because the type resulting from +// `format!` (`String`) was not being propagated upward, owing to the +// fact that the expression diverges. + +use std::borrow::Cow; fn main() { let _ = if false { - Ok(return) + Cow::Owned(format!("{:?}", panic!())) /* as Cow */ // uncomment to fix } else { - Err("") + Cow::Borrowed("") }; } From a60e27e25b88dd7febdb3f878a09bef08c03eb41 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 09:19:49 -0400 Subject: [PATCH 388/662] pacify the mercilous tidy --- src/librustc_typeck/check/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 21eaa0c2120d5..65e7e240cc360 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3605,8 +3605,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ctxt.may_break = true; } else { - // Otherwise, we failed to find the enclosing loop; this can only happen if the - // `break` was not inside a loop at all, which is caught by the loop-checking pass. + // Otherwise, we failed to find the enclosing loop; + // this can only happen if the `break` was not + // inside a loop at all, which is caught by the + // loop-checking pass. assert!(self.tcx.sess.err_count() > 0); } From 609bfe82fd1c1207ab59f6c08bbadf45e587bd4a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 09:41:41 -0400 Subject: [PATCH 389/662] cherry-pick over the tests I wrote for the reachability code For the most part, the current code performs similarly, although it differs in some particulars. I'll be nice to have these tests for judging future changes, as well. --- src/test/ui/reachable/README.md | 7 +++ src/test/ui/reachable/expr_add.rs | 28 ++++++++++++ src/test/ui/reachable/expr_add.stderr | 14 ++++++ src/test/ui/reachable/expr_again.rs | 20 +++++++++ src/test/ui/reachable/expr_again.stderr | 15 +++++++ src/test/ui/reachable/expr_andand.rs | 21 +++++++++ src/test/ui/reachable/expr_andand.stderr | 0 src/test/ui/reachable/expr_array.rs | 28 ++++++++++++ src/test/ui/reachable/expr_array.stderr | 20 +++++++++ src/test/ui/reachable/expr_assign.rs | 39 +++++++++++++++++ src/test/ui/reachable/expr_assign.stderr | 26 ++++++++++++ src/test/ui/reachable/expr_block.rs | 41 ++++++++++++++++++ src/test/ui/reachable/expr_block.stderr | 22 ++++++++++ src/test/ui/reachable/expr_box.rs | 18 ++++++++ src/test/ui/reachable/expr_box.stderr | 14 ++++++ src/test/ui/reachable/expr_call.rs | 31 ++++++++++++++ src/test/ui/reachable/expr_call.stderr | 20 +++++++++ src/test/ui/reachable/expr_cast.rs | 23 ++++++++++ src/test/ui/reachable/expr_cast.stderr | 14 ++++++ src/test/ui/reachable/expr_if.rs | 41 ++++++++++++++++++ src/test/ui/reachable/expr_if.stderr | 15 +++++++ src/test/ui/reachable/expr_loop.rs | 44 +++++++++++++++++++ src/test/ui/reachable/expr_loop.stderr | 31 ++++++++++++++ src/test/ui/reachable/expr_match.rs | 54 ++++++++++++++++++++++++ src/test/ui/reachable/expr_match.stderr | 30 +++++++++++++ src/test/ui/reachable/expr_method.rs | 34 +++++++++++++++ src/test/ui/reachable/expr_method.stderr | 20 +++++++++ src/test/ui/reachable/expr_oror.rs | 20 +++++++++ src/test/ui/reachable/expr_oror.stderr | 0 src/test/ui/reachable/expr_repeat.rs | 23 ++++++++++ src/test/ui/reachable/expr_repeat.stderr | 14 ++++++ src/test/ui/reachable/expr_return.rs | 24 +++++++++++ src/test/ui/reachable/expr_return.stderr | 14 ++++++ src/test/ui/reachable/expr_struct.rs | 43 +++++++++++++++++++ src/test/ui/reachable/expr_struct.stderr | 32 ++++++++++++++ src/test/ui/reachable/expr_tup.rs | 28 ++++++++++++ src/test/ui/reachable/expr_tup.stderr | 20 +++++++++ src/test/ui/reachable/expr_type.rs | 23 ++++++++++ src/test/ui/reachable/expr_type.stderr | 14 ++++++ src/test/ui/reachable/expr_unary.rs | 21 +++++++++ src/test/ui/reachable/expr_unary.stderr | 8 ++++ src/test/ui/reachable/expr_while.rs | 38 +++++++++++++++++ src/test/ui/reachable/expr_while.stderr | 31 ++++++++++++++ 43 files changed, 1023 insertions(+) create mode 100644 src/test/ui/reachable/README.md create mode 100644 src/test/ui/reachable/expr_add.rs create mode 100644 src/test/ui/reachable/expr_add.stderr create mode 100644 src/test/ui/reachable/expr_again.rs create mode 100644 src/test/ui/reachable/expr_again.stderr create mode 100644 src/test/ui/reachable/expr_andand.rs create mode 100644 src/test/ui/reachable/expr_andand.stderr create mode 100644 src/test/ui/reachable/expr_array.rs create mode 100644 src/test/ui/reachable/expr_array.stderr create mode 100644 src/test/ui/reachable/expr_assign.rs create mode 100644 src/test/ui/reachable/expr_assign.stderr create mode 100644 src/test/ui/reachable/expr_block.rs create mode 100644 src/test/ui/reachable/expr_block.stderr create mode 100644 src/test/ui/reachable/expr_box.rs create mode 100644 src/test/ui/reachable/expr_box.stderr create mode 100644 src/test/ui/reachable/expr_call.rs create mode 100644 src/test/ui/reachable/expr_call.stderr create mode 100644 src/test/ui/reachable/expr_cast.rs create mode 100644 src/test/ui/reachable/expr_cast.stderr create mode 100644 src/test/ui/reachable/expr_if.rs create mode 100644 src/test/ui/reachable/expr_if.stderr create mode 100644 src/test/ui/reachable/expr_loop.rs create mode 100644 src/test/ui/reachable/expr_loop.stderr create mode 100644 src/test/ui/reachable/expr_match.rs create mode 100644 src/test/ui/reachable/expr_match.stderr create mode 100644 src/test/ui/reachable/expr_method.rs create mode 100644 src/test/ui/reachable/expr_method.stderr create mode 100644 src/test/ui/reachable/expr_oror.rs create mode 100644 src/test/ui/reachable/expr_oror.stderr create mode 100644 src/test/ui/reachable/expr_repeat.rs create mode 100644 src/test/ui/reachable/expr_repeat.stderr create mode 100644 src/test/ui/reachable/expr_return.rs create mode 100644 src/test/ui/reachable/expr_return.stderr create mode 100644 src/test/ui/reachable/expr_struct.rs create mode 100644 src/test/ui/reachable/expr_struct.stderr create mode 100644 src/test/ui/reachable/expr_tup.rs create mode 100644 src/test/ui/reachable/expr_tup.stderr create mode 100644 src/test/ui/reachable/expr_type.rs create mode 100644 src/test/ui/reachable/expr_type.stderr create mode 100644 src/test/ui/reachable/expr_unary.rs create mode 100644 src/test/ui/reachable/expr_unary.stderr create mode 100644 src/test/ui/reachable/expr_while.rs create mode 100644 src/test/ui/reachable/expr_while.stderr diff --git a/src/test/ui/reachable/README.md b/src/test/ui/reachable/README.md new file mode 100644 index 0000000000000..8bed5fba7a2e8 --- /dev/null +++ b/src/test/ui/reachable/README.md @@ -0,0 +1,7 @@ +A variety of tests around reachability. These tests in general check +two things: + +- that we get unreachable code warnings in reasonable locations; +- that we permit coercions **into** `!` from expressions which + diverge, where an expression "diverges" if it must execute some + subexpression of type `!`, or it has type `!` itself. diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs new file mode 100644 index 0000000000000..87d017adf6819 --- /dev/null +++ b/src/test/ui/reachable/expr_add.rs @@ -0,0 +1,28 @@ +// 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. + +#![feature(never_type)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +use std::ops; + +struct Foo; + +impl ops::Add for Foo { + type Output = !; + fn add(self, rhs: !) -> ! { + unimplemented!() + } +} + +fn main() { + let x = Foo + return; +} diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr new file mode 100644 index 0000000000000..1a2cc252051bf --- /dev/null +++ b/src/test/ui/reachable/expr_add.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_add.rs:27:13 + | +27 | let x = Foo + return; + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_add.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_again.rs b/src/test/ui/reachable/expr_again.rs new file mode 100644 index 0000000000000..cdbdb8dc0dbb3 --- /dev/null +++ b/src/test/ui/reachable/expr_again.rs @@ -0,0 +1,20 @@ +// 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. + +#![feature(box_syntax)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +fn main() { + let x = loop { + continue; + println!("hi"); + }; +} diff --git a/src/test/ui/reachable/expr_again.stderr b/src/test/ui/reachable/expr_again.stderr new file mode 100644 index 0000000000000..bf4e4dc4711cb --- /dev/null +++ b/src/test/ui/reachable/expr_again.stderr @@ -0,0 +1,15 @@ +error: unreachable statement + --> $DIR/expr_again.rs:18:9 + | +18 | println!("hi"); + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_again.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_andand.rs b/src/test/ui/reachable/expr_andand.rs new file mode 100644 index 0000000000000..af404d03097b6 --- /dev/null +++ b/src/test/ui/reachable/expr_andand.rs @@ -0,0 +1,21 @@ +// 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. + +#![allow(unused_variables)] +#![allow(dead_code)] +#![deny(unreachable_code)] + +fn foo() { + // No error here. + let x = false && (return); + println!("I am not dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_andand.stderr b/src/test/ui/reachable/expr_andand.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/test/ui/reachable/expr_array.rs b/src/test/ui/reachable/expr_array.rs new file mode 100644 index 0000000000000..00e8be0772547 --- /dev/null +++ b/src/test/ui/reachable/expr_array.rs @@ -0,0 +1,28 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the `22` is unreachable: + let x: [usize; 2] = [return, 22]; +} + +fn b() { + // the `array is unreachable: + let x: [usize; 2] = [22, return]; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr new file mode 100644 index 0000000000000..f8dbdb5f8bb66 --- /dev/null +++ b/src/test/ui/reachable/expr_array.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_array.rs:20:34 + | +20 | let x: [usize; 2] = [return, 22]; + | ^^ + | +note: lint level defined here + --> $DIR/expr_array.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_array.rs:25:25 + | +25 | let x: [usize; 2] = [22, return]; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs new file mode 100644 index 0000000000000..1b9357013d270 --- /dev/null +++ b/src/test/ui/reachable/expr_assign.rs @@ -0,0 +1,39 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + // No error here. + let x; + x = return; +} + +fn bar() { + use std::ptr; + let p: *mut ! = ptr::null_mut::(); + unsafe { + // Here we consider the `return` unreachable because + // "evaluating" the `*p` has type `!`. This is somewhat + // dubious, I suppose. + *p = return; + } +} + +fn baz() { + let mut i = 0; + *{return; &mut i} = 22; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr new file mode 100644 index 0000000000000..807f6a1c1d584 --- /dev/null +++ b/src/test/ui/reachable/expr_assign.stderr @@ -0,0 +1,26 @@ +error: unreachable expression + --> $DIR/expr_assign.rs:20:5 + | +20 | x = return; + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_assign.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_assign.rs:30:14 + | +30 | *p = return; + | ^^^^^^ + +error: unreachable expression + --> $DIR/expr_assign.rs:36:15 + | +36 | *{return; &mut i} = 22; + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_block.rs b/src/test/ui/reachable/expr_block.rs new file mode 100644 index 0000000000000..093589b4dc839 --- /dev/null +++ b/src/test/ui/reachable/expr_block.rs @@ -0,0 +1,41 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + // Here the tail expression is considered unreachable: + let x = { + return; + 22 + }; +} + +fn b() { + // Here the `x` assignment is considered unreachable, not the block: + let x = { + return; + }; +} + +fn c() { + // Here the `println!` is unreachable: + let x = { + return; + println!("foo"); + 22 + }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr new file mode 100644 index 0000000000000..542ce1c3fd9cb --- /dev/null +++ b/src/test/ui/reachable/expr_block.stderr @@ -0,0 +1,22 @@ +error: unreachable expression + --> $DIR/expr_block.rs:21:9 + | +21 | 22 + | ^^ + | +note: lint level defined here + --> $DIR/expr_block.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_block.rs:36:9 + | +36 | println!("foo"); + | ^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_box.rs b/src/test/ui/reachable/expr_box.rs new file mode 100644 index 0000000000000..6509b608335af --- /dev/null +++ b/src/test/ui/reachable/expr_box.rs @@ -0,0 +1,18 @@ +// 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. + +#![feature(box_syntax)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +fn main() { + let x = box return; + println!("hi"); +} diff --git a/src/test/ui/reachable/expr_box.stderr b/src/test/ui/reachable/expr_box.stderr new file mode 100644 index 0000000000000..78ba231cef9fc --- /dev/null +++ b/src/test/ui/reachable/expr_box.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_box.rs:16:13 + | +16 | let x = box return; + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_box.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs new file mode 100644 index 0000000000000..8d9f303df7fdc --- /dev/null +++ b/src/test/ui/reachable/expr_call.rs @@ -0,0 +1,31 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo(x: !, y: usize) { } + +fn bar(x: !) { } + +fn a() { + // the `22` is unreachable: + foo(return, 22); +} + +fn b() { + // the call is unreachable: + bar(return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr new file mode 100644 index 0000000000000..5526827f59fc9 --- /dev/null +++ b/src/test/ui/reachable/expr_call.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_call.rs:23:17 + | +23 | foo(return, 22); + | ^^ + | +note: lint level defined here + --> $DIR/expr_call.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_call.rs:28:5 + | +28 | bar(return); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs new file mode 100644 index 0000000000000..926ef864ebf21 --- /dev/null +++ b/src/test/ui/reachable/expr_cast.rs @@ -0,0 +1,23 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the cast is unreachable: + let x = {return} as !; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr new file mode 100644 index 0000000000000..a22300dcc1398 --- /dev/null +++ b/src/test/ui/reachable/expr_cast.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_cast.rs:20:13 + | +20 | let x = {return} as !; + | ^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_cast.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs new file mode 100644 index 0000000000000..2a265e772f359 --- /dev/null +++ b/src/test/ui/reachable/expr_if.rs @@ -0,0 +1,41 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + if {return} { + println!("Hello, world!"); + } +} + +fn bar() { + if {true} { + return; + } + println!("I am not dead."); +} + +fn baz() { + if {true} { + return; + } else { + return; + } + // As the next action to be taken after the if arms, we should + // report the `println!` as unreachable: + println!("But I am."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr new file mode 100644 index 0000000000000..2cf17474f6e9d --- /dev/null +++ b/src/test/ui/reachable/expr_if.stderr @@ -0,0 +1,15 @@ +error: unreachable statement + --> $DIR/expr_if.rs:38:5 + | +38 | println!("But I am."); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_if.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_loop.rs b/src/test/ui/reachable/expr_loop.rs new file mode 100644 index 0000000000000..3ed4b2dcf0cf8 --- /dev/null +++ b/src/test/ui/reachable/expr_loop.rs @@ -0,0 +1,44 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + loop { return; } + println!("I am dead."); +} + +fn b() { + loop { + break; + } + println!("I am not dead."); +} + +fn c() { + loop { return; } + println!("I am dead."); +} + +fn d() { + 'outer: loop { loop { break 'outer; } } + println!("I am not dead."); +} + +fn e() { + loop { 'middle: loop { loop { break 'middle; } } } + println!("I am dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr new file mode 100644 index 0000000000000..6e98e754c54db --- /dev/null +++ b/src/test/ui/reachable/expr_loop.stderr @@ -0,0 +1,31 @@ +error: unreachable statement + --> $DIR/expr_loop.rs:19:5 + | +19 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_loop.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_loop.rs:31:5 + | +31 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_loop.rs:41:5 + | +41 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_match.rs b/src/test/ui/reachable/expr_match.rs new file mode 100644 index 0000000000000..23bdcc035b227 --- /dev/null +++ b/src/test/ui/reachable/expr_match.rs @@ -0,0 +1,54 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + // The match is considered unreachable here, because the `return` + // diverges: + match {return} { } +} + +fn b() { + match () { () => return } + println!("I am dead"); +} + +fn c() { + match () { () if false => return, () => () } + println!("I am not dead"); +} + +fn d() { + match () { () if false => return, () => return } + println!("I am dead"); +} + +fn e() { + // Here the compiler fails to figure out that the `println` is dead. + match () { () if return => (), () => return } + println!("I am dead"); +} + +fn f() { + match Some(()) { None => (), Some(()) => return } + println!("I am not dead"); +} + +fn g() { + match Some(()) { None => return, Some(()) => () } + println!("I am not dead"); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr new file mode 100644 index 0000000000000..f5857a5b345ec --- /dev/null +++ b/src/test/ui/reachable/expr_match.stderr @@ -0,0 +1,30 @@ +error: unreachable expression + --> $DIR/expr_match.rs:20:5 + | +20 | match {return} { } + | ^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_match.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_match.rs:25:5 + | +25 | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_match.rs:35:5 + | +35 | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs new file mode 100644 index 0000000000000..f1d979d7df79d --- /dev/null +++ b/src/test/ui/reachable/expr_method.rs @@ -0,0 +1,34 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +struct Foo; + +impl Foo { + fn foo(&self, x: !, y: usize) { } + fn bar(&self, x: !) { } +} + +fn a() { + // the `22` is unreachable: + Foo.foo(return, 22); +} + +fn b() { + // the call is unreachable: + Foo.bar(return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr new file mode 100644 index 0000000000000..177d4352a376d --- /dev/null +++ b/src/test/ui/reachable/expr_method.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_method.rs:26:21 + | +26 | Foo.foo(return, 22); + | ^^ + | +note: lint level defined here + --> $DIR/expr_method.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_method.rs:31:5 + | +31 | Foo.bar(return); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_oror.rs b/src/test/ui/reachable/expr_oror.rs new file mode 100644 index 0000000000000..d01304d4034b5 --- /dev/null +++ b/src/test/ui/reachable/expr_oror.rs @@ -0,0 +1,20 @@ +// 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. + +#![allow(unused_variables)] +#![allow(dead_code)] +#![deny(unreachable_code)] + +fn foo() { + let x = false || (return); + println!("I am not dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_oror.stderr b/src/test/ui/reachable/expr_oror.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/test/ui/reachable/expr_repeat.rs b/src/test/ui/reachable/expr_repeat.rs new file mode 100644 index 0000000000000..6078d6d5bde46 --- /dev/null +++ b/src/test/ui/reachable/expr_repeat.rs @@ -0,0 +1,23 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the repeat is unreachable: + let x: [usize; 2] = [return; 2]; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr new file mode 100644 index 0000000000000..19afc5dd7b5ee --- /dev/null +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_repeat.rs:20:25 + | +20 | let x: [usize; 2] = [return; 2]; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_repeat.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_return.rs b/src/test/ui/reachable/expr_return.rs new file mode 100644 index 0000000000000..c640ca0663029 --- /dev/null +++ b/src/test/ui/reachable/expr_return.rs @@ -0,0 +1,24 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // Here we issue that the "2nd-innermost" return is unreachable, + // but we stop there. + let x = {return {return {return;}}}; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr new file mode 100644 index 0000000000000..3eb70a4dd7c84 --- /dev/null +++ b/src/test/ui/reachable/expr_return.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_return.rs:21:22 + | +21 | let x = {return {return {return;}}}; + | ^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_return.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_struct.rs b/src/test/ui/reachable/expr_struct.rs new file mode 100644 index 0000000000000..09e31819279f2 --- /dev/null +++ b/src/test/ui/reachable/expr_struct.rs @@ -0,0 +1,43 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +struct Foo { + a: usize, + b: usize, +} + +fn a() { + // struct expr is unreachable: + let x = Foo { a: 22, b: 33, ..return }; +} + +fn b() { + // the `33` is unreachable: + let x = Foo { a: return, b: 33, ..return }; +} + +fn c() { + // the `..return` is unreachable: + let x = Foo { a: 22, b: return, ..return }; +} + +fn d() { + // the struct expr is unreachable: + let x = Foo { a: 22, b: return }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr new file mode 100644 index 0000000000000..4b7ac6604132c --- /dev/null +++ b/src/test/ui/reachable/expr_struct.stderr @@ -0,0 +1,32 @@ +error: unreachable expression + --> $DIR/expr_struct.rs:25:13 + | +25 | let x = Foo { a: 22, b: 33, ..return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_struct.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:30:33 + | +30 | let x = Foo { a: return, b: 33, ..return }; + | ^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:35:39 + | +35 | let x = Foo { a: 22, b: return, ..return }; + | ^^^^^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:40:13 + | +40 | let x = Foo { a: 22, b: return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/reachable/expr_tup.rs b/src/test/ui/reachable/expr_tup.rs new file mode 100644 index 0000000000000..7c75296de6c54 --- /dev/null +++ b/src/test/ui/reachable/expr_tup.rs @@ -0,0 +1,28 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the `2` is unreachable: + let x: (usize, usize) = (return, 2); +} + +fn b() { + // the tuple is unreachable: + let x: (usize, usize) = (2, return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr new file mode 100644 index 0000000000000..63f477fd0c373 --- /dev/null +++ b/src/test/ui/reachable/expr_tup.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_tup.rs:20:38 + | +20 | let x: (usize, usize) = (return, 2); + | ^ + | +note: lint level defined here + --> $DIR/expr_tup.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_tup.rs:25:29 + | +25 | let x: (usize, usize) = (2, return); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs new file mode 100644 index 0000000000000..2fa277c382e87 --- /dev/null +++ b/src/test/ui/reachable/expr_type.rs @@ -0,0 +1,23 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the cast is unreachable: + let x = {return}: !; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr new file mode 100644 index 0000000000000..6ed79974ccb77 --- /dev/null +++ b/src/test/ui/reachable/expr_type.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_type.rs:20:13 + | +20 | let x = {return}: !; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_type.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs new file mode 100644 index 0000000000000..57901fbaa7c44 --- /dev/null +++ b/src/test/ui/reachable/expr_unary.rs @@ -0,0 +1,21 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + let x: ! = ! { return; 22 }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr new file mode 100644 index 0000000000000..11172652d8445 --- /dev/null +++ b/src/test/ui/reachable/expr_unary.stderr @@ -0,0 +1,8 @@ +error: cannot apply unary operator `!` to type `!` + --> $DIR/expr_unary.rs:18:16 + | +18 | let x: ! = ! { return; 22 }; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_while.rs b/src/test/ui/reachable/expr_while.rs new file mode 100644 index 0000000000000..7dcd609fbc8f4 --- /dev/null +++ b/src/test/ui/reachable/expr_while.rs @@ -0,0 +1,38 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + while {return} { + println!("Hello, world!"); + } +} + +fn bar() { + while {true} { + return; + } + println!("I am not dead."); +} + +fn baz() { + // Here, we cite the `while` loop as dead. + while {return} { + println!("I am dead."); + } + println!("I am, too."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr new file mode 100644 index 0000000000000..066cfc86c6462 --- /dev/null +++ b/src/test/ui/reachable/expr_while.stderr @@ -0,0 +1,31 @@ +error: unreachable statement + --> $DIR/expr_while.rs:19:9 + | +19 | println!("Hello, world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_while.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_while.rs:33:9 + | +33 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_while.rs:35:5 + | +35 | println!("I am, too."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + From bad79484fb99d40f48e3b84776699526a37513e0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 15:37:57 -0400 Subject: [PATCH 390/662] avoid allocating a vector when the coercion sites are known upfront --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/autoderef.rs | 12 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/coercion.rs | 174 +++++++++++++++----- src/librustc_typeck/check/method/confirm.rs | 4 +- src/librustc_typeck/check/mod.rs | 18 +- src/librustc_typeck/lib.rs | 1 + 7 files changed, 154 insertions(+), 59 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f0d2598a0fb2a..5ca8f2c01c589 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -474,7 +474,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), }; - CoerceMany::new(coerce_first) + CoerceMany::with_coercion_sites(coerce_first, arms) }; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 1aab4853a4f64..647adbbb82f2d 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,6 +12,7 @@ use astconv::AstConv; use super::FnCtxt; +use check::coercion::AsCoercionSite; use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; @@ -148,16 +149,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) - where I: IntoIterator + pub fn finalize(self, pref: LvaluePreference, exprs: &[E]) + where E: AsCoercionSite { let fcx = self.fcx; fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); } - pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I) - -> InferOk<'tcx, ()> - where I: IntoIterator + pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) + -> InferOk<'tcx, ()> + where E: AsCoercionSite { let methods: Vec<_> = self.steps .iter() @@ -176,6 +177,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.obligations); for expr in exprs { + let expr = expr.as_coercion_site(); debug!("finalize - finalizing #{} - {:?}", expr.id, expr); for (n, method) in methods.iter().enumerate() { if let &Some(method) = method { diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 529ee107c46ce..f9bc947a97358 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) .next(); let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr)); + autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]); let output = match result { None => { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c420449cea092..eba58df781f1b 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -76,6 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use syntax::abi; use syntax::feature_gate; +use syntax::ptr::P; use std::collections::VecDeque; use std::ops::Deref; @@ -155,11 +156,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } - fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> - where E: Fn() -> I, - I: IntoIterator + fn coerce(&self, exprs: &[E], a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> + where E: AsCoercionSite { - let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); @@ -239,15 +238,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer<'a, E, I>(&self, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>, - r_b: &'tcx ty::Region, - mt_b: TypeAndMut<'tcx>) - -> CoerceResult<'tcx> - where E: Fn() -> I, - I: IntoIterator + fn coerce_borrowed_pointer(&self, + exprs: &[E], + a: Ty<'tcx>, + b: Ty<'tcx>, + r_b: &'tcx ty::Region, + mt_b: TypeAndMut<'tcx>) + -> CoerceResult<'tcx> + where E: AsCoercionSite { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -424,7 +422,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { autoref); let pref = LvaluePreference::from_mutbl(mt_b.mutbl); - obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations); + obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations); success(Adjust::DerefRef { autoderefs: autoderefs, @@ -699,7 +697,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { - let ok = coerce.coerce(&|| Some(expr), source, target)?; + let ok = coerce.coerce(&[expr], source, target)?; let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); @@ -718,15 +716,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// /// This is really an internal helper. From outside the coercion /// module, you should instantiate a `CoerceMany` instance. - fn try_find_coercion_lub<'b, E, I>(&self, - cause: &ObligationCause<'tcx>, - exprs: E, - prev_ty: Ty<'tcx>, - new: &'b hir::Expr, - new_ty: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> - where E: Fn() -> I, - I: IntoIterator + fn try_find_coercion_lub(&self, + cause: &ObligationCause<'tcx>, + exprs: &[E], + prev_ty: Ty<'tcx>, + new: &hir::Expr, + new_ty: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where E: AsCoercionSite { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); @@ -758,7 +755,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(fty); - for expr in exprs().into_iter().chain(Some(new)) { + for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { // No adjustments can produce a fn item, so this should never trip. assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); self.write_adjustment(expr.id, Adjustment { @@ -778,7 +775,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty)); match result { Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); @@ -794,7 +791,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Then try to coerce the previous expressions to the type of the new one. // This requires ensuring there are no coercions applied to *any* of the // previous expressions, other than noop reborrows (ignoring lifetimes). - for expr in exprs() { + for expr in exprs { + let expr = expr.as_coercion_site(); let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) { Some(Adjust::DerefRef { autoderefs: 1, @@ -838,7 +836,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { let mut tables = self.tables.borrow_mut(); - for expr in exprs() { + for expr in exprs { + let expr = expr.as_coercion_site(); if let Some(&mut Adjustment { kind: Adjust::NeverToAny, ref mut target @@ -897,25 +896,61 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// let final_ty = coerce.complete(fcx); /// ``` #[derive(Clone)] // (*) -pub struct CoerceMany<'gcx: 'tcx, 'tcx> { +pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> + where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, +{ expected_ty: Ty<'tcx>, final_ty: Option>, - expressions: Vec<&'gcx hir::Expr>, + expressions: Expressions<'gcx, 'exprs, E>, + pushed: usize, +} + +/// The type of a `CoerceMany` that is storing up the expressions into +/// a buffer. We use this in `check/mod.rs` for things like `break`. +pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'static, hir::Expr>; + +#[derive(Clone)] // (*) +enum Expressions<'gcx, 'exprs, E> + where E: 'exprs + AsCoercionSite, +{ + Dynamic(Vec<&'gcx hir::Expr>), + UpFront(&'exprs [E]), } // (*) this is clone because `FnCtxt` is clone, but it seems dubious -- nmatsakis -impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { +impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> + where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, +{ + /// The usual case; collect the set of expressions dynamically. + /// If the full set of coercion sites is known before hand, + /// consider `with_coercion_sites()` instead to avoid allocation. pub fn new(expected_ty: Ty<'tcx>) -> Self { + Self::make(expected_ty, Expressions::Dynamic(vec![])) + } + + /// As an optimization, you can create a `CoerceMany` with a + /// pre-existing slice of expressions. In this case, you are + /// expected to pass each element in the slice to `coerce(...)` in + /// order. This is used with arrays in particular to avoid + /// needlessly cloning the slice. + pub fn with_coercion_sites(expected_ty: Ty<'tcx>, + coercion_sites: &'exprs [E]) + -> Self { + Self::make(expected_ty, Expressions::UpFront(coercion_sites)) + } + + fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'gcx, 'exprs, E>) -> Self { CoerceMany { expected_ty, final_ty: None, - expressions: vec![], + expressions, + pushed: 0, } } pub fn is_empty(&self) -> bool { - self.expressions.is_empty() + self.pushed == 0 } /// Return the "expected type" with which this coercion was @@ -997,16 +1032,25 @@ impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { // Handle the actual type unification etc. let result = if let Some(expression) = expression { - if self.expressions.is_empty() { + if self.pushed == 0 { // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. fcx.try_coerce(expression, expression_ty, self.expected_ty) } else { - fcx.try_find_coercion_lub(cause, - || self.expressions.iter().cloned(), - self.merged_ty(), - expression, - expression_ty) + match self.expressions { + Expressions::Dynamic(ref exprs) => + fcx.try_find_coercion_lub(cause, + exprs, + self.merged_ty(), + expression, + expression_ty), + Expressions::UpFront(ref coercion_sites) => + fcx.try_find_coercion_lub(cause, + &coercion_sites[0..self.pushed], + self.merged_ty(), + expression, + expression_ty), + } } } else { // this is a hack for cases where we default to `()` because @@ -1034,7 +1078,17 @@ impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { match result { Ok(v) => { self.final_ty = Some(v); - self.expressions.extend(expression); + if let Some(e) = expression { + match self.expressions { + Expressions::Dynamic(ref mut buffer) => buffer.push(e), + Expressions::UpFront(coercion_sites) => { + // if the user gave us an array to validate, check that we got + // the next expression in the list, as expected + assert_eq!(coercion_sites[self.pushed].as_coercion_site().id, e.id); + } + } + self.pushed += 1; + } } Err(err) => { let (expected, found) = if expression.is_none() { @@ -1076,8 +1130,46 @@ impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { } else { // If we only had inputs that were of type `!` (or no // inputs at all), then the final type is `!`. - assert!(self.expressions.is_empty()); + assert_eq!(self.pushed, 0); fcx.tcx.types.never } } } + +/// Something that can be converted into an expression to which we can +/// apply a coercion. +pub trait AsCoercionSite { + fn as_coercion_site(&self) -> &hir::Expr; +} + +impl AsCoercionSite for hir::Expr { + fn as_coercion_site(&self) -> &hir::Expr { + self + } +} + +impl AsCoercionSite for P { + fn as_coercion_site(&self) -> &hir::Expr { + self + } +} + +impl<'a, T> AsCoercionSite for &'a T + where T: AsCoercionSite +{ + fn as_coercion_site(&self) -> &hir::Expr { + (**self).as_coercion_site() + } +} + +impl AsCoercionSite for ! { + fn as_coercion_site(&self) -> &hir::Expr { + unreachable!() + } +} + +impl AsCoercionSite for hir::Arm { + fn as_coercion_site(&self) -> &hir::Expr { + &self.body + } +} diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e6e4b577bd50d..73f6cd76290aa 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert_eq!(n, pick.autoderefs); autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr)); + autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -444,7 +444,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { "expr was deref-able {} times but now isn't?", autoderefs); }); - autoderef.finalize(PreferMutLvalue, Some(expr)); + autoderef.finalize(PreferMutLvalue, &[expr]); } } Some(_) | None => {} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 65e7e240cc360..4b7d9a0fd3aae 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,7 +77,7 @@ type parameter). */ pub use self::Expectation::*; -use self::coercion::CoerceMany; +use self::coercion::{CoerceMany, DynamicCoerceMany}; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; @@ -420,7 +420,7 @@ pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { // this is `null` for loops where break with a value is illegal, // such as `while`, `for`, and `while let` - coerce: Option>, + coerce: Option>, } #[derive(Clone)] @@ -450,7 +450,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_coercion: Option>>, + ret_coercion: Option>>, ps: RefCell, @@ -2245,12 +2245,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, base_expr, adj_ty, autoderefs, false, lvalue_pref, idx_ty) { - autoderef.finalize(lvalue_pref, Some(base_expr)); + autoderef.finalize(lvalue_pref, &[base_expr]); return Some(final_mt); } if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, Some(base_expr)); + autoderef.finalize(lvalue_pref, &[base_expr]); let adjusted_ty = self.tcx.mk_slice(element_ty); return self.try_index_step( MethodCall::expr(expr.id), expr, base_expr, @@ -2861,7 +2861,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // (`only_has_type`); otherwise, we just go with a // fresh type variable. let coerce_to_ty = expected.only_has_type_or_fresh_var(self, sp); - let mut coerce = CoerceMany::new(coerce_to_ty); + let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); coerce.coerce(self, &if_cause, then_expr, then_ty); @@ -2908,7 +2908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); if self.tcx.vis_is_accessible_from(field.vis, self.body_id) { - autoderef.finalize(lvalue_pref, Some(base)); + autoderef.finalize(lvalue_pref, &[base]); self.write_autoderef_adjustment(base.id, autoderefs, base_t); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3032,7 +3032,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, Some(base)); + autoderef.finalize(lvalue_pref, &[base]); self.write_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } @@ -3768,7 +3768,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = uty.unwrap_or_else( || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); - let mut coerce = CoerceMany::new(coerce_to); + let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index df1c94dc19b59..0bde9fefeba0c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -79,6 +79,7 @@ This API is completely unstable and subject to change. #![feature(conservative_impl_trait)] #![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(loop_break_value)] +#![feature(never_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] From f83706454fd00c2a3b7873b50223b68ca2cbd0d0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 11:48:44 -0400 Subject: [PATCH 391/662] coercion now depends on whether the expression diverges Before I was checking this in `demand_coerce` but that's not really the right place. The right place is to move that into the coercion routine itself. --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/cast.rs | 10 ++++-- src/librustc_typeck/check/coercion.rs | 46 ++++++++++++++++++++------- src/librustc_typeck/check/demand.rs | 16 +--------- src/librustc_typeck/check/mod.rs | 18 +++++++---- 5 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5ca8f2c01c589..e83b786b9a838 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -504,7 +504,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arm_span: arm.body.span, source: match_src }); - coercion.coerce(self, &cause, &arm.body, arm_ty); + coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get()); } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 441d427fe499e..ea0aad007dd73 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::FnCtxt; +use super::{Diverges, FnCtxt}; use lint; use hir::def_id::DefId; @@ -376,7 +376,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (None, Some(t_cast)) => { if let ty::TyFnDef(.., f) = self.expr_ty.sty { // Attempt a coercion to a fn pointer type. - let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f)); + let res = fcx.try_coerce(self.expr, + self.expr_ty, + Diverges::Maybe, // TODO + fcx.tcx.mk_fn_ptr(f)); if !res.is_ok() { return Err(CastError::NonScalar); } @@ -542,7 +545,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { - fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok() + // TODO + fcx.try_coerce(self.expr, self.expr_ty, Diverges::Maybe, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index eba58df781f1b..a737b82700e34 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,7 +60,7 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::FnCtxt; +use check::{Diverges, FnCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; @@ -156,7 +156,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } - fn coerce(&self, exprs: &[E], a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> + fn coerce(&self, + exprs: &[E], + a: Ty<'tcx>, + b: Ty<'tcx>) + -> CoerceResult<'tcx> where E: AsCoercionSite { let a = self.shallow_resolve(a); @@ -689,11 +693,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn try_coerce(&self, expr: &hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, target: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + // Special-ish case: we can coerce any type `T` into the `!` + // type, but only if the source expression diverges. + if target.is_never() && expr_diverges.always() { + debug!("permit coercion to `!` because expr diverges"); + return Ok(target); + } + let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { @@ -721,15 +733,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { exprs: &[E], prev_ty: Ty<'tcx>, new: &hir::Expr, - new_ty: Ty<'tcx>) + new_ty: Ty<'tcx>, + new_diverges: Diverges) -> RelateResult<'tcx, Ty<'tcx>> where E: AsCoercionSite { - let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + // Special-ish case: we can coerce any type `T` into the `!` + // type, but only if the source expression diverges. + if prev_ty.is_never() && new_diverges.always() { + debug!("permit coercion to `!` because expr diverges"); + return Ok(prev_ty); + } + let trace = TypeTrace::types(cause, true, prev_ty, new_ty); // Special-case that coercion alone cannot handle: @@ -982,9 +1001,10 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> fcx: &FnCtxt<'a, 'gcx, 'tcx>, cause: &ObligationCause<'tcx>, expression: &'gcx hir::Expr, - expression_ty: Ty<'tcx>) + expression_ty: Ty<'tcx>, + expression_diverges: Diverges) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges) } /// Indicates that one of the inputs is a "forced unit". This @@ -1002,7 +1022,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> self.coerce_inner(fcx, cause, None, - fcx.tcx.mk_nil()) + fcx.tcx.mk_nil(), + Diverges::Maybe) } /// The inner coercion "engine". If `expression` is `None`, this @@ -1012,7 +1033,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> fcx: &FnCtxt<'a, 'gcx, 'tcx>, cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, - mut expression_ty: Ty<'tcx>) + mut expression_ty: Ty<'tcx>, + expression_diverges: Diverges) { // Incorporate whatever type inference information we have // until now; in principle we might also want to process @@ -1035,7 +1057,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> if self.pushed == 0 { // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. - fcx.try_coerce(expression, expression_ty, self.expected_ty) + fcx.try_coerce(expression, expression_ty, expression_diverges, self.expected_ty) } else { match self.expressions { Expressions::Dynamic(ref exprs) => @@ -1043,13 +1065,15 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> exprs, self.merged_ty(), expression, - expression_ty), + expression_ty, + expression_diverges), Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub(cause, &coercion_sites[0..self.pushed], self.merged_ty(), expression, - expression_ty), + expression_ty, + expression_diverges), } } } else { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 25d689b3c2c45..e922c7447ff85 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -77,21 +77,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); - // If we are "assigning" to a `!` location, then we can permit - // any type to be assigned there, so long as we are in - // dead-code. This applies to e.g. `fn foo() -> ! { return; 22 - // }` but also `fn foo() { let x: ! = { return; 22 }; }`. - // - // You might imagine that we could just *always* bail if we - // are in dead-code, but we don't want to do that, because - // that leaves a lot of type variables unconstrained. See - // e.g. #39808 and #39984. - let in_dead_code = self.diverges.get().always(); - if expected.is_never() && in_dead_code { - return; - } - - if let Err(e) = self.try_coerce(expr, checked_ty, expected) { + if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mode = probe::Mode::MethodCall; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4b7d9a0fd3aae..539f16ec6709b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -366,7 +366,7 @@ impl UnsafetyState { /// as diverging), with some manual adjustments for control-flow /// primitives (approximating a CFG). #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -enum Diverges { +pub enum Diverges { /// Potentially unknown, some cases converge, /// others require a CFG to determine them. Maybe, @@ -2833,7 +2833,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .coerce(self, &self.misc(return_expr.span), return_expr, - return_expr_ty); + return_expr_ty, + self.diverges.get()); } @@ -2864,13 +2865,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); - coerce.coerce(self, &if_cause, then_expr, then_ty); + coerce.coerce(self, &if_cause, then_expr, then_ty, then_diverges); if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - coerce.coerce(self, &if_cause, else_expr, else_ty); + coerce.coerce(self, &if_cause, else_expr, else_ty, else_diverges); // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); @@ -3553,7 +3554,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprBreak(destination, ref expr_opt) => { if let Some(target_id) = destination.target_id.opt_id() { - let (e_ty, cause); + let (e_ty, e_diverges, cause); if let Some(ref e) = *expr_opt { // If this is a break with a value, we need to type-check // the expression. Get an expected type from the loop context. @@ -3572,11 +3573,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); + e_diverges = self.diverges.get(); cause = self.misc(e.span); } else { // Otherwise, this is a break *without* a value. That's // always legal, and is equivalent to `break ()`. e_ty = tcx.mk_nil(); + e_diverges = Diverges::Maybe; cause = self.misc(expr.span); } @@ -3587,7 +3590,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ctxt = enclosing_breakables.find_breakable(target_id); if let Some(ref mut coerce) = ctxt.coerce { if let Some(ref e) = *expr_opt { - coerce.coerce(self, &cause, e, e_ty); + coerce.coerce(self, &cause, e, e_ty, e_diverges); } else { assert!(e_ty.is_nil()); coerce.coerce_forced_unit(self, &cause); @@ -3769,10 +3772,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce_to = uty.unwrap_or_else( || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); + assert_eq!(self.diverges.get(), Diverges::Maybe); for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); - coerce.coerce(self, &cause, e, e_ty); + coerce.coerce(self, &cause, e, e_ty, self.diverges.get()); } coerce.complete(self) } else { From d448329849bb2cef355cabfdc6cb4d8b5b76b80e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 11:50:36 -0400 Subject: [PATCH 392/662] fix handling of blocks with `CoerceMany` --- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/mod.rs | 137 ++++++++++---------------- 2 files changed, 51 insertions(+), 88 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a737b82700e34..8a9db674c6ebc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -926,7 +926,7 @@ pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> /// The type of a `CoerceMany` that is storing up the expressions into /// a buffer. We use this in `check/mod.rs` for things like `break`. -pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'static, hir::Expr>; +pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P>; #[derive(Clone)] // (*) enum Expressions<'gcx, 'exprs, E> diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 539f16ec6709b..413d09117af08 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -86,6 +86,7 @@ use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace}; use rustc::infer::type_variable::{self, TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; @@ -4108,102 +4109,64 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut ty = if blk.targeted_by_break { - let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(blk.span)); - let coerce_to = expected.only_has_type(self).unwrap_or(unified); - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: false, + // In some cases, blocks have just one exit, but other blocks + // can be targeted by multiple breaks. This cannot happen in + // normal Rust syntax today, but it can happen when we desugar + // a `do catch { ... }` expression. + // + // Example 1: + // + // 'a: { if true { break 'a Err(()); } Ok(()) } + // + // Here we would wind up with two coercions, one from + // `Err(())` and the other from the tail expression + // `Ok(())`. If the tail expression is omitted, that's a + // "forced unit" -- unless the block diverges, in which + // case we can ignore the tail expression (e.g., `'a: { + // break 'a 22; }` would not force the type of the block + // to be `()`). + let tail_expr = blk.expr.as_ref(); + let coerce_to_ty = expected.coercion_target_type(self, blk.span); + let coerce = if blk.targeted_by_break { + CoerceMany::new(coerce_to_ty) + } else { + let tail_expr: &[P] = match tail_expr { + Some(e) => ref_slice(e), + None => &[], }; + CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) + }; - let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(blk.id, ctxt, || { - for s in &blk.stmts { - self.check_stmt(s); - } - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable(blk.id).coerce_to - }; - let e_ty; - let cause; - match blk.expr { - Some(ref e) => { - e_ty = self.check_expr_with_hint(e, coerce_to); - cause = self.misc(e.span); - }, - None => { - e_ty = if self.diverges.get().always() { - self.tcx.types.never - } else { - self.tcx.mk_nil() - }; - cause = self.misc(blk.span); - } - }; - - (e_ty, cause) - }); - - if let ExpectHasType(ety) = expected { - if let Some(ref e) = blk.expr { - let result = if !ctxt.may_break { - self.try_coerce(e, e_ty, ctxt.coerce_to) - } else { - self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(), - ctxt.unified, e, e_ty) - }; - match result { - Ok(ty) => ctxt.unified = ty, - Err(err) => - self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(), - } - } else if self.diverges.get().always() { - // No tail expression and the body diverges; ignore - // the expected type, and keep `!` as the type of the - // block. - } else { - self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty); - }; + let ctxt = BreakableCtxt { + coerce: Some(coerce), + may_break: false, + }; - ctxt.unified - } else { + let (ctxt, ()) = self.with_breakable_ctxt(blk.id, ctxt, || { for s in &blk.stmts { self.check_stmt(s); } - let mut ty = match blk.expr { - Some(ref e) => self.check_expr_with_expectation(e, expected), - None => if self.diverges.get().always() { - self.tcx.types.never - } else { - self.tcx.mk_nil() - }, - }; + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - if let ExpectHasType(ety) = expected { - if let Some(ref e) = blk.expr { - // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); - - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; - } else if self.diverges.get().always() { - // No tail expression and the body diverges; ignore - // the expected type, and keep `!` as the type of the - // block. - } else { - self.check_block_no_expr(blk, ty, ety); - - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; - } + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let mut ctxt = enclosing_breakables.find_breakable(blk.id); + let mut coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + coerce.coerce(self, + &self.misc(tail_expr.span), + tail_expr, + tail_expr_ty, + self.diverges.get()); // TODO + } else if !self.diverges.get().always() { + coerce.coerce_forced_unit(self, &self.misc(blk.span)); } - ty - }; + }); + + let mut ty = ctxt.coerce.unwrap().complete(self); if self.has_errors.get() || ty.references_error() { ty = self.tcx.types.err From 127a7d643d70dea605ca479c12a32f450d985b09 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 11:51:02 -0400 Subject: [PATCH 393/662] rename `only_has_type_or_fresh_var` to `coercion_target_type` --- src/librustc_typeck/check/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 413d09117af08..0a2cb94c591d7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { /// Like `only_has_type`, but instead of returning `None` if no /// hard constraint exists, creates a fresh type variable. - fn only_has_type_or_fresh_var(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { + fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { self.only_has_type(fcx) .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span))) } @@ -2862,7 +2862,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `expected` if it represents a *hard* constraint // (`only_has_type`); otherwise, we just go with a // fresh type variable. - let coerce_to_ty = expected.only_has_type_or_fresh_var(self, sp); + let coerce_to_ty = expected.coercion_target_type(self, sp); let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); @@ -3683,7 +3683,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce = match source { // you can only use break with a value from a normal `loop { }` hir::LoopSource::Loop => { - let coerce_to = expected.only_has_type_or_fresh_var(self, body.span); + let coerce_to = expected.coercion_target_type(self, body.span); Some(CoerceMany::new(coerce_to)) } From d08a6da1f05dc6f8de4201efe949f1c26704ced0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 21:21:24 -0400 Subject: [PATCH 394/662] remove `Clone` from `FnCtxt` --- src/librustc_typeck/check/coercion.rs | 4 ---- src/librustc_typeck/check/mod.rs | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8a9db674c6ebc..37d442f1d059e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -914,7 +914,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// } /// let final_ty = coerce.complete(fcx); /// ``` -#[derive(Clone)] // (*) pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, { @@ -928,7 +927,6 @@ pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> /// a buffer. We use this in `check/mod.rs` for things like `break`. pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P>; -#[derive(Clone)] // (*) enum Expressions<'gcx, 'exprs, E> where E: 'exprs + AsCoercionSite, { @@ -936,8 +934,6 @@ enum Expressions<'gcx, 'exprs, E> UpFront(&'exprs [E]), } -// (*) this is clone because `FnCtxt` is clone, but it seems dubious -- nmatsakis - impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0a2cb94c591d7..9eaa8404bded9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -415,7 +415,6 @@ impl Diverges { } } -#[derive(Clone)] pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { may_break: bool, @@ -424,7 +423,6 @@ pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { coerce: Option>, } -#[derive(Clone)] pub struct EnclosingBreakables<'gcx: 'tcx, 'tcx> { stack: Vec>, by_id: NodeMap, @@ -439,7 +437,6 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { } } -#[derive(Clone)] pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ast_ty_to_ty_cache: RefCell>>, From 8c6156e1d1f7e46c59fd21c878dccbc4526d7e0c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 22 Mar 2017 21:07:02 -0400 Subject: [PATCH 395/662] have coercion supply back the target type The `try_coerce` method coerces from a source to a target type, possibly inserting adjustments. It should guarantee that the post-adjustment type is a subtype of the target type (or else that some side-constraint has been registered which will lead to an error). However, it used to return the (possibly adjusted) source as the type of the expression rather than the target. This led to less good downstream errors. To work around this, the code around blocks -- and particular tail expressions in blocks -- had some special case manipulation. However, since that code is now using the more general `CoerceMany` construct (to account for breaks), it can no longer take advantage of that. This lead to some regressions in compile-fail tests were errors were reported at "less good" locations than before. This change modifies coercions to return the target type when successful rather the source type. This extends the behavior from blocks to all coercions. Typically this has limited effect but on a few tests yielded better errors results (and avoided regressions, of course). This change also restores the hint about removing semicolons which went missing (by giving 'force-unit' coercions a chance to add notes etc). --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 40 +++++--- src/librustc_typeck/check/mod.rs | 99 +++++++++++-------- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-2149.rs | 2 +- ...region-invariant-static-error-reporting.rs | 3 - src/test/compile-fail/regions-bounds.rs | 4 +- 7 files changed, 91 insertions(+), 61 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e83b786b9a838..4a04464244442 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if is_if_let_fallback { let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); assert!(arm_ty.is_nil()); - coercion.coerce_forced_unit(self, &cause); + coercion.coerce_forced_unit(self, &cause, &mut |_| ()); } else { let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 37d442f1d059e..a5acd0c7e5300 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -74,6 +74,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; +use errors::DiagnosticBuilder; use syntax::abi; use syntax::feature_gate; use syntax::ptr::P; @@ -718,7 +719,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.write_adjustment(expr.id, adjustment); } - Ok(adjustment.target) + + // We should now have added sufficient adjustments etc to + // ensure that the type of expression, post-adjustment, is + // a subtype of target. + Ok(target) }) } @@ -1000,7 +1005,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> expression_ty: Ty<'tcx>, expression_diverges: Diverges) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges, None) } /// Indicates that one of the inputs is a "forced unit". This @@ -1011,15 +1016,21 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> /// purposes. Note that these tend to correspond to cases where /// the `()` expression is implicit in the source, and hence we do /// not take an expression argument. + /// + /// The `augment_error` gives you a chance to extend the error + /// message, in case any results (e.g., we use this to suggest + /// removing a `;`). pub fn coerce_forced_unit<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, - cause: &ObligationCause<'tcx>) + cause: &ObligationCause<'tcx>, + augment_error: &mut FnMut(&mut DiagnosticBuilder)) { self.coerce_inner(fcx, cause, None, fcx.tcx.mk_nil(), - Diverges::Maybe) + Diverges::Maybe, + Some(augment_error)) } /// The inner coercion "engine". If `expression` is `None`, this @@ -1030,7 +1041,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, mut expression_ty: Ty<'tcx>, - expression_diverges: Diverges) + expression_diverges: Diverges, + augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>) { // Incorporate whatever type inference information we have // until now; in principle we might also want to process @@ -1126,19 +1138,25 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> (self.final_ty.unwrap_or(self.expected_ty), expression_ty) }; + let mut db; match cause.code { ObligationCauseCode::ReturnNoExpression => { - struct_span_err!(fcx.tcx.sess, cause.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(cause.span, &format!("return type is not ()")) - .emit(); + db = struct_span_err!( + fcx.tcx.sess, cause.span, E0069, + "`return;` in a function whose return type is not `()`"); + db.span_label(cause.span, &format!("return type is not ()")); } _ => { - fcx.report_mismatched_types(cause, expected, found, err) - .emit(); + db = fcx.report_mismatched_types(cause, expected, found, err); } } + if let Some(mut augment_error) = augment_error { + augment_error(&mut db); + } + + db.emit(); + self.final_ty = Some(fcx.tcx.types.err); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9eaa8404bded9..29b83523aed6b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,7 @@ use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; -use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace}; +use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{self, TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; @@ -99,6 +99,7 @@ use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; +use errors::DiagnosticBuilder; use require_c_abi_if_variadic; use session::{Session, CompileResult}; use TypeAndSubsts; @@ -2875,7 +2876,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(cond_diverges | then_diverges & else_diverges); } else { let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - coerce.coerce_forced_unit(self, &else_cause); + coerce.coerce_forced_unit(self, &else_cause, &mut |_| ()); // If the condition is false we can't diverge. self.diverges.set(cond_diverges); @@ -3591,7 +3592,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { coerce.coerce(self, &cause, e, e_ty, e_diverges); } else { assert!(e_ty.is_nil()); - coerce.coerce_forced_unit(self, &cause); + coerce.coerce_forced_unit(self, &cause, &mut |_| ()); } } else { // If `ctxt.coerce` is `None`, we can just ignore @@ -3626,7 +3627,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - coercion.coerce_forced_unit(self, &cause); + coercion.coerce_forced_unit(self, &cause, &mut |_| ()); } tcx.types.never } @@ -4158,8 +4159,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tail_expr, tail_expr_ty, self.diverges.get()); // TODO - } else if !self.diverges.get().always() { - coerce.coerce_forced_unit(self, &self.misc(blk.span)); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + if !self.diverges.get().always() { + coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| { + if let Some(expected_ty) = expected.only_has_type(self) { + self.consider_hint_about_removing_semicolon(blk, + expected_ty, + err); + } + }); + } } }); @@ -4175,43 +4191,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } - pub fn check_block_no_expr(&self, blk: &'gcx hir::Block, ty: Ty<'tcx>, ety: Ty<'tcx>) { - // We're not diverging and there's an expected type, which, - // in case it's not `()`, could result in an error higher-up. - // We have a chance to error here early and be more helpful. - let cause = self.misc(blk.span); - let trace = TypeTrace::types(&cause, false, ty, ety); - match self.sub_types(false, &cause, ty, ety) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }, - Err(err) => { - let mut err = self.report_and_explain_type_error(trace, &err); - - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let mut extra_semi = None; - if let Some(stmt) = blk.stmts.last() { - if let hir::StmtSemi(ref e, _) = stmt.node { - if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { - extra_semi = Some(stmt); - } - } - } - if let Some(last_stmt) = extra_semi { - let original_span = original_sp(last_stmt.span, blk.span); - let span_semi = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - ctxt: original_span.ctxt, - }; - err.span_help(span_semi, "consider removing this semicolon:"); - } - - err.emit(); - } + /// A common error is to add an extra semicolon: + /// + /// ``` + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + fn consider_hint_about_removing_semicolon(&self, + blk: &'gcx hir::Block, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder) { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = match blk.stmts.last() { + Some(s) => s, + None => return, + }; + let last_expr = match last_stmt.node { + hir::StmtSemi(ref e, _) => e, + _ => return, + }; + let last_expr_ty = self.expr_ty(last_expr); + if self.can_sub_types(last_expr_ty, expected_ty).is_err() { + return; } + let original_span = original_sp(last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + ctxt: original_span.ctxt, + }; + err.span_help(span_semi, "consider removing this semicolon:"); } // Instantiates the given path, which must refer to an item with the given diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index d5d597c190ea0..08b896f387bbe 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR expected function, found `!` +//~^ ERROR the type of this value must be known in this context () ; } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 9143a226a2483..256c5d8e6f72c 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -21,5 +21,5 @@ impl vec_monad for Vec { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope + //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope } diff --git a/src/test/compile-fail/region-invariant-static-error-reporting.rs b/src/test/compile-fail/region-invariant-static-error-reporting.rs index ac0167e08bdd6..d25674a74b1d3 100644 --- a/src/test/compile-fail/region-invariant-static-error-reporting.rs +++ b/src/test/compile-fail/region-invariant-static-error-reporting.rs @@ -13,9 +13,6 @@ // over time, but this test used to exhibit some pretty bogus messages // that were not remotely helpful. -// error-pattern:cannot infer -// error-pattern:cannot outlive the lifetime 'a -// error-pattern:must be valid for the static lifetime // error-pattern:cannot infer // error-pattern:cannot outlive the lifetime 'a // error-pattern:must be valid for the static lifetime diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 810a8671c536b..5ce80be98d974 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,11 +16,11 @@ struct an_enum<'a>(&'a isize); struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~^ ERROR mismatched types + return e; //~ ERROR mismatched types } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~^ ERROR mismatched types + return e; //~ ERROR mismatched types } fn main() { } From 7eeddb409364fdeecbec8611f08a6ccea134971f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:21:50 -0400 Subject: [PATCH 396/662] add test illustrating current "coerce to `!`" behavior --- src/test/compile-fail/coerce-to-bang.rs | 90 +++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/test/compile-fail/coerce-to-bang.rs diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs new file mode 100644 index 0000000000000..870665bb49ee6 --- /dev/null +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -0,0 +1,90 @@ +// 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. + +#![feature(never_type)] + +fn foo(x: usize, y: !, z: usize) { } + +fn call_foo_a() { + // FIXME(#40800) -- accepted beacuse divergence happens **before** + // the coercion to `!`, but within same expression. Not clear that + // these are the rules we want. + foo(return, 22, 44); +} + +fn call_foo_b() { + // Divergence happens in the argument itself, definitely ok. + foo(22, return, 44); +} + +fn call_foo_c() { + // This test fails because the divergence happens **after** the + // coercion to `!`: + foo(22, 44, return); //~ ERROR mismatched types +} + +fn call_foo_d() { + // This test passes because `a` has type `!`: + let a: ! = return; + let b = 22; + let c = 44; + foo(a, b, c); // ... and hence a reference to `a` is expected to diverge. +} + +fn call_foo_e() { + // This test probably could pass but we don't *know* that `a` + // has type `!` so we don't let it work. + let a = return; + let b = 22; + let c = 44; + foo(a, b, c); //~ ERROR mismatched types +} + +fn call_foo_f() { + // This fn fails because `a` has type `usize`, and hence a + // reference to is it **not** considered to diverge. + let a: usize = return; + let b = 22; + let c = 44; + foo(a, b, c); //~ ERROR mismatched types +} + +fn array_a() { + // Accepted: return is coerced to `!` just fine, and then `22` can be + // because we already diverged. + let x: [!; 2] = [return, 22]; +} + +fn array_b() { + // Error: divergence has not yet occurred. + let x: [!; 2] = [22, return]; //~ ERROR mismatched types +} + +fn tuple_a() { + // No divergence at all. + let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types +} + +fn tuple_b() { + // Divergence happens before coercion: OK + let x: (usize, !, usize) = (return, 44, 66); +} + +fn tuple_c() { + // Divergence happens before coercion: OK + let x: (usize, !, usize) = (22, return, 66); +} + +fn tuple_d() { + // Error: divergence happens too late + let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types +} + +fn main() { } From 8450add8bede7bc5119457e37bbbcc95a5e8b121 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:35:49 -0400 Subject: [PATCH 397/662] fix `X as !` behavior --- src/librustc_typeck/check/cast.rs | 8 ++++--- src/librustc_typeck/check/mod.rs | 5 +++-- src/test/compile-fail/coerce-to-bang-cast.rs | 23 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/coerce-to-bang-cast.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index ea0aad007dd73..32b363ed755f4 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -56,6 +56,7 @@ use util::common::ErrorReported; pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -115,6 +116,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, cast_ty: Ty<'tcx>, cast_span: Span, span: Span) @@ -122,6 +124,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let check = CastCheck { expr: expr, expr_ty: expr_ty, + expr_diverges: expr_diverges, cast_ty: cast_ty, cast_span: cast_span, span: span, @@ -378,7 +381,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // Attempt a coercion to a fn pointer type. let res = fcx.try_coerce(self.expr, self.expr_ty, - Diverges::Maybe, // TODO + self.expr_diverges, fcx.tcx.mk_fn_ptr(f)); if !res.is_ok() { return Err(CastError::NonScalar); @@ -545,8 +548,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { - // TODO - fcx.try_coerce(self.expr, self.expr_ty, Diverges::Maybe, self.cast_ty).is_ok() + fcx.try_coerce(self.expr, self.expr_ty, self.expr_diverges, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 29b83523aed6b..da15c8f766e37 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3736,6 +3736,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let t_cast = self.resolve_type_vars_if_possible(&t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); let t_cast = self.resolve_type_vars_if_possible(&t_cast); + let diverges = self.diverges.get(); // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { @@ -3743,7 +3744,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + match cast::CastCheck::new(self, e, t_expr, diverges, t_cast, t.span, expr.span) { Ok(cast_check) => { deferred_cast_checks.push(cast_check); t_cast @@ -4158,7 +4159,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.misc(tail_expr.span), tail_expr, tail_expr_ty, - self.diverges.get()); // TODO + self.diverges.get()); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs new file mode 100644 index 0000000000000..57d2192e6356b --- /dev/null +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -0,0 +1,23 @@ +// 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. + +#![feature(never_type)] + +fn foo(x: usize, y: !, z: usize) { } + +fn cast_a() { + let y = {return; 22} as !; +} + +fn cast_b() { + let y = 22 as !; //~ ERROR non-scalar cast +} + +fn main() { } From 1b5768df4e70e4a05e15271ee58c32cb00d7fefd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:36:01 -0400 Subject: [PATCH 398/662] document `diverges` more correctly --- src/librustc_typeck/check/mod.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index da15c8f766e37..aaa3cf0f29e74 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -454,11 +454,19 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, /// Whether the last checked node generates a divergence (e.g., - /// `return` will set this to Always). In general, this is - /// typically set to *Maybe* on the way **down** the tree, and - /// then values are propagated **up** the tree. In a block, we - /// combine the results from statements and propagate the - /// end-result up. + /// `return` will set this to Always). In general, when entering + /// an expression or other node in the tree, the initial value + /// indicates whether prior parts of the containing expression may + /// have diverged. It is then typically set to `Maybe` (and the + /// old value remembered) for processing the subparts of the + /// current expression. As each subpart is processed, they may set + /// the flag to `Always` etc. Finally, at the end, we take the + /// result and "union" it with the original value, so that when we + /// return the flag indicates if any subpart of the the parent + /// expression (up to and including this part) has diverged. So, + /// if you read it after evaluating a subexpression `X`, the value + /// you get indicates whether any subexpression that was + /// evaluating up to and including `X` diverged. /// /// We use this flag for two purposes: /// From e97fc5247a1d3e3e223febbbcda15e3439b61c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 18:47:58 -0400 Subject: [PATCH 399/662] kill the graphviz-flowgraph tests They are so annoying to update, and haven't caught any bugs afaik. --- src/test/run-make/graphviz-flowgraph/Makefile | 38 ----- .../graphviz-flowgraph/f00.dot-expected.dot | 9 - src/test/run-make/graphviz-flowgraph/f00.rs | 13 -- .../graphviz-flowgraph/f01.dot-expected.dot | 13 -- src/test/run-make/graphviz-flowgraph/f01.rs | 13 -- .../graphviz-flowgraph/f02.dot-expected.dot | 13 -- src/test/run-make/graphviz-flowgraph/f02.rs | 13 -- .../graphviz-flowgraph/f03.dot-expected.dot | 17 -- src/test/run-make/graphviz-flowgraph/f03.rs | 13 -- .../graphviz-flowgraph/f04.dot-expected.dot | 15 -- src/test/run-make/graphviz-flowgraph/f04.rs | 13 -- .../graphviz-flowgraph/f05.dot-expected.dot | 23 --- src/test/run-make/graphviz-flowgraph/f05.rs | 13 -- .../graphviz-flowgraph/f06.dot-expected.dot | 19 --- src/test/run-make/graphviz-flowgraph/f06.rs | 14 -- .../graphviz-flowgraph/f07.dot-expected.dot | 39 ----- src/test/run-make/graphviz-flowgraph/f07.rs | 17 -- .../graphviz-flowgraph/f08.dot-expected.dot | 38 ----- src/test/run-make/graphviz-flowgraph/f08.rs | 16 -- .../graphviz-flowgraph/f09.dot-expected.dot | 54 ------ src/test/run-make/graphviz-flowgraph/f09.rs | 18 -- .../graphviz-flowgraph/f10.dot-expected.dot | 36 ---- src/test/run-make/graphviz-flowgraph/f10.rs | 16 -- .../graphviz-flowgraph/f11.dot-expected.dot | 35 ---- src/test/run-make/graphviz-flowgraph/f11.rs | 18 -- .../graphviz-flowgraph/f12.dot-expected.dot | 50 ------ src/test/run-make/graphviz-flowgraph/f12.rs | 18 -- .../graphviz-flowgraph/f13.dot-expected.dot | 54 ------ src/test/run-make/graphviz-flowgraph/f13.rs | 18 -- .../graphviz-flowgraph/f14.dot-expected.dot | 36 ---- src/test/run-make/graphviz-flowgraph/f14.rs | 18 -- .../graphviz-flowgraph/f15.dot-expected.dot | 105 ------------ src/test/run-make/graphviz-flowgraph/f15.rs | 30 ---- .../graphviz-flowgraph/f16.dot-expected.dot | 111 ------------ src/test/run-make/graphviz-flowgraph/f16.rs | 31 ---- .../graphviz-flowgraph/f17.dot-expected.dot | 21 --- src/test/run-make/graphviz-flowgraph/f17.rs | 13 -- .../graphviz-flowgraph/f18.dot-expected.dot | 23 --- src/test/run-make/graphviz-flowgraph/f18.rs | 14 -- .../graphviz-flowgraph/f19.dot-expected.dot | 29 ---- src/test/run-make/graphviz-flowgraph/f19.rs | 16 -- .../graphviz-flowgraph/f20.dot-expected.dot | 29 ---- src/test/run-make/graphviz-flowgraph/f20.rs | 14 -- .../graphviz-flowgraph/f21.dot-expected.dot | 101 ----------- src/test/run-make/graphviz-flowgraph/f21.rs | 30 ---- .../graphviz-flowgraph/f22.dot-expected.dot | 107 ------------ src/test/run-make/graphviz-flowgraph/f22.rs | 31 ---- .../graphviz-flowgraph/f23.dot-expected.dot | 113 ------------ src/test/run-make/graphviz-flowgraph/f23.rs | 31 ---- .../graphviz-flowgraph/f24.dot-expected.dot | 161 ------------------ src/test/run-make/graphviz-flowgraph/f24.rs | 36 ---- .../graphviz-flowgraph/f25.dot-expected.dot | 161 ------------------ src/test/run-make/graphviz-flowgraph/f25.rs | 36 ---- 53 files changed, 1963 deletions(-) delete mode 100644 src/test/run-make/graphviz-flowgraph/Makefile delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.rs diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile deleted file mode 100644 index 5740a36359c9c..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/Makefile +++ /dev/null @@ -1,38 +0,0 @@ --include ../tools.mk - -FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \ - f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \ - f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs f23.rs \ - f24.rs f25.rs - - -# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES)) -all: $(patsubst %.rs,$(TMPDIR)/%.check,$(FILES)) - - -RUSTC_LIB=$(RUSTC) --crate-type=lib - -define FIND_LAST_BLOCK -LASTBLOCKNUM_$(1) := $(shell $(RUSTC_LIB) -Z unstable-options --pretty=expanded,identified $(1) \ - | grep block - | tail -1 - | sed -e 's@.*/\* block \([0-9]*\) \*/.*@\1@') -endef - -ifeq ($(findstring rustc,$(RUSTC)),) -$(error Must set RUSTC) -endif - -$(TMPDIR)/%.pp: %.rs - $(RUSTC_LIB) --pretty=expanded,identified $< -o $@ - -$(TMPDIR)/%.dot: %.rs - $(eval $(call FIND_LAST_BLOCK,$<)) - $(RUSTC_LIB) -Z unstable-options --unpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp - cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \ - -e 's@\[label=""\]@@' \ - -e 's@digraph [a-zA-Z0-9_]* @digraph block @' \ - > $@ - -$(TMPDIR)/%.check: %.rs $(TMPDIR)/%.dot - diff -u $(patsubst %.rs,$(TMPDIR)/%.dot,$<) $(patsubst %.rs,%.dot-expected.dot,$<) diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot deleted file mode 100644 index 8ea8370ab235d..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot +++ /dev/null @@ -1,9 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="block { }"]; - N3[label="expr { }"]; - N0 -> N2; - N2 -> N3; - N3 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f00.rs b/src/test/run-make/graphviz-flowgraph/f00.rs deleted file mode 100644 index 4e7fc7ea9b084..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f00.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn empty_0() { - -} diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot deleted file mode 100644 index 5982fbea76902..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ /dev/null @@ -1,13 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 1"]; - N3[label="stmt 1;"]; - N4[label="block { 1; }"]; - N5[label="expr { 1; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f01.rs b/src/test/run-make/graphviz-flowgraph/f01.rs deleted file mode 100644 index 231aab69e50d9..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f01.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn lit_1() { - 1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot deleted file mode 100644 index 1639785bd68c0..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ /dev/null @@ -1,13 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="local _x"]; - N3[label="stmt let _x: isize;"]; - N4[label="block { let _x: isize; }"]; - N5[label="expr { let _x: isize; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f02.rs b/src/test/run-make/graphviz-flowgraph/f02.rs deleted file mode 100644 index f7fe126619853..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f02.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn decl_x_2() { - let _x : isize; -} diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot deleted file mode 100644 index b0ae00d81675a..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ /dev/null @@ -1,17 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 3"]; - N3[label="expr 4"]; - N4[label="expr 3 + 4"]; - N5[label="stmt 3 + 4;"]; - N6[label="block { 3 + 4; }"]; - N7[label="expr { 3 + 4; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f03.rs b/src/test/run-make/graphviz-flowgraph/f03.rs deleted file mode 100644 index 2dd71b623c24d..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f03.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_add_3() { - 3 + 4; -} diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot deleted file mode 100644 index 41ace15a4c680..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ /dev/null @@ -1,15 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 4"]; - N3[label="local _x"]; - N4[label="stmt let _x = 4;"]; - N5[label="block { let _x = 4; }"]; - N6[label="expr { let _x = 4; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f04.rs b/src/test/run-make/graphviz-flowgraph/f04.rs deleted file mode 100644 index 2a0ac8ac9e570..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f04.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn pat_id_4() { - let _x = 4; -} diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot deleted file mode 100644 index 72b8ae71751c2..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 5"]; - N3[label="expr 55"]; - N4[label="expr (5, 55)"]; - N5[label="local _x"]; - N6[label="local _y"]; - N7[label="pat (_x, _y)"]; - N8[label="stmt let (_x, _y) = (5, 55);"]; - N9[label="block { let (_x, _y) = (5, 55); }"]; - N10[label="expr { let (_x, _y) = (5, 55); }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f05.rs b/src/test/run-make/graphviz-flowgraph/f05.rs deleted file mode 100644 index 616d822bed07b..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f05.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn pat_tup_5() { - let (_x, _y) = (5, 55); -} diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot deleted file mode 100644 index acba71ef625ff..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ /dev/null @@ -1,19 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 6"]; - N3[label="expr S6{val: 6,}"]; - N4[label="local _x"]; - N5[label="pat S6 { val: _x }"]; - N6[label="stmt let S6 { val: _x } = S6{val: 6,};"]; - N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; - N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f06.rs b/src/test/run-make/graphviz-flowgraph/f06.rs deleted file mode 100644 index 538ef2af89896..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f06.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -struct S6 { val: isize } -pub fn pat_struct_6() { - let S6 { val: _x } = S6{ val: 6 }; -} diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot deleted file mode 100644 index 251e2b39f14c8..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ /dev/null @@ -1,39 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 7"]; - N3[label="expr 77"]; - N4[label="expr 777"]; - N5[label="expr 7777"]; - N6[label="expr [7, 77, 777, 7777]"]; - N7[label="expr match [7, 77, 777, 7777] { [x, y, ..] => x + y, }"]; - N8[label="(dummy_node)"]; - N9[label="local x"]; - N10[label="local y"]; - N11[label="pat _"]; - N12[label="pat [x, y, ..]"]; - N13[label="expr x"]; - N14[label="expr y"]; - N15[label="expr x + y"]; - N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"]; - N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; - N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N8; - N8 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N7; - N7 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f07.rs b/src/test/run-make/graphviz-flowgraph/f07.rs deleted file mode 100644 index f36b8d0abc7e3..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f07.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(slice_patterns)] - -pub fn pat_vec_7() { - match [7, 77, 777, 7777] { - [x, y, ..] => x + y - }; -} diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot deleted file mode 100644 index e2779c9414a9e..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ /dev/null @@ -1,38 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 8"]; - N3[label="local x"]; - N4[label="stmt let x = 8;"]; - N5[label="local _y"]; - N6[label="stmt let _y;"]; - N7[label="expr x"]; - N8[label="expr 88"]; - N9[label="expr x > 88"]; - N10[label="expr 888"]; - N11[label="expr _y"]; - N12[label="expr _y = 888"]; - N13[label="stmt _y = 888;"]; - N14[label="block { _y = 888; }"]; - N15[label="expr if x > 88 { _y = 888; }"]; - N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"]; - N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N9 -> N15; - N14 -> N15; - N15 -> N16; - N16 -> N17; - N17 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f08.rs b/src/test/run-make/graphviz-flowgraph/f08.rs deleted file mode 100644 index 6ba7b03d54da5..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f08.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_if_onearm_8() { - let x = 8; let _y; - if x > 88 { - _y = 888; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot deleted file mode 100644 index 536abde91e81a..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ /dev/null @@ -1,54 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 91"]; - N3[label="local x"]; - N4[label="stmt let x = 91;"]; - N5[label="local _y"]; - N6[label="stmt let _y;"]; - N7[label="expr x"]; - N8[label="expr 92"]; - N9[label="expr x > 92"]; - N10[label="expr 93"]; - N11[label="expr _y"]; - N12[label="expr _y = 93"]; - N13[label="stmt _y = 93;"]; - N14[label="block { _y = 93; }"]; - N15[label="expr 94"]; - N16[label="expr 95"]; - N17[label="expr 94 + 95"]; - N18[label="expr _y"]; - N19[label="expr _y = 94 + 95"]; - N20[label="stmt _y = 94 + 95;"]; - N21[label="block { _y = 94 + 95; }"]; - N22[label="expr { _y = 94 + 95; }"]; - N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"]; - N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; - N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N9 -> N15; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N21 -> N22; - N14 -> N23; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f09.rs b/src/test/run-make/graphviz-flowgraph/f09.rs deleted file mode 100644 index a78ccb8a93741..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f09.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_if_twoarm_9() { - let x = 91; let _y; - if x > 92 { - _y = 93; - } else { - _y = 94+95; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot deleted file mode 100644 index 07b9c744a7171..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ /dev/null @@ -1,36 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 10"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 10;"]; - N5[label="(dummy_node)"]; - N6[label="expr while x > 0 { x -= 1; }"]; - N7[label="expr x"]; - N8[label="expr 0"]; - N9[label="expr x > 0"]; - N10[label="expr 1"]; - N11[label="expr x"]; - N12[label="expr x -= 1"]; - N13[label="stmt x -= 1;"]; - N14[label="block { x -= 1; }"]; - N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"]; - N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N6; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N5; - N6 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f10.rs b/src/test/run-make/graphviz-flowgraph/f10.rs deleted file mode 100644 index 0ca7cc5ee86bd..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f10.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_while_10() { - let mut x = 10; - while x > 0 { - x -= 1; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot deleted file mode 100644 index 70034d299ba95..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ /dev/null @@ -1,35 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 11"]; - N3[label="local mut _x"]; - N4[label="stmt let mut _x = 11;"]; - N5[label="(dummy_node)"]; - N6[label="expr loop { _x -= 1; }"]; - N7[label="expr 1"]; - N8[label="expr _x"]; - N9[label="expr _x -= 1"]; - N10[label="stmt _x -= 1;"]; - N11[label="block { _x -= 1; }"]; - N12[label="stmt loop { _x -= 1; }"]; - N13[label="expr \"unreachable\""]; - N14[label="stmt \"unreachable\";"]; - N15[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; - N16[label="expr { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N5; - N6 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f11.rs b/src/test/run-make/graphviz-flowgraph/f11.rs deleted file mode 100644 index d0f3452119e16..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f11.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_loop_11() { - let mut _x = 11; - loop { - _x -= 1; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot deleted file mode 100644 index 245afc43504c4..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ /dev/null @@ -1,50 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 12"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 12;"]; - N5[label="(dummy_node)"]; - N6[label="expr loop { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; - N7[label="expr 1"]; - N8[label="expr x"]; - N9[label="expr x -= 1"]; - N10[label="stmt x -= 1;"]; - N11[label="expr x"]; - N12[label="expr 2"]; - N13[label="expr x == 2"]; - N14[label="expr break"]; - N15[label="(dummy_node)"]; - N16[label="stmt break ;"]; - N17[label="expr \"unreachable\""]; - N18[label="stmt \"unreachable\";"]; - N19[label="block { break ; \"unreachable\"; }"]; - N20[label="expr if x == 2 { break ; \"unreachable\"; }"]; - N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; - N22[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; - N23[label="expr { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N6; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N13 -> N20; - N19 -> N20; - N20 -> N21; - N21 -> N5; - N6 -> N22; - N22 -> N23; - N23 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f12.rs b/src/test/run-make/graphviz-flowgraph/f12.rs deleted file mode 100644 index 90b146340b6f5..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f12.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_loop_12() { - let mut x = 12; - loop { - x -= 1; - if x == 2 { break; "unreachable"; } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot deleted file mode 100644 index 0f268bd0f2aeb..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ /dev/null @@ -1,54 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr E13::E13b"]; - N3[label="expr 13"]; - N4[label="expr E13::E13b(13)"]; - N5[label="local x"]; - N6[label="stmt let x = E13::E13b(13);"]; - N7[label="local _y"]; - N8[label="stmt let _y;"]; - N9[label="expr x"]; - N10[label="expr match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }"]; - N11[label="(dummy_node)"]; - N12[label="pat E13::E13a"]; - N13[label="expr 1"]; - N14[label="expr _y"]; - N15[label="expr _y = 1"]; - N16[label="(dummy_node)"]; - N17[label="local v"]; - N18[label="pat E13::E13b(v)"]; - N19[label="expr v"]; - N20[label="expr 1"]; - N21[label="expr v + 1"]; - N22[label="expr _y"]; - N23[label="expr _y = v + 1"]; - N24[label="block {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; - N25[label="expr {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N12; - N12 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N10; - N9 -> N17; - N17 -> N18; - N18 -> N16; - N16 -> N19; - N19 -> N20; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N10; - N10 -> N24; - N24 -> N25; - N25 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f13.rs b/src/test/run-make/graphviz-flowgraph/f13.rs deleted file mode 100644 index babb283c7342c..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f13.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -enum E13 { E13a, E13b(isize) } -pub fn expr_match_13() { - let x = E13::E13b(13); let _y; - match x { - E13::E13a => _y = 1, - E13::E13b(v) => _y = v + 1, - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot deleted file mode 100644 index 719a6cf2619d3..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ /dev/null @@ -1,36 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 14"]; - N3[label="local x"]; - N4[label="stmt let x = 14;"]; - N5[label="expr x"]; - N6[label="expr 1"]; - N7[label="expr x > 1"]; - N8[label="expr return"]; - N9[label="(dummy_node)"]; - N10[label="stmt return;"]; - N11[label="expr \"unreachable\""]; - N12[label="stmt \"unreachable\";"]; - N13[label="block { return; \"unreachable\"; }"]; - N14[label="expr if x > 1 { return; \"unreachable\"; }"]; - N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; - N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N1; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N7 -> N14; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f14.rs b/src/test/run-make/graphviz-flowgraph/f14.rs deleted file mode 100644 index 98ff095c8317c..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f14.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_ret_14() { - let x = 14; - if x > 1 { - return; - "unreachable"; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot deleted file mode 100644 index d8cbd8411e209..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ /dev/null @@ -1,105 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr break \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt break \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { break \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="stmt break ;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { break ; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { break ; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { break ; \"unreachable\"; }"]; - N34[label="expr 3"]; - N35[label="expr y"]; - N36[label="expr y -= 3"]; - N37[label="stmt y -= 3;"]; - N38[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l}\l"]; - N39[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"]; - N40[label="expr 4"]; - N41[label="expr y"]; - N42[label="expr y -= 4"]; - N43[label="stmt y -= 4;"]; - N44[label="expr 5"]; - N45[label="expr x"]; - N46[label="expr x -= 5"]; - N47[label="stmt x -= 5;"]; - N48[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; - N49[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; - N50[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N9; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N11; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N10; - N11 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N48 -> N8; - N9 -> N49; - N49 -> N50; - N50 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs deleted file mode 100644 index 056458e5558de..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f15.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_break_label_15() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - break 'outer; - "unreachable"; - } - if y >= 2 { - break; - "unreachable"; - } - y -= 3; - } - y -= 4; - x -= 5; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot deleted file mode 100644 index b11881247fb6a..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ /dev/null @@ -1,111 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 16"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 16;"]; - N5[label="expr 16"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 16;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr continue \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt continue \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { continue \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 1"]; - N25[label="expr y >= 1"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="stmt break ;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { break ; \"unreachable\"; }"]; - N32[label="expr if y >= 1 { break ; \"unreachable\"; }"]; - N33[label="stmt if y >= 1 { break ; \"unreachable\"; }"]; - N34[label="expr 1"]; - N35[label="expr y"]; - N36[label="expr y -= 1"]; - N37[label="stmt y -= 1;"]; - N38[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l}\l"]; - N39[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"]; - N40[label="expr 1"]; - N41[label="expr y"]; - N42[label="expr y -= 1"]; - N43[label="stmt y -= 1;"]; - N44[label="expr 1"]; - N45[label="expr x"]; - N46[label="expr x -= 1"]; - N47[label="stmt x -= 1;"]; - N48[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l}\l"]; - N49[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; - N50[label="expr \"unreachable\""]; - N51[label="stmt \"unreachable\";"]; - N52[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; - N53[label="expr {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N8; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N11; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N10; - N11 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N48 -> N8; - N9 -> N49; - N49 -> N50; - N50 -> N51; - N51 -> N52; - N52 -> N53; - N53 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs deleted file mode 100644 index e225b0080e59a..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f16.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_continue_label_16() { - let mut x = 16; - let mut y = 16; - 'outer: loop { - 'inner: loop { - if x == 1 { - continue 'outer; - "unreachable"; - } - if y >= 1 { - break; - "unreachable"; - } - y -= 1; - } - y -= 1; - x -= 1; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot deleted file mode 100644 index 705eece77558d..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ /dev/null @@ -1,21 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 1"]; - N3[label="expr 7"]; - N4[label="expr 17"]; - N5[label="expr [1, 7, 17]"]; - N6[label="local _v"]; - N7[label="stmt let _v = [1, 7, 17];"]; - N8[label="block { let _v = [1, 7, 17]; }"]; - N9[label="expr { let _v = [1, 7, 17]; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f17.rs b/src/test/run-make/graphviz-flowgraph/f17.rs deleted file mode 100644 index 23f5bb8a1eb17..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f17.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_vec_17() { - let _v = [1, 7, 17]; -} diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot deleted file mode 100644 index b0491fe6e27fd..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="stmt fn inner(x: isize) -> isize { x + x }"]; - N3[label="expr inner"]; - N4[label="expr inner"]; - N5[label="expr 18"]; - N6[label="expr inner(18)"]; - N7[label="expr inner(inner(18))"]; - N8[label="stmt inner(inner(18));"]; - N9[label="block {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"]; - N10[label="expr {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f18.rs b/src/test/run-make/graphviz-flowgraph/f18.rs deleted file mode 100644 index cbf8aa5db4391..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f18.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_call_18() { - fn inner(x:isize) -> isize { x + x } - inner(inner(18)); -} diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot deleted file mode 100644 index 223978c3d7634..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="stmt struct S19 {\l x: isize,\l}\l"]; - N3[label="stmt impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"]; - N4[label="expr 19"]; - N5[label="expr S19{x: 19,}"]; - N6[label="local s"]; - N7[label="stmt let s = S19{x: 19,};"]; - N8[label="expr s"]; - N9[label="expr s.inner()"]; - N10[label="expr s.inner().inner()"]; - N11[label="stmt s.inner().inner();"]; - N12[label="block {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; - N13[label="expr {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f19.rs b/src/test/run-make/graphviz-flowgraph/f19.rs deleted file mode 100644 index 78c15dd64adc4..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f19.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_method_call_19() { - struct S19 { x: isize } - impl S19 { fn inner(self) -> S19 { S19 { x: self.x + self.x } } } - let s = S19 { x: 19 }; - s.inner().inner(); -} diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot deleted file mode 100644 index 120eab4dac909..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 2"]; - N3[label="expr 0"]; - N4[label="expr 20"]; - N5[label="expr [2, 0, 20]"]; - N6[label="local v"]; - N7[label="stmt let v = [2, 0, 20];"]; - N8[label="expr v"]; - N9[label="expr 20"]; - N10[label="expr v[20]"]; - N11[label="stmt v[20];"]; - N12[label="block { let v = [2, 0, 20]; v[20]; }"]; - N13[label="expr { let v = [2, 0, 20]; v[20]; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f20.rs b/src/test/run-make/graphviz-flowgraph/f20.rs deleted file mode 100644 index d7349932355b1..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f20.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn expr_index_20() { - let v = [2, 0, 20]; - v[20]; -} diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot deleted file mode 100644 index 370dcdd8554da..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ /dev/null @@ -1,101 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr break \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt break \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { break \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr return"]; - N27[label="(dummy_node)"]; - N28[label="stmt return;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { return; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { return; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { return; \"unreachable\"; }"]; - N34[label="expr 3"]; - N35[label="expr y"]; - N36[label="expr y -= 3"]; - N37[label="stmt y -= 3;"]; - N38[label="expr 5"]; - N39[label="expr x"]; - N40[label="expr x -= 5"]; - N41[label="stmt x -= 5;"]; - N42[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l}\l"]; - N43[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; - N44[label="expr \"unreachable\""]; - N45[label="stmt \"unreachable\";"]; - N46[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; - N47[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; - N48[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N9; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N1; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N10; - N11 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N8; - N9 -> N47; - N47 -> N48; - N48 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f21.rs b/src/test/run-make/graphviz-flowgraph/f21.rs deleted file mode 100644 index 70083ed8312cb..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f21.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_break_label_21() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - break 'outer; - "unreachable"; - } - if y >= 2 { - return; - "unreachable"; - } - y -= 3; - x -= 5; - } - "unreachable"; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot deleted file mode 100644 index 9d3bc22831a13..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ /dev/null @@ -1,107 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr continue \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt continue \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { continue \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr return"]; - N27[label="(dummy_node)"]; - N28[label="stmt return;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { return; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { return; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { return; \"unreachable\"; }"]; - N34[label="expr 1"]; - N35[label="expr x"]; - N36[label="expr x -= 1"]; - N37[label="stmt x -= 1;"]; - N38[label="expr 3"]; - N39[label="expr y"]; - N40[label="expr y -= 3"]; - N41[label="stmt y -= 3;"]; - N42[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l}\l"]; - N43[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; - N44[label="expr \"unreachable\""]; - N45[label="stmt \"unreachable\";"]; - N46[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l}\l"]; - N47[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; - N48[label="expr \"unreachable\""]; - N49[label="stmt \"unreachable\";"]; - N50[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; - N51[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N8; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N1; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N10; - N11 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N8; - N9 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N51; - N51 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f22.rs b/src/test/run-make/graphviz-flowgraph/f22.rs deleted file mode 100644 index b35aac9ec422e..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f22.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_break_label_21() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - continue 'outer; - "unreachable"; - } - if y >= 2 { - return; - "unreachable"; - } - x -= 1; - y -= 3; - } - "unreachable"; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot deleted file mode 100644 index c8bfcd6510b30..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ /dev/null @@ -1,113 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 23"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 23;"]; - N5[label="expr 23"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 23;"]; - N8[label="expr 23"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 23;"]; - N11[label="(dummy_node)"]; - N12[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x > 0"]; - N16[label="expr 1"]; - N17[label="expr x"]; - N18[label="expr x -= 1"]; - N19[label="stmt x -= 1;"]; - N20[label="(dummy_node)"]; - N21[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N22[label="expr y"]; - N23[label="expr 0"]; - N24[label="expr y > 0"]; - N25[label="expr 1"]; - N26[label="expr y"]; - N27[label="expr y -= 1"]; - N28[label="stmt y -= 1;"]; - N29[label="(dummy_node)"]; - N30[label="expr while z > 0 { z -= 1; }"]; - N31[label="expr z"]; - N32[label="expr 0"]; - N33[label="expr z > 0"]; - N34[label="expr 1"]; - N35[label="expr z"]; - N36[label="expr z -= 1"]; - N37[label="stmt z -= 1;"]; - N38[label="block { z -= 1; }"]; - N39[label="stmt while z > 0 { z -= 1; }"]; - N40[label="expr x"]; - N41[label="expr 10"]; - N42[label="expr x > 10"]; - N43[label="expr return"]; - N44[label="(dummy_node)"]; - N45[label="stmt return;"]; - N46[label="expr \"unreachable\""]; - N47[label="stmt \"unreachable\";"]; - N48[label="block { return; \"unreachable\"; }"]; - N49[label="expr if x > 10 { return; \"unreachable\"; }"]; - N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"]; - N51[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N52[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N53[label="expr {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N12; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N21; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N29; - N29 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N30; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N29; - N30 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N1; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N42 -> N49; - N48 -> N49; - N49 -> N50; - N50 -> N20; - N21 -> N51; - N51 -> N11; - N12 -> N52; - N52 -> N53; - N53 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f23.rs b/src/test/run-make/graphviz-flowgraph/f23.rs deleted file mode 100644 index 52341a3fbd408..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f23.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_while_23() { - let mut x = 23; - let mut y = 23; - let mut z = 23; - - while x > 0 { - x -= 1; - - while y > 0 { - y -= 1; - - while z > 0 { z -= 1; } - - if x > 10 { - return; - "unreachable"; - } - } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot deleted file mode 100644 index e40dd014f0a4d..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ /dev/null @@ -1,161 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 24"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 24;"]; - N5[label="expr 24"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 24;"]; - N8[label="expr 24"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 24;"]; - N11[label="(dummy_node)"]; - N12[label="expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x == 0"]; - N16[label="expr break"]; - N17[label="(dummy_node)"]; - N18[label="stmt break ;"]; - N19[label="expr \"unreachable\""]; - N20[label="stmt \"unreachable\";"]; - N21[label="block { break ; \"unreachable\"; }"]; - N22[label="expr if x == 0 { break ; \"unreachable\"; }"]; - N23[label="stmt if x == 0 { break ; \"unreachable\"; }"]; - N24[label="expr 1"]; - N25[label="expr x"]; - N26[label="expr x -= 1"]; - N27[label="stmt x -= 1;"]; - N28[label="(dummy_node)"]; - N29[label="expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N30[label="expr y"]; - N31[label="expr 0"]; - N32[label="expr y == 0"]; - N33[label="expr break"]; - N34[label="(dummy_node)"]; - N35[label="stmt break ;"]; - N36[label="expr \"unreachable\""]; - N37[label="stmt \"unreachable\";"]; - N38[label="block { break ; \"unreachable\"; }"]; - N39[label="expr if y == 0 { break ; \"unreachable\"; }"]; - N40[label="stmt if y == 0 { break ; \"unreachable\"; }"]; - N41[label="expr 1"]; - N42[label="expr y"]; - N43[label="expr y -= 1"]; - N44[label="stmt y -= 1;"]; - N45[label="(dummy_node)"]; - N46[label="expr loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N47[label="expr z"]; - N48[label="expr 0"]; - N49[label="expr z == 0"]; - N50[label="expr break"]; - N51[label="(dummy_node)"]; - N52[label="stmt break ;"]; - N53[label="expr \"unreachable\""]; - N54[label="stmt \"unreachable\";"]; - N55[label="block { break ; \"unreachable\"; }"]; - N56[label="expr if z == 0 { break ; \"unreachable\"; }"]; - N57[label="stmt if z == 0 { break ; \"unreachable\"; }"]; - N58[label="expr 1"]; - N59[label="expr z"]; - N60[label="expr z -= 1"]; - N61[label="stmt z -= 1;"]; - N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N63[label="stmt loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N64[label="expr x"]; - N65[label="expr 10"]; - N66[label="expr x > 10"]; - N67[label="expr return"]; - N68[label="(dummy_node)"]; - N69[label="stmt return;"]; - N70[label="expr \"unreachable\""]; - N71[label="stmt \"unreachable\";"]; - N72[label="block { return; \"unreachable\"; }"]; - N73[label="expr if x > 10 { return; \"unreachable\"; }"]; - N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N76[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N77[label="expr {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N12; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N15 -> N22; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N30; - N30 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N29; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N32 -> N39; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N46; - N51 -> N52; - N52 -> N53; - N53 -> N54; - N54 -> N55; - N49 -> N56; - N55 -> N56; - N56 -> N57; - N57 -> N58; - N58 -> N59; - N59 -> N60; - N60 -> N61; - N61 -> N62; - N62 -> N45; - N46 -> N63; - N63 -> N64; - N64 -> N65; - N65 -> N66; - N66 -> N67; - N67 -> N1; - N68 -> N69; - N69 -> N70; - N70 -> N71; - N71 -> N72; - N66 -> N73; - N72 -> N73; - N73 -> N74; - N74 -> N28; - N29 -> N75; - N75 -> N11; - N12 -> N76; - N76 -> N77; - N77 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f24.rs b/src/test/run-make/graphviz-flowgraph/f24.rs deleted file mode 100644 index f796d660a1856..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f24.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_while_24() { - let mut x = 24; - let mut y = 24; - let mut z = 24; - - loop { - if x == 0 { break; "unreachable"; } - x -= 1; - - loop { - if y == 0 { break; "unreachable"; } - y -= 1; - - loop { - if z == 0 { break; "unreachable"; } - z -= 1; - } - - if x > 10 { - return; - "unreachable"; - } - } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot deleted file mode 100644 index 1e2df1ab5e7b7..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ /dev/null @@ -1,161 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 25"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 25;"]; - N5[label="expr 25"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 25;"]; - N8[label="expr 25"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 25;"]; - N11[label="(dummy_node)"]; - N12[label="expr \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x == 0"]; - N16[label="expr break"]; - N17[label="(dummy_node)"]; - N18[label="stmt break ;"]; - N19[label="expr \"unreachable\""]; - N20[label="stmt \"unreachable\";"]; - N21[label="block { break ; \"unreachable\"; }"]; - N22[label="expr if x == 0 { break ; \"unreachable\"; }"]; - N23[label="stmt if x == 0 { break ; \"unreachable\"; }"]; - N24[label="expr 1"]; - N25[label="expr x"]; - N26[label="expr x -= 1"]; - N27[label="stmt x -= 1;"]; - N28[label="(dummy_node)"]; - N29[label="expr \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l"]; - N30[label="expr y"]; - N31[label="expr 0"]; - N32[label="expr y == 0"]; - N33[label="expr break"]; - N34[label="(dummy_node)"]; - N35[label="stmt break ;"]; - N36[label="expr \"unreachable\""]; - N37[label="stmt \"unreachable\";"]; - N38[label="block { break ; \"unreachable\"; }"]; - N39[label="expr if y == 0 { break ; \"unreachable\"; }"]; - N40[label="stmt if y == 0 { break ; \"unreachable\"; }"]; - N41[label="expr 1"]; - N42[label="expr y"]; - N43[label="expr y -= 1"]; - N44[label="stmt y -= 1;"]; - N45[label="(dummy_node)"]; - N46[label="expr \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N47[label="expr z"]; - N48[label="expr 0"]; - N49[label="expr z == 0"]; - N50[label="expr break"]; - N51[label="(dummy_node)"]; - N52[label="stmt break ;"]; - N53[label="expr \"unreachable\""]; - N54[label="stmt \"unreachable\";"]; - N55[label="block { break ; \"unreachable\"; }"]; - N56[label="expr if z == 0 { break ; \"unreachable\"; }"]; - N57[label="stmt if z == 0 { break ; \"unreachable\"; }"]; - N58[label="expr 1"]; - N59[label="expr z"]; - N60[label="expr z -= 1"]; - N61[label="stmt z -= 1;"]; - N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N63[label="stmt \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N64[label="expr x"]; - N65[label="expr 10"]; - N66[label="expr x > 10"]; - N67[label="expr continue \'a"]; - N68[label="(dummy_node)"]; - N69[label="stmt continue \'a ;"]; - N70[label="expr \"unreachable\""]; - N71[label="stmt \"unreachable\";"]; - N72[label="block { continue \'a ; \"unreachable\"; }"]; - N73[label="expr if x > 10 { continue \'a ; \"unreachable\"; }"]; - N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; - N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; - N76[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; - N77[label="expr {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N12; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N15 -> N22; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N30; - N30 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N29; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N32 -> N39; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N46; - N51 -> N52; - N52 -> N53; - N53 -> N54; - N54 -> N55; - N49 -> N56; - N55 -> N56; - N56 -> N57; - N57 -> N58; - N58 -> N59; - N59 -> N60; - N60 -> N61; - N61 -> N62; - N62 -> N45; - N46 -> N63; - N63 -> N64; - N64 -> N65; - N65 -> N66; - N66 -> N67; - N67 -> N28; - N68 -> N69; - N69 -> N70; - N70 -> N71; - N71 -> N72; - N66 -> N73; - N72 -> N73; - N73 -> N74; - N74 -> N28; - N29 -> N75; - N75 -> N11; - N12 -> N76; - N76 -> N77; - N77 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f25.rs b/src/test/run-make/graphviz-flowgraph/f25.rs deleted file mode 100644 index 2ee2e48fd10e0..0000000000000 --- a/src/test/run-make/graphviz-flowgraph/f25.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unreachable_code)] -pub fn expr_while_25() { - let mut x = 25; - let mut y = 25; - let mut z = 25; - - 'a: loop { - if x == 0 { break; "unreachable"; } - x -= 1; - - 'a: loop { - if y == 0 { break; "unreachable"; } - y -= 1; - - 'a: loop { - if z == 0 { break; "unreachable"; } - z -= 1; - } - - if x > 10 { - continue 'a; - "unreachable"; - } - } - } -} From fb99d87c460c8f35ae8ab9e3694aa34d983dbd9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 25 Mar 2017 05:30:39 -0400 Subject: [PATCH 400/662] update UI test We no longer give suggestions; this is presumably related to the changes I made in coercion. However, those suggestions appear to be wrong anyhow! --- src/test/ui/resolve/token-error-correct-3.stderr | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e3688957502..5be23d8ca48c8 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -36,10 +36,6 @@ error[E0308]: mismatched types | = note: expected type `()` found type `std::result::Result` - = help: here are some functions which might fulfill your needs: - - .unwrap() - - .unwrap_err() - - .unwrap_or_default() error: aborting due to previous error From 744f666445348d505f42b3fb77217e31d8eb786b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 26 Mar 2017 07:02:39 -0400 Subject: [PATCH 401/662] fix error message for issue-10176.rs --- src/test/compile-fail/issue-10176.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-10176.rs b/src/test/compile-fail/issue-10176.rs index 434b795ff31f5..c968844ae21ac 100644 --- a/src/test/compile-fail/issue-10176.rs +++ b/src/test/compile-fail/issue-10176.rs @@ -12,7 +12,7 @@ fn f() -> isize { (return 1, return 2) //~^ ERROR mismatched types //~| expected type `isize` -//~| found type `(_, _)` +//~| found type `(!, !)` //~| expected isize, found tuple } From 2414222b17f45e33d68582dd5ebe0083ed27b8cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 27 Mar 2017 19:48:55 -0400 Subject: [PATCH 402/662] remove comments that were tripping up pretty printer --- src/test/run-pass/issue-39808.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs index 00c2bdc8cc99d..91c70d76eefbc 100644 --- a/src/test/run-pass/issue-39808.rs +++ b/src/test/run-pass/issue-39808.rs @@ -19,7 +19,7 @@ use std::borrow::Cow; fn main() { let _ = if false { - Cow::Owned(format!("{:?}", panic!())) /* as Cow */ // uncomment to fix + Cow::Owned(format!("{:?}", panic!())) } else { Cow::Borrowed("") }; From 8804a4a6d91309ffb33dc62a430d4749a803348a Mon Sep 17 00:00:00 2001 From: Luxko Date: Thu, 30 Mar 2017 20:36:07 +0800 Subject: [PATCH 403/662] Add missing link in unstable-book add link to specialization's tracking issue --- src/doc/unstable-book/src/specialization.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/unstable-book/src/specialization.md b/src/doc/unstable-book/src/specialization.md index 59f27343b66df..efc380df6e119 100644 --- a/src/doc/unstable-book/src/specialization.md +++ b/src/doc/unstable-book/src/specialization.md @@ -2,6 +2,8 @@ The tracking issue for this feature is: [#31844] +[#31844]: https://github.com/rust-lang/rust/issues/31844 + ------------------------ From 3fa28cc11eb5559b169f0d2fc7523f933e188e13 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 30 Mar 2017 16:08:13 +0200 Subject: [PATCH 404/662] Add a note about overflow for fetch_add/fetch_sub --- src/libcore/sync/atomic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 743e3c41170a3..cde98a670367f 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1171,6 +1171,8 @@ macro_rules! atomic_int { /// Add to the current value, returning the previous value. /// + /// This operation wraps around on overflow. + /// /// # Examples /// /// ``` @@ -1188,6 +1190,8 @@ macro_rules! atomic_int { /// Subtract from the current value, returning the previous value. /// + /// This operation wraps around on overflow. + /// /// # Examples /// /// ``` From 2946c41c05c8bfbad04a431c4a4603127630367d Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 30 Mar 2017 16:23:46 +0200 Subject: [PATCH 405/662] More consistent wording --- src/libcore/sync/atomic.rs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index cde98a670367f..12c1287b4f65c 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -296,7 +296,7 @@ impl AtomicBool { } } - /// Stores a value into the bool, returning the old value. + /// Stores a value into the bool, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -703,7 +703,7 @@ impl AtomicPtr { } } - /// Stores a value into the pointer, returning the old value. + /// Stores a value into the pointer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -1015,7 +1015,7 @@ macro_rules! atomic_int { unsafe { atomic_store(self.v.get(), val, order); } } - /// Stores a value into the atomic integer, returning the old value. + /// Stores a value into the atomic integer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. @@ -1169,7 +1169,7 @@ macro_rules! atomic_int { } } - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// /// This operation wraps around on overflow. /// @@ -1188,7 +1188,7 @@ macro_rules! atomic_int { unsafe { atomic_add(self.v.get(), val, order) } } - /// Subtract from the current value, returning the previous value. + /// Subtracts from the current value, returning the previous value. /// /// This operation wraps around on overflow. /// @@ -1207,7 +1207,12 @@ macro_rules! atomic_int { unsafe { atomic_sub(self.v.get(), val, order) } } - /// Bitwise and with the current value, returning the previous value. + /// Bitwise "and" with the current value. + /// + /// Performs a bitwise "and" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1223,7 +1228,12 @@ macro_rules! atomic_int { unsafe { atomic_and(self.v.get(), val, order) } } - /// Bitwise or with the current value, returning the previous value. + /// Bitwise "or" with the current value. + /// + /// Performs a bitwise "or" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1239,7 +1249,12 @@ macro_rules! atomic_int { unsafe { atomic_or(self.v.get(), val, order) } } - /// Bitwise xor with the current value, returning the previous value. + /// Bitwise "xor" with the current value. + /// + /// Performs a bitwise "xor" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1387,7 +1402,7 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_add). +/// Returns the previous value (like __sync_fetch_and_add). #[inline] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1400,7 +1415,7 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_sub). +/// Returns the previous value (like __sync_fetch_and_sub). #[inline] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { From f82705403f133bbff8d8ab72f34a3a3e522c7c98 Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Thu, 30 Mar 2017 16:31:16 +0200 Subject: [PATCH 406/662] adding debug in consume_body function When in debug_assertions=true mode, the function consume_body lacks some debug output, which makes it harder to follow the control flow. This commit adds this needed debug. --- src/librustc/middle/expr_use_visitor.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a44679b0b3e0e..57b96dba753ae 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -288,6 +288,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } pub fn consume_body(&mut self, body: &hir::Body) { + debug!("consume_body(body={:?})", body); + for arg in &body.arguments { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); From ea281962149cd188edf384cb120852369b669c50 Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Thu, 30 Mar 2017 17:02:51 +0200 Subject: [PATCH 407/662] removing trailing whitespaces --- src/librustc/middle/expr_use_visitor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 57b96dba753ae..dc40d0bc649d7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn consume_body(&mut self, body: &hir::Body) { debug!("consume_body(body={:?})", body); - + for arg in &body.arguments { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); From 6fda0fe891fd85f5cde89fe672d5796f15269898 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 30 Mar 2017 17:25:36 +0200 Subject: [PATCH 408/662] cmp: Implement all PartialOrd methods for Reverse When making a forwarding wrapper we must in general forward all methods, so that we use the type's own `lt` for example instead of the default. Example important case: f32's partial_cmp does several operations but its lt is a primitive. --- src/libcore/cmp.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index dc2398b22acec..74ded948b18e7 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -347,6 +347,15 @@ impl PartialOrd for Reverse { fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) } + + #[inline] + fn lt(&self, other: &Self) -> bool { other.0 < self.0 } + #[inline] + fn le(&self, other: &Self) -> bool { other.0 <= self.0 } + #[inline] + fn ge(&self, other: &Self) -> bool { other.0 >= self.0 } + #[inline] + fn gt(&self, other: &Self) -> bool { other.0 > self.0 } } #[unstable(feature = "reverse_cmp_key", issue = "40893")] From 9d4b486b845c7d04691801f1151219b41b7c327b Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:36:50 -0400 Subject: [PATCH 409/662] Modify Lines' description --- src/libcore/str/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 857eeb26af078..e995b59a14505 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1161,9 +1161,13 @@ generate_pattern_iterators! { delegate double ended; } -/// Created with the method [`lines`]. +/// An iterator over the lines of a string, as string slices. /// -/// [`lines`]: ../../std/primitive.str.html#method.lines +/// This struct is created with the [`lines()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`lines()`]: ../../std/primitive.str.html#method.lines +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Lines<'a>(Map, LinesAnyMap>); From 0f5cf54246f7a68a8fc18ee41dffc7cdf866e19c Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:40:05 -0400 Subject: [PATCH 410/662] Modify Bytes' description --- src/libcore/str/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e995b59a14505..4556d41dd0a5a 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -625,12 +625,13 @@ impl<'a> CharIndices<'a> { } } -/// External iterator for a string's bytes. -/// Use with the `std::iter` module. +/// An iterator over the bytes of a string slice. /// -/// Created with the method [`bytes`]. +/// This struct is created by the [`bytes()`] method on [`str`]. +/// See its documentation for more. /// -/// [`bytes`]: ../../std/primitive.str.html#method.bytes +/// [`bytes()`]: ../../std/primitive.str.html#method.bytes +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Bytes<'a>(Cloned>); From b03edb4a0245b04716c537ac4f2c0eee4ec5b321 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Thu, 30 Mar 2017 13:23:35 -0500 Subject: [PATCH 411/662] Improve the docs for the write and writeln macros This change reduces duplication by linking the documentation for `writeln!` to `write!`. It also restructures the `write!` documentation to read in a more logical manner. Updates #29329, #29381 --- src/libcore/macros.rs | 54 +++++++++++++------------------------------ 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 021079f85f6be..2a28d108df77d 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -337,27 +337,20 @@ macro_rules! try { /// Write formatted data into a buffer /// -/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a -/// list of arguments to format. +/// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be +/// formatted according to the specified format string and the result will be passed to the writer. +/// The writer may be any value with a `write_fmt` method; generally this comes from an +/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro +/// returns whatever the 'write_fmt' method returns; commonly a [`std::fmt::Result`], or an +/// [`io::Result`]. /// -/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] -/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of -/// these two traits. +/// See [`std::fmt`] for more information on the format string syntax. /// -/// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer. -/// -/// See [`std::fmt`][fmt] for more information on format syntax. -/// -/// `write!` returns whatever the 'write_fmt' method returns. -/// -/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] -/// -/// [fmt]: ../std/fmt/index.html -/// [fmt_write]: ../std/fmt/trait.Write.html -/// [io_write]: ../std/io/trait.Write.html -/// [fmt_result]: ../std/fmt/type.Result.html -/// [io_result]: ../std/io/type.Result.html +/// [`std::fmt`]: ../std/fmt/index.html +/// [`std::fmt::Write`]: ../std/fmt/trait.Write.html +/// [`std::io::Write`]: ../std/io/trait.Write.html +/// [`std::fmt::Result`]: ../std/fmt/type.Result.html +/// [`io::Result`]: ../std/io/type.Result.html /// /// # Examples /// @@ -396,27 +389,12 @@ macro_rules! write { /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone /// (no additional CARRIAGE RETURN (`\r`/`U+000D`). /// -/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a -/// list of arguments to format. -/// -/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] -/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of -/// these two traits. -/// -/// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer, along with the appended newline. -/// -/// See [`std::fmt`][fmt] for more information on format syntax. -/// -/// `write!` returns whatever the 'write_fmt' method returns. +/// For more information, see [`write!`]. For information on the format string syntax, see +/// [`std::fmt`]. /// -/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] +/// [`write!`]: macro.write.html +/// [`std::fmt`]: ../std/fmt/index.html /// -/// [fmt]: ../std/fmt/index.html -/// [fmt_write]: ../std/fmt/trait.Write.html -/// [io_write]: ../std/io/trait.Write.html -/// [fmt_result]: ../std/fmt/type.Result.html -/// [io_result]: ../std/io/type.Result.html /// /// # Examples /// From 41e04985867e04b2be7b7fbd90864e5d9b3a276f Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:46:41 -0400 Subject: [PATCH 412/662] Modify CharIndices' description --- src/libcore/str/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4556d41dd0a5a..4720c965c57ce 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -553,7 +553,15 @@ impl<'a> Chars<'a> { } } -/// Iterator for a string's characters and their byte offsets. +/// An iterator over the [`char`]s of a string slice, and their positions. +/// +/// [`char`]: ../../std/primitive.char.html +/// +/// This struct is created by the [`char_indices()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char_indices()`]: ../../std/primitive.str.html#method.char_indices +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CharIndices<'a> { From 17b4884d3c3d88af7f43d5fca32fd8f48d75669b Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:51:49 -0400 Subject: [PATCH 413/662] Modify Chars' description --- src/libcore/str/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4720c965c57ce..11d52e3c15bc3 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -369,11 +369,15 @@ impl fmt::Display for Utf8Error { Section: Iterators */ -/// Iterator for the char (representing *Unicode Scalar Values*) of a string. +/// An iterator over the [`char`]s of a string slice. /// -/// Created with the method [`chars`]. +/// [`char`]: ../../std/primitive.char.html +/// +/// This struct is created by the [`chars()`] method on [`str`]. +/// See its documentation for more. /// -/// [`chars`]: ../../std/primitive.str.html#method.chars +/// [`chars()`]: ../../std/primitive.str.html#method.chars +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { From 5d14ccbc96923607f6ab00810817885ee0939486 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 16:35:19 -0400 Subject: [PATCH 414/662] Modify EncodeUtf16's description --- src/libcollections/str.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 219e818f7d738..aee6861a09f40 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -133,9 +133,15 @@ impl> SliceConcatExt for [S] { } } -/// External iterator for a string's UTF-16 code units. +/// An iterator of [`u16`] over the string encoded as UTF-16. /// -/// For use with the `std::iter` module. +/// [`u16`]: ../../std/primitive.u16.html +/// +/// This struct is created by the [`encode_utf16()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`encode_utf16()`]: ../../std/primitive.str.html#method.encode_utf16 +/// [`str`]: ../../std/primitive.str.html #[derive(Clone)] #[stable(feature = "encode_utf16", since = "1.8.0")] pub struct EncodeUtf16<'a> { From a4a7166fd585802e9644ae9b4aa3e63861d11d3e Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 16:36:06 -0400 Subject: [PATCH 415/662] Modify SplitWhitespace's description --- src/libstd_unicode/u_str.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 3c02ea82d2a11..fd309e822a0e5 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -17,8 +17,13 @@ use core::char; use core::iter::{Filter, FusedIterator}; use core::str::Split; -/// An iterator over the non-whitespace substrings of a string, -/// separated by any amount of whitespace. +/// An iterator over sub-slices of the original string slice. +/// +/// This struct is created by the [`split_whitespace()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_whitespace()`]: ../../std/primitive.str.html#method.split_whitespace +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "split_whitespace", since = "1.1.0")] pub struct SplitWhitespace<'a> { inner: Filter bool>, fn(&&str) -> bool>, From c4b11d19b85f970b759f14e6dd864512d8c41f66 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 16:46:16 -0400 Subject: [PATCH 416/662] Revert SplitWhitespace's description Original headline of SplitWhitespace's description is more descriptive as to what it contains and iterates over. --- src/libstd_unicode/u_str.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index fd309e822a0e5..d3aa27b436d48 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -17,7 +17,8 @@ use core::char; use core::iter::{Filter, FusedIterator}; use core::str::Split; -/// An iterator over sub-slices of the original string slice. +/// An iterator over the non-whitespace substrings of a string, +/// separated by any amount of whitespace. /// /// This struct is created by the [`split_whitespace()`] method on [`str`]. /// See its documentation for more. From 3b396217b5b52cf87769263bf0b842c56471b54f Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 18:33:23 -0400 Subject: [PATCH 417/662] Remove parentheses in method references --- src/libcollections/str.rs | 4 ++-- src/libcore/str/mod.rs | 16 ++++++++-------- src/libstd_unicode/u_str.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index aee6861a09f40..36a1f1eb2b7b2 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -137,10 +137,10 @@ impl> SliceConcatExt for [S] { /// /// [`u16`]: ../../std/primitive.u16.html /// -/// This struct is created by the [`encode_utf16()`] method on [`str`]. +/// This struct is created by the [`encode_utf16`] method on [`str`]. /// See its documentation for more. /// -/// [`encode_utf16()`]: ../../std/primitive.str.html#method.encode_utf16 +/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 /// [`str`]: ../../std/primitive.str.html #[derive(Clone)] #[stable(feature = "encode_utf16", since = "1.8.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 11d52e3c15bc3..56f42349b2041 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -373,10 +373,10 @@ Section: Iterators /// /// [`char`]: ../../std/primitive.char.html /// -/// This struct is created by the [`chars()`] method on [`str`]. +/// This struct is created by the [`chars`] method on [`str`]. /// See its documentation for more. /// -/// [`chars()`]: ../../std/primitive.str.html#method.chars +/// [`chars`]: ../../std/primitive.str.html#method.chars /// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -561,10 +561,10 @@ impl<'a> Chars<'a> { /// /// [`char`]: ../../std/primitive.char.html /// -/// This struct is created by the [`char_indices()`] method on [`str`]. +/// This struct is created by the [`char_indices`] method on [`str`]. /// See its documentation for more. /// -/// [`char_indices()`]: ../../std/primitive.str.html#method.char_indices +/// [`char_indices`]: ../../std/primitive.str.html#method.char_indices /// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -639,10 +639,10 @@ impl<'a> CharIndices<'a> { /// An iterator over the bytes of a string slice. /// -/// This struct is created by the [`bytes()`] method on [`str`]. +/// This struct is created by the [`bytes`] method on [`str`]. /// See its documentation for more. /// -/// [`bytes()`]: ../../std/primitive.str.html#method.bytes +/// [`bytes`]: ../../std/primitive.str.html#method.bytes /// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] @@ -1176,10 +1176,10 @@ generate_pattern_iterators! { /// An iterator over the lines of a string, as string slices. /// -/// This struct is created with the [`lines()`] method on [`str`]. +/// This struct is created with the [`lines`] method on [`str`]. /// See its documentation for more. /// -/// [`lines()`]: ../../std/primitive.str.html#method.lines +/// [`lines`]: ../../std/primitive.str.html#method.lines /// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index d3aa27b436d48..770b67acd49ef 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -20,10 +20,10 @@ use core::str::Split; /// An iterator over the non-whitespace substrings of a string, /// separated by any amount of whitespace. /// -/// This struct is created by the [`split_whitespace()`] method on [`str`]. +/// This struct is created by the [`split_whitespace`] method on [`str`]. /// See its documentation for more. /// -/// [`split_whitespace()`]: ../../std/primitive.str.html#method.split_whitespace +/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace /// [`str`]: ../../std/primitive.str.html #[stable(feature = "split_whitespace", since = "1.1.0")] pub struct SplitWhitespace<'a> { From 36b15f0409fae948b3de7dee1d6b2cb995c5784d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Mar 2017 17:29:54 -0600 Subject: [PATCH 418/662] Fix multiple footnotes and improve testing --- src/librustdoc/html/markdown.rs | 54 +++++++++++-------- src/test/rustdoc/check-rule-image-footnote.rs | 13 +++-- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 6c82dab94bcb3..e8acabde4081a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,6 +27,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; +use std::collections::HashMap; use std::default::Default; use std::fmt::{self, Write}; use std::str; @@ -135,8 +136,8 @@ macro_rules! event_loop_break { struct ParserWrapper<'a> { parser: Parser<'a>, - footnotes: Vec, - current_footnote_id: u16, + // The key is the footnote reference. The value is the footnote definition and the id. + footnotes: HashMap, } impl<'a> ParserWrapper<'a> { @@ -144,18 +145,18 @@ impl<'a> ParserWrapper<'a> { ParserWrapper { parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | pulldown_cmark::OPTION_ENABLE_FOOTNOTES), - footnotes: Vec::new(), - current_footnote_id: 1, + footnotes: HashMap::new(), } } + pub fn next(&mut self) -> Option> { self.parser.next() } - pub fn get_next_footnote_id(&mut self) -> u16 { - let tmp = self.current_footnote_id; - self.current_footnote_id += 1; - tmp + pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) { + let new_id = self.footnotes.keys().count() + 1; + let key = key.to_owned(); + self.footnotes.entry(key).or_insert((String::new(), new_id as u16)) } } @@ -450,10 +451,11 @@ pub fn render(w: &mut fmt::Formatter, fn footnote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, - mut definition: String, id: &mut Option<&mut String>) { - event_loop_break!(parser, toc_builder, shorter, definition, true, id, + id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::FootnoteDefinition(_))); - buffer.push_str(&definition); + buffer.push_str(&content); } fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, @@ -507,17 +509,24 @@ pub fn render(w: &mut fmt::Formatter, } Event::Start(Tag::FootnoteDefinition(ref def)) => { let mut content = String::new(); - footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), - id); - let cur_len = parser.footnotes.len() + 1; - parser.footnotes.push(format!("
  • {}
  • ", - cur_len, content)); - } - Event::FootnoteReference(_) => { + let def = def.as_ref(); + footnote(parser, &mut content, toc_builder, shorter, id); + let entry = parser.get_entry(def); + let cur_id = (*entry).1; + (*entry).0.push_str(&format!("
  • {} 

  • ", + cur_id, + if content.ends_with("

    ") { + &content[..content.len() - 4] + } else { + &content + })); + } + Event::FootnoteReference(ref reference) => { + let entry = parser.get_entry(reference.as_ref()); buffer.push_str(&format!("{0}\ ", - parser.get_next_footnote_id())); + (*entry).1)); } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); @@ -545,7 +554,10 @@ pub fn render(w: &mut fmt::Formatter, } if !parser.footnotes.is_empty() { buffer.push_str(&format!("

      {}
    ", - parser.footnotes.join(""))); + parser.footnotes.values() + .map(|&(ref s, _)| s.as_str()) + .collect::>() + .join(""))); } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs index 629e1a64e6fd0..4d3bea20ba895 100644 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -10,11 +10,10 @@ #![crate_name = "foo"] +// ignore-tidy-linelength + // @has foo/fn.f.html -// @has - '

    hard break: after hard break


    ' -// @has - 'Rust' -// @has - '
  • ' -// @has - '1' +// @has - '

    markdown test

    this is a link.

    hard break: after hard break


    a footnote1.

    another footnote2.

    Rust


    1. Thing 

    2. Another Thing 

    ' /// markdown test /// /// this is a [link]. @@ -28,8 +27,14 @@ /// /// a footnote[^footnote]. /// +/// another footnote[^footnotebis]. +/// /// [^footnote]: Thing /// +/// +/// [^footnotebis]: Another Thing +/// +/// /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) #[deprecated(note = "Struct")] pub fn f() {} From 78c3a49044d2f93a008f5e8040a27445c8d2f58c Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Thu, 23 Mar 2017 18:03:39 -0700 Subject: [PATCH 419/662] Emit linker hints for all library kinds. --- src/librustc_trans/back/link.rs | 31 ++------ src/librustc_trans/back/linker.rs | 127 +++++++++++++++--------------- 2 files changed, 68 insertions(+), 90 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 6d17b2f0eeda3..12a1ffa276725 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -734,9 +734,10 @@ fn link_natively(sess: &Session, } { - let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); + let mut linker = trans.linker_info.to_linker(cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, outputs, trans); + cmd = linker.finalize(); } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -1021,38 +1022,18 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { } }); - let pair = sess.cstore.used_libraries().into_iter().filter(|l| { + let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| { relevant_lib(sess, l) - }).partition(|lib| { - lib.kind == NativeLibraryKind::NativeStatic }); - let (staticlibs, others): (Vec<_>, Vec<_>) = pair; - - // Some platforms take hints about whether a library is static or dynamic. - // For those that support this, we ensure we pass the option if the library - // was flagged "static" (most defaults are dynamic) to ensure that if - // libfoo.a and libfoo.so both exist that the right one is chosen. - cmd.hint_static(); let search_path = archive_search_paths(sess); - for l in staticlibs { - // Here we explicitly ask that the entire archive is included into the - // result artifact. For more details see #15460, but the gist is that - // the linker will strip away any unused objects in the archive if we - // don't otherwise explicitly reference them. This can occur for - // libraries which are just providing bindings, libraries with generic - // functions, etc. - cmd.link_whole_staticlib(&l.name.as_str(), &search_path); - } - - cmd.hint_dynamic(); - - for lib in others { + for lib in relevant_libs { match lib.kind { NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), - NativeLibraryKind::NativeStatic => bug!(), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), + &search_path) } } } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 80801e8161cd0..a178d17a7c2d3 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> LinkerInfo { } pub fn to_linker(&'a self, - cmd: &'a mut Command, + cmd: Command, sess: &'a Session) -> Box { if sess.target.target.options.is_like_msvc { Box::new(MsvcLinker { @@ -61,7 +61,8 @@ impl<'a, 'tcx> LinkerInfo { Box::new(GnuLinker { cmd: cmd, sess: sess, - info: self + info: self, + hinted_static: false, }) as Box } } @@ -93,30 +94,49 @@ pub trait Linker { fn no_default_libraries(&mut self); fn build_dylib(&mut self, out_filename: &Path); fn args(&mut self, args: &[String]); - fn hint_static(&mut self); - fn hint_dynamic(&mut self); - fn whole_archives(&mut self); - fn no_whole_archives(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); fn subsystem(&mut self, subsystem: &str); + // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). + fn finalize(&mut self) -> Command; } pub struct GnuLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, - info: &'a LinkerInfo + info: &'a LinkerInfo, + hinted_static: bool, // Keeps track of the current hinting mode. } impl<'a> GnuLinker<'a> { fn takes_hints(&self) -> bool { !self.sess.target.target.options.is_like_osx } + + // Some platforms take hints about whether a library is static or dynamic. + // For those that support this, we ensure we pass the option if the library + // was flagged "static" (most defaults are dynamic) to ensure that if + // libfoo.a and libfoo.so both exist that the right one is chosen. + fn hint_static(&mut self) { + if !self.takes_hints() { return } + if !self.hinted_static { + self.cmd.arg("-Wl,-Bstatic"); + self.hinted_static = true; + } + } + + fn hint_dynamic(&mut self) { + if !self.takes_hints() { return } + if self.hinted_static { + self.cmd.arg("-Wl,-Bdynamic"); + self.hinted_static = false; + } + } } impl<'a> Linker for GnuLinker<'a> { - fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); } - fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); } - fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } + fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } + fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); } + fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); } fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } @@ -125,14 +145,23 @@ impl<'a> Linker for GnuLinker<'a> { fn args(&mut self, args: &[String]) { self.cmd.args(args); } fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } fn link_framework(&mut self, framework: &str) { + self.hint_dynamic(); self.cmd.arg("-framework").arg(framework); } + // Here we explicitly ask that the entire archive is included into the + // result artifact. For more details see #15460, but the gist is that + // the linker will strip away any unused objects in the archive if we + // don't otherwise explicitly reference them. This can occur for + // libraries which are just providing bindings, libraries with generic + // functions, etc. fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) { + self.hint_static(); let target = &self.sess.target.target; if !target.options.is_like_osx { self.cmd.arg("-Wl,--whole-archive") @@ -148,6 +177,7 @@ impl<'a> Linker for GnuLinker<'a> { } fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); if self.sess.target.target.options.is_like_osx { let mut v = OsString::from("-Wl,-force_load,"); v.push(lib); @@ -228,26 +258,6 @@ impl<'a> Linker for GnuLinker<'a> { } } - fn whole_archives(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,--whole-archive"); - } - - fn no_whole_archives(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,--no-whole-archive"); - } - - fn hint_static(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,-Bstatic"); - } - - fn hint_dynamic(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,-Bdynamic"); - } - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // If we're compiling a dylib, then we let symbol visibility in object // files to take care of whether they're exported or not. @@ -311,10 +321,17 @@ impl<'a> Linker for GnuLinker<'a> { fn subsystem(&mut self, subsystem: &str) { self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); } + + fn finalize(&mut self) -> Command { + self.hint_dynamic(); // Reset to default before returning the composed command line. + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } pub struct MsvcLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, info: &'a LinkerInfo } @@ -416,22 +433,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/DEBUG"); } - fn whole_archives(&mut self) { - // hints not supported? - } - fn no_whole_archives(&mut self) { - // hints not supported? - } - - // On windows static libraries are of the form `foo.lib` and dynamic - // libraries are not linked against directly, but rather through their - // import libraries also called `foo.lib`. As a result there's no - // possibility for a native library to appear both dynamically and - // statically in the same folder so we don't have to worry about hints like - // we do on Unix platforms. - fn hint_static(&mut self) {} - fn hint_dynamic(&mut self) {} - // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to // export symbols from a dynamic library. When building a dynamic library, // however, we're going to want some symbols exported, so this function @@ -492,10 +493,16 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/ENTRY:mainCRTStartup"); } } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } pub struct EmLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, info: &'a LinkerInfo } @@ -591,22 +598,6 @@ impl<'a> Linker for EmLinker<'a> { bug!("building dynamic library is unsupported on Emscripten") } - fn whole_archives(&mut self) { - // noop - } - - fn no_whole_archives(&mut self) { - // noop - } - - fn hint_static(&mut self) { - // noop - } - - fn hint_dynamic(&mut self) { - // noop - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { let symbols = &self.info.exports[&crate_type]; @@ -640,6 +631,12 @@ impl<'a> Linker for EmLinker<'a> { fn subsystem(&mut self, _subsystem: &str) { // noop } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } fn exported_symbols(scx: &SharedCrateContext, From 7c2fc62a47a9e7e6c71492d5b3752ab78cf0af0d Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 11:01:45 -0700 Subject: [PATCH 420/662] libgcc_eh may depend on libpthread. Make sure we link to the static libpthread, so that compiled Rust binaries do not depend on winpthread1.dll. --- src/libunwind/build.rs | 3 ++- src/libunwind/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ed3d5212bf256..9b8099d55a024 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -35,7 +35,8 @@ fn main() { } else if target.contains("dragonfly") { println!("cargo:rustc-link-lib=gcc_pic"); } else if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=pthread"); } else if target.contains("fuchsia") { println!("cargo:rustc-link-lib=unwind"); } diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 7fa2ce650fd6c..d4d52322adab0 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -17,6 +17,7 @@ #![feature(cfg_target_vendor)] #![feature(staged_api)] #![feature(unwind_attributes)] +#![feature(static_nobundle)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] From 3b1ba01095aaf37e3f3edf251332e0682bd98c8a Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 10:58:18 -0700 Subject: [PATCH 421/662] Fix stage0->stage1 build when using "pthreads" mingw compiler. --- src/bootstrap/bootstrap.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e7f..9f9d3471640ff 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -163,12 +163,13 @@ def download_stage0(self): if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) + channel = self.stage0_rustc_channel() + if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) - channel = self.stage0_rustc_channel() filename = "rust-std-{}-{}.tar.gz".format(channel, self.build) url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() tarball = os.path.join(rustc_cache, filename) @@ -189,6 +190,14 @@ def download_stage0(self): with open(self.rustc_stamp(), 'w') as f: f.write(self.stage0_rustc_date()) + if "pc-windows-gnu" in self.build: + filename = "rust-mingw-{}-{}.tar.gz".format(channel, self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="rust-mingw", verbose=self.verbose) + if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() From 0f87203e2e6c79677388443fba76c3f6895f7674 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 10:59:27 -0700 Subject: [PATCH 422/662] Make sure that -lole32 ends up *after* LLVM libs on the linker command line. --- src/librustc_llvm/build.rs | 6 ++++++ src/librustc_llvm/ffi.rs | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 2b945e0a3afaf..7d5887e699fd7 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -259,4 +259,10 @@ fn main() { println!("cargo:rustc-link-lib={}", stdcppname); } } + + // LLVM requires symbols from this library, but apparently they're not printeds + // during llvm-config? + if target.contains("windows") { + println!("cargo:rustc-link-lib=ole32"); + } } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 26c7a9166e68e..32c9183ece999 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1662,10 +1662,3 @@ extern "C" { pub fn LLVMRustUnsetComdat(V: ValueRef); pub fn LLVMRustSetModulePIELevel(M: ModuleRef); } - - -// LLVM requires symbols from this library, but apparently they're not printed -// during llvm-config? -#[cfg(windows)] -#[link(name = "ole32")] -extern "C" {} From ad3f6e056cdae847c3784ece2ebd8b52baa130e2 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 15:10:52 -0700 Subject: [PATCH 423/662] Include libpthread into mingw package. --- src/etc/make-win-dist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py index eda5f85408574..394ff97d84533 100644 --- a/src/etc/make-win-dist.py +++ b/src/etc/make-win-dist.py @@ -51,7 +51,7 @@ def make_win_dist(rust_root, plat_root, target_triple): target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe"] - rustc_dlls = ["libstdc++-6.dll"] + rustc_dlls = ["libstdc++-6.dll", "libwinpthread-1.dll"] if target_triple.startswith("i686-"): rustc_dlls.append("libgcc_s_dw2-1.dll") else: @@ -67,6 +67,7 @@ def make_win_dist(rust_root, plat_root, target_triple): "libstdc++.a", "libiconv.a", "libmoldname.a", + "libpthread.a", # Windows import libs "libadvapi32.a", "libbcrypt.a", From 9a50874dd46313203d137847427da0036bd11fd4 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 30 Mar 2017 21:54:10 -0400 Subject: [PATCH 424/662] tweak links --- src/libstd/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ab1167e20b1db..b5a4cabafdce5 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -97,12 +97,12 @@ //! # Contributing changes to the documentation //! //! Check out the rust contribution guidelines [here](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). -//! The source for this documentation can be found on [Github](https://github.com/rust-lang/rust/tree/master/src/libstd). +//! The source for this documentation can be found on [Github](https://github.com/rust-lang). //! To contribute changes, make sure you read the guidelines first, then submit //! pull-requests for your suggested changes. //! //! Contributions are appreciated! If you see a part of the docs that can be -//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust. +//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs. //! //! # A Tour of The Rust Standard Library //! From e1b0027b51d8c8b7558513565c2baa45f1b1b984 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 20:49:06 -0600 Subject: [PATCH 425/662] Refer to a subcommand as a subcommand. For some reason 'command' and 'subcommand' were intermixed to mean the same thing. Lets just call it the one thing that it is. --- src/bootstrap/flags.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b55f3d710ca7b..ea0fc97e22a7b 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -90,12 +90,11 @@ impl Flags { opts.optflag("h", "help", "print this help message"); let usage = |n, opts: &Options| -> ! { - let command = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py {} [options] [...]", - command.unwrap_or("")); + let subcommand = args.get(0).map(|s| &**s); + let brief = format!("Usage: x.py [options] [...]"); println!("{}", opts.usage(&brief)); - match command { + match subcommand { Some("build") => { println!("\ Arguments: @@ -156,13 +155,13 @@ Arguments: _ => {} } - if let Some(command) = command { - if command == "build" || - command == "dist" || - command == "doc" || - command == "test" || - command == "bench" || - command == "clean" { + if let Some(subcommand) = subcommand { + if subcommand == "build" || + subcommand == "dist" || + subcommand == "doc" || + subcommand == "test" || + subcommand == "bench" || + subcommand == "clean" { println!("Available invocations:"); if args.iter().any(|a| a == "-v") { let flags = Flags::parse(&["build".to_string()]); @@ -170,10 +169,10 @@ Arguments: config.build = flags.build.clone(); let mut build = Build::new(flags, config); metadata::build(&mut build); - step::build_rules(&build).print_help(command); + step::build_rules(&build).print_help(subcommand); } else { println!(" ... elided, run `./x.py {} -h -v` to see", - command); + subcommand); } println!(""); @@ -189,13 +188,13 @@ Subcommands: clean Clean out build directories dist Build and/or install distribution artifacts -To learn more about a subcommand, run `./x.py -h` +To learn more about a subcommand, run `./x.py -h` "); process::exit(n); }; if args.len() == 0 { - println!("a command must be passed"); + println!("a subcommand must be passed"); usage(1, &opts); } let parse = |opts: &Options| { @@ -258,7 +257,7 @@ To learn more about a subcommand, run `./x.py -h` } "--help" => usage(0, &opts), cmd => { - println!("unknown command: {}", cmd); + println!("unknown subcommand: {}", cmd); usage(1, &opts); } }; From 8ad5c95e521f90897a6bd611956d476fcc51c042 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 20:58:07 -0600 Subject: [PATCH 426/662] When dealing with the list of all possible subcommands, deal with them in the same order to ease comparing the sections of code in order. I chose the order that appears in the help text, because that is most likely to have been ordered with specific reasoning. --- src/bootstrap/flags.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ea0fc97e22a7b..556a362a8749a 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -157,11 +157,11 @@ Arguments: if let Some(subcommand) = subcommand { if subcommand == "build" || - subcommand == "dist" || - subcommand == "doc" || subcommand == "test" || subcommand == "bench" || - subcommand == "clean" { + subcommand == "doc" || + subcommand == "clean" || + subcommand == "dist" { println!("Available invocations:"); if args.iter().any(|a| a == "-v") { let flags = Flags::parse(&["build".to_string()]); @@ -219,10 +219,6 @@ To learn more about a subcommand, run `./x.py -h` m = parse(&opts); Subcommand::Build { paths: remaining_as_path(&m) } } - "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } - } "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); m = parse(&opts); @@ -239,6 +235,10 @@ To learn more about a subcommand, run `./x.py -h` test_args: m.opt_strs("test-args"), } } + "doc" => { + m = parse(&opts); + Subcommand::Doc { paths: remaining_as_path(&m) } + } "clean" => { m = parse(&opts); if m.free.len() > 0 { From e1c1e09867e489a41170e726fe64281caaca087a Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:12:01 -0600 Subject: [PATCH 427/662] Don't print build statistics if we explicitly asked for the help message. --- src/bootstrap/bootstrap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e7f..73f3b1d1cebab 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -593,14 +593,16 @@ def main(): start_time = time() try: bootstrap() - print("Build completed successfully in %s" % format_build_time(time() - start_time)) + if ('-h' not in sys.argv) and ('--help' not in sys.argv): + print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): exit_code = e.code else: exit_code = 1 print(e) - print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) + if ('-h' not in sys.argv) and ('--help' not in sys.argv): + print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) if __name__ == '__main__': From 5a6ebdfcda149fdf3093003bceacbb2e0a1682ab Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Thu, 30 Mar 2017 23:27:09 -0700 Subject: [PATCH 428/662] Add links to std::sync::mpsc docs #29377 --- src/libstd/sync/mpsc/mod.rs | 40 +++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 71dd94161c03d..288a589e589b7 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -13,40 +13,50 @@ //! This module provides message-based communication over channels, concretely //! defined among three types: //! -//! * `Sender` -//! * `SyncSender` -//! * `Receiver` +//! * [`Sender`] +//! * [`SyncSender`] +//! * [`Receiver`] //! -//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both +//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both //! senders are clone-able (multi-producer) such that many threads can send //! simultaneously to one receiver (single-consumer). //! //! These channels come in two flavors: //! -//! 1. An asynchronous, infinitely buffered channel. The `channel()` function +//! 1. An asynchronous, infinitely buffered channel. The [`channel()`] function //! will return a `(Sender, Receiver)` tuple where all sends will be //! **asynchronous** (they never block). The channel conceptually has an //! infinite buffer. //! -//! 2. A synchronous, bounded channel. The `sync_channel()` function will return -//! a `(SyncSender, Receiver)` tuple where the storage for pending messages -//! is a pre-allocated buffer of a fixed size. All sends will be +//! 2. A synchronous, bounded channel. The [`sync_channel()`] function will +//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note -//! that a bound of 0 is allowed, causing the channel to become a -//! "rendezvous" channel where each sender atomically hands off a message to -//! a receiver. +//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" +//! channel where each sender atomically hands off a message to a receiver. +//! +//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html +//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html +//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +//! [`channel()`]: ../../../std/sync/mpsc/fn.channel.html +//! [`sync_channel()`]: ../../../std/sync/mpsc/fn.sync_channel.html //! //! ## Disconnection //! -//! The send and receive operations on channels will all return a `Result` +//! The send and receive operations on channels will all return a [`Result`] //! indicating whether the operation succeeded or not. An unsuccessful operation //! is normally indicative of the other half of a channel having "hung up" by //! being dropped in its corresponding thread. //! //! Once half of a channel has been deallocated, most operations can no longer -//! continue to make progress, so `Err` will be returned. Many applications will -//! continue to `unwrap()` the results returned from this module, instigating a -//! propagation of failure among threads if one unexpectedly dies. +//! continue to make progress, so [`Err`] will be returned. Many applications +//! will continue to [`unwrap()`] the results returned from this module, +//! instigating a propagation of failure among threads if one unexpectedly dies. +//! +//! [`Result`]: ../../../std/result/enum.Result.html +//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err +//! [`unwrap()`]: ../../../std/result/enum.Result.html#method.unwrap //! //! # Examples //! From 0e2d3d41bb42abe1c40585d2ed06aea2840e664f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 31 Mar 2017 16:59:01 +0200 Subject: [PATCH 429/662] Test sort algorithms using a random cmp function --- src/libcollectionstest/slice.rs | 16 +++++++++++++++- src/libcoretest/slice.rs | 12 ++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 00d4dbe9c0458..c3e5304fb2b35 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -383,9 +383,11 @@ fn test_reverse() { #[test] fn test_sort() { + let mut rng = thread_rng(); + for len in (2..25).chain(500..510) { for _ in 0..100 { - let mut v: Vec<_> = thread_rng().gen_iter::().take(len).collect(); + let mut v: Vec<_> = rng.gen_iter::().take(len).collect(); let mut v1 = v.clone(); v.sort(); @@ -399,6 +401,18 @@ fn test_sort() { } } + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + // Should not panic. [0i32; 0].sort(); [(); 10].sort(); diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index 89bd3be08519c..ec38345030fa5 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::cmp::Ordering::{Equal, Greater, Less}; use core::slice::heapsort; use core::result::Result::{Ok, Err}; use rand::{Rng, XorShiftRng}; @@ -268,6 +269,17 @@ fn sort_unstable() { } } + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort_unstable(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + // Should not panic. [0i32; 0].sort_unstable(); [(); 10].sort_unstable(); From d7b3f053d06799e521fa15732f409595dd46d5fc Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 31 Mar 2017 17:12:47 +0200 Subject: [PATCH 430/662] Improve some docs for VecDeque --- src/libcollections/vec_deque.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index cb92236ec736c..c37bf752e86bc 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -635,7 +635,7 @@ impl VecDeque { } } - /// Shortens a `VecDeque`, dropping excess elements from the back. + /// Shortens the `VecDeque`, dropping excess elements from the back. /// /// If `len` is greater than the `VecDeque`'s current length, this has no /// effect. @@ -941,7 +941,7 @@ impl VecDeque { a.contains(x) || b.contains(x) } - /// Provides a reference to the front element, or `None` if the sequence is + /// Provides a reference to the front element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -966,7 +966,7 @@ impl VecDeque { } /// Provides a mutable reference to the front element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -993,7 +993,7 @@ impl VecDeque { } } - /// Provides a reference to the back element, or `None` if the sequence is + /// Provides a reference to the back element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1018,7 +1018,7 @@ impl VecDeque { } /// Provides a mutable reference to the back element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -1046,7 +1046,7 @@ impl VecDeque { } } - /// Removes the first element and returns it, or `None` if the sequence is + /// Removes the first element and returns it, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1073,7 +1073,7 @@ impl VecDeque { } } - /// Inserts an element first in the sequence. + /// Prepends an element to the front of the `VecDeque`. /// /// # Examples /// @@ -1096,7 +1096,7 @@ impl VecDeque { } } - /// Appends an element to the back of a buffer + /// Appends an element to the back of the `VecDeque`. /// /// # Examples /// @@ -1117,7 +1117,7 @@ impl VecDeque { unsafe { self.buffer_write(head, value) } } - /// Removes the last element from a buffer and returns it, or `None` if + /// Removes the last element from the `VecDeque` and returns it, or `None` if /// it is empty. /// /// # Examples From eef2a9598b9a149d45d440efe0580604b5726527 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 19 Mar 2017 10:45:05 -0400 Subject: [PATCH 431/662] Sync all unstable features with Unstable Book; add tidy lint. Add a tidy lint that checks for... * Unstable Book sections with no corresponding SUMMARY.md links * unstable features that don't have Unstable Book sections * Unstable Book sections that don't have corresponding unstable features --- src/Cargo.lock | 3 + src/doc/unstable-book/src/SUMMARY.md | 4 +- src/doc/unstable-book/src/pub-restricted.md | 7 - src/doc/unstable-book/src/reverse-cmp-key.md | 7 + src/doc/unstable-book/src/rustdoc.md | 7 - .../unstable-book/src/str-checked-slicing.md | 7 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/features.rs | 150 ++++++++++-------- src/tools/tidy/src/main.rs | 4 + src/tools/tidy/src/unstable_book.rs | 138 ++++++++++++++++ 10 files changed, 243 insertions(+), 85 deletions(-) delete mode 100644 src/doc/unstable-book/src/pub-restricted.md create mode 100644 src/doc/unstable-book/src/reverse-cmp-key.md delete mode 100644 src/doc/unstable-book/src/rustdoc.md create mode 100644 src/doc/unstable-book/src/str-checked-slicing.md create mode 100644 src/tools/tidy/src/unstable_book.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index a9021dc34e207..1fa256197ce52 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -926,6 +926,9 @@ dependencies = [ [[package]] name = "tidy" version = "0.1.0" +dependencies = [ + "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "toml" diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index fe491d7f9018e..292f5a1ec816a 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -146,7 +146,6 @@ - [proc_macro](proc-macro.md) - [proc_macro_internals](proc-macro-internals.md) - [process_try_wait](process-try-wait.md) -- [pub_restricted](pub-restricted.md) - [question_mark_carrier](question-mark-carrier.md) - [quote](quote.md) - [rand](rand.md) @@ -156,11 +155,11 @@ - [relaxed_adts](relaxed-adts.md) - [repr_simd](repr-simd.md) - [retain_hash_collection](retain-hash-collection.md) +- [reverse_cmp_key](reverse-cmp-key.md) - [rt](rt.md) - [rustc_attrs](rustc-attrs.md) - [rustc_diagnostic_macros](rustc-diagnostic-macros.md) - [rustc_private](rustc-private.md) -- [rustdoc](rustdoc.md) - [rvalue_static_promotion](rvalue-static-promotion.md) - [sanitizer_runtime](sanitizer-runtime.md) - [sanitizer_runtime_lib](sanitizer-runtime-lib.md) @@ -181,6 +180,7 @@ - [step_by](step-by.md) - [step_trait](step-trait.md) - [stmt_expr_attributes](stmt-expr-attributes.md) +- [str_checked_slicing](str-checked-slicing.md) - [str_escape](str-escape.md) - [str_internals](str-internals.md) - [struct_field_attributes](struct-field-attributes.md) diff --git a/src/doc/unstable-book/src/pub-restricted.md b/src/doc/unstable-book/src/pub-restricted.md deleted file mode 100644 index 6b1e88b860301..0000000000000 --- a/src/doc/unstable-book/src/pub-restricted.md +++ /dev/null @@ -1,7 +0,0 @@ -# `pub_restricted` - -The tracking issue for this feature is: [#32409] - -[#38356]: https://github.com/rust-lang/rust/issues/32409 - ------------------------- diff --git a/src/doc/unstable-book/src/reverse-cmp-key.md b/src/doc/unstable-book/src/reverse-cmp-key.md new file mode 100644 index 0000000000000..a1a851d6ed632 --- /dev/null +++ b/src/doc/unstable-book/src/reverse-cmp-key.md @@ -0,0 +1,7 @@ +# `reverse_cmp_key` + +The tracking issue for this feature is: [#40893] + +[#40893]: https://github.com/rust-lang/rust/issues/40893 + +------------------------ diff --git a/src/doc/unstable-book/src/rustdoc.md b/src/doc/unstable-book/src/rustdoc.md deleted file mode 100644 index c7491ab034bff..0000000000000 --- a/src/doc/unstable-book/src/rustdoc.md +++ /dev/null @@ -1,7 +0,0 @@ -# `rustdoc` - -The tracking issue for this feature is: [#27812] - -[#27812]: https://github.com/rust-lang/rust/issues/27812 - ------------------------- diff --git a/src/doc/unstable-book/src/str-checked-slicing.md b/src/doc/unstable-book/src/str-checked-slicing.md new file mode 100644 index 0000000000000..d390139a6befa --- /dev/null +++ b/src/doc/unstable-book/src/str-checked-slicing.md @@ -0,0 +1,7 @@ +# `str_checked_slicing` + +The tracking issue for this feature is: [#39932] + +[#39932]: https://github.com/rust-lang/rust/issues/39932 + +------------------------ diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index e900bd47fb7bd..371922c9e6bb2 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Alex Crichton "] [dependencies] +regex = "0.2" \ No newline at end of file diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 9b323c95fc3c8..e1fdc19c27d25 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -24,8 +24,8 @@ use std::fs::File; use std::io::prelude::*; use std::path::Path; -#[derive(PartialEq)] -enum Status { +#[derive(Debug, PartialEq)] +pub enum Status { Stable, Removed, Unstable, @@ -42,78 +42,21 @@ impl fmt::Display for Status { } } -struct Feature { - level: Status, - since: String, - has_gate_test: bool, +#[derive(Debug)] +pub struct Feature { + pub level: Status, + pub since: String, + pub has_gate_test: bool, } pub fn check(path: &Path, bad: &mut bool) { - let mut features = collect_lang_features(&path.join("libsyntax/feature_gate.rs")); + let mut features = collect_lang_features(path); assert!(!features.is_empty()); - let mut lib_features = HashMap::::new(); - - let mut contents = String::new(); - super::walk(path, - &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), - &mut |file| { - let filename = file.file_name().unwrap().to_string_lossy(); - if !filename.ends_with(".rs") || filename == "features.rs" || - filename == "diagnostic_list.rs" { - return; - } - - contents.truncate(0); - t!(t!(File::open(&file), &file).read_to_string(&mut contents)); - for (i, line) in contents.lines().enumerate() { - let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; - }; - let level = if line.contains("[unstable(") { - Status::Unstable - } else if line.contains("[stable(") { - Status::Stable - } else { - continue; - }; - let feature_name = match find_attr_val(line, "feature") { - Some(name) => name, - None => { - err("malformed stability attribute"); - continue; - } - }; - let since = match find_attr_val(line, "since") { - Some(name) => name, - None if level == Status::Stable => { - err("malformed stability attribute"); - continue; - } - None => "None", - }; + let lib_features = collect_lib_features(path, bad, &features); + assert!(!lib_features.is_empty()); - if features.contains_key(feature_name) { - err("duplicating a lang feature"); - } - if let Some(ref s) = lib_features.get(feature_name) { - if s.level != level { - err("different stability level than before"); - } - if s.since != since { - err("different `since` than before"); - } - continue; - } - lib_features.insert(feature_name.to_owned(), - Feature { - level: level, - since: since.to_owned(), - has_gate_test: false, - }); - } - }); + let mut contents = String::new(); super::walk_many(&[&path.join("test/compile-fail"), &path.join("test/compile-fail-fulldeps"), @@ -233,8 +176,9 @@ fn test_filen_gate(filen_underscore: &str, return false; } -fn collect_lang_features(path: &Path) -> HashMap { +pub fn collect_lang_features(base_src_path: &Path) -> HashMap { let mut contents = String::new(); + let path = base_src_path.join("libsyntax/feature_gate.rs"); t!(t!(File::open(path)).read_to_string(&mut contents)); contents.lines() @@ -257,3 +201,71 @@ fn collect_lang_features(path: &Path) -> HashMap { }) .collect() } + +pub fn collect_lib_features(base_src_path: &Path, + bad: &mut bool, + features: &HashMap) -> HashMap { + let mut lib_features = HashMap::::new(); + let mut contents = String::new(); + super::walk(base_src_path, + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), + &mut |file| { + let filename = file.file_name().unwrap().to_string_lossy(); + if !filename.ends_with(".rs") || filename == "features.rs" || + filename == "diagnostic_list.rs" { + return; + } + + contents.truncate(0); + t!(t!(File::open(&file), &file).read_to_string(&mut contents)); + + for (i, line) in contents.lines().enumerate() { + let mut err = |msg: &str| { + println!("{}:{}: {}", file.display(), i + 1, msg); + *bad = true; + }; + let level = if line.contains("[unstable(") { + Status::Unstable + } else if line.contains("[stable(") { + Status::Stable + } else { + continue; + }; + let feature_name = match find_attr_val(line, "feature") { + Some(name) => name, + None => { + err("malformed stability attribute"); + continue; + } + }; + let since = match find_attr_val(line, "since") { + Some(name) => name, + None if level == Status::Stable => { + err("malformed stability attribute"); + continue; + } + None => "None", + }; + + if features.contains_key(feature_name) { + err("duplicating a lang feature"); + } + if let Some(ref s) = lib_features.get(feature_name) { + if s.level != level { + err("different stability level than before"); + } + if s.since != since { + err("different `since` than before"); + } + continue; + } + lib_features.insert(feature_name.to_owned(), + Feature { + level: level, + since: since.to_owned(), + has_gate_test: false, + }); + } + }); + lib_features +} \ No newline at end of file diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 2af891b5b8562..501e35e03e8a7 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -14,6 +14,8 @@ //! etc. This is run by default on `make check` and as part of the auto //! builders. +extern crate regex; + use std::fs; use std::path::{PathBuf, Path}; use std::env; @@ -37,6 +39,7 @@ mod features; mod cargo; mod pal; mod deps; +mod unstable_book; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -51,6 +54,7 @@ fn main() { cargo::check(&path, &mut bad); features::check(&path, &mut bad); pal::check(&path, &mut bad); + unstable_book::check(&path, &mut bad); if !args.iter().any(|s| *s == "--no-vendor") { deps::check(&path, &mut bad); } diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs new file mode 100644 index 0000000000000..c10e31077944f --- /dev/null +++ b/src/tools/tidy/src/unstable_book.rs @@ -0,0 +1,138 @@ +// Copyright 2017 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::collections::HashSet; +use std::fs; +use std::io::{self, BufRead, Write}; +use std::path; +use features::{collect_lang_features, collect_lib_features, Status}; + +const PATH_STR: &'static str = "doc/unstable-book/src"; + +const SUMMARY_FILE_NAME: &'static str = "SUMMARY.md"; + +static EXCLUDE: &'static [&'static str; 2] = &[SUMMARY_FILE_NAME, "the-unstable-book.md"]; + +/// Build the path to the Unstable Book source directory from the Rust 'src' directory +fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { + base_src_path.join(PATH_STR) +} + +/// Build the path to the Unstable Book SUMMARY file from the Rust 'src' directory +fn unstable_book_summary_path(base_src_path: &path::Path) -> path::PathBuf { + unstable_book_path(base_src_path).join(SUMMARY_FILE_NAME) +} + +/// Open the Unstable Book SUMMARY file +fn open_unstable_book_summary_file(base_src_path: &path::Path) -> fs::File { + fs::File::open(unstable_book_summary_path(base_src_path)) + .expect("could not open Unstable Book SUMMARY.md") +} + +/// Test to determine if DirEntry is a file +fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool { + dir_entry.file_type().expect("could not determine file type of directory entry").is_file() +} + +/// Retrieve names of all lang-related unstable features +fn collect_unstable_lang_feature_names(base_src_path: &path::Path) -> HashSet { + collect_lang_features(base_src_path) + .into_iter() + .filter(|&(_, ref f)| f.level == Status::Unstable) + .map(|(ref name, _)| name.to_owned()) + .collect() +} + +/// Retrieve names of all lib-related unstable features +fn collect_unstable_lib_feature_names(base_src_path: &path::Path) -> HashSet { + let mut bad = true; + let lang_features = collect_lang_features(base_src_path); + collect_lib_features(base_src_path, &mut bad, &lang_features) + .into_iter() + .filter(|&(_, ref f)| f.level == Status::Unstable) + .map(|(ref name, _)| name.to_owned()) + .collect() +} + +/// Retrieve names of all unstable features +fn collect_unstable_feature_names(base_src_path: &path::Path) -> HashSet { + collect_unstable_lib_feature_names(base_src_path) + .union(&collect_unstable_lang_feature_names(base_src_path)) + .map(|n| n.to_owned()) + .collect::>() +} + +/// Retrieve file names of all sections in the Unstable Book with: +/// +/// * hyphens replaced by underscores +/// * the markdown suffix ('.md') removed +fn collect_unstable_book_section_file_names(base_src_path: &path::Path) -> HashSet { + fs::read_dir(unstable_book_path(base_src_path)) + .expect("could not read directory") + .into_iter() + .map(|entry| entry.expect("could not read directory entry")) + .filter(dir_entry_is_file) + .map(|entry| entry.file_name().into_string().unwrap()) + .filter(|n| EXCLUDE.iter().all(|e| n != e)) + .map(|n| n.trim_right_matches(".md").replace('-', "_")) + .collect() +} + +/// Retrieve unstable feature names that are in the Unstable Book SUMMARY file +fn collect_unstable_book_summary_links(base_src_path: &path::Path) -> HashSet { + let summary_link_regex = + ::regex::Regex::new(r"^- \[(\S+)\]\(\S+\.md\)").expect("invalid regex"); + io::BufReader::new(open_unstable_book_summary_file(base_src_path)) + .lines() + .map(|l| l.expect("could not read line from file")) + .filter_map(|line| { + summary_link_regex.captures(&line).map(|c| { + c.get(1) + .unwrap() + .as_str() + .to_owned() + }) + }) + .collect() +} + +pub fn check(path: &path::Path, bad: &mut bool) { + let unstable_feature_names = collect_unstable_feature_names(path); + let unstable_book_section_file_names = collect_unstable_book_section_file_names(path); + let unstable_book_links = collect_unstable_book_summary_links(path); + + // Check for Unstable Book section names with no corresponding SUMMARY.md link + for feature_name in &unstable_book_section_file_names - &unstable_book_links { + *bad = true; + writeln!(io::stderr(), + "The Unstable Book section '{}' needs to have a link in SUMMARY.md", + feature_name) + .expect("could not write to stderr") + } + + // Check for unstable features that don't have Unstable Book sections + for feature_name in &unstable_feature_names - &unstable_book_section_file_names { + *bad = true; + writeln!(io::stderr(), + "Unstable feature '{}' needs to have a section in The Unstable Book", + feature_name) + .expect("could not write to stderr") + } + + // Check for Unstable Book sections that don't have a corresponding unstable feature + for feature_name in &unstable_book_section_file_names - &unstable_feature_names { + *bad = true; + writeln!(io::stderr(), + "The Unstable Book has a section '{}' which doesn't correspond \ + to an unstable feature", + feature_name) + .expect("could not write to stderr") + } +} From 0ba7da344935c553d6c45364e45246729abf6ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 31 Mar 2017 20:09:37 +0200 Subject: [PATCH 432/662] Ignore tests for the personality slot lifetimes on MSVC Exception handling on MSVC targets doesn't use personality slots. --- src/test/codegen/personality_lifetimes.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs index 1d07a2f104082..e0de64b26df47 100644 --- a/src/test/codegen/personality_lifetimes.rs +++ b/src/test/codegen/personality_lifetimes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-msvc + // compile-flags: -O -C no-prepopulate-passes #![crate_type="lib"] From 51d3cec38794beb644f67e80b1e7718ee14facf0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Mar 2017 11:02:46 -0600 Subject: [PATCH 433/662] Fix hard break issue --- src/librustdoc/html/markdown.rs | 36 ++++++++++++++++++++-- src/librustdoc/passes/unindent_comments.rs | 13 +++++++- src/test/rustdoc/check-hard-break.rs | 19 ++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/check-hard-break.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8acabde4081a..d1f2948bc2532 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -116,6 +116,7 @@ macro_rules! event_loop_break { match event { $($end_event)|* => break, Event::Text(ref s) => { + debug!("Text"); inner($id, s); if $escape { $buf.push_str(&format!("{}", Escape(s))); @@ -123,8 +124,11 @@ macro_rules! event_loop_break { $buf.push_str(s); } } - Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { - $buf.push(' '); + Event::SoftBreak => { + debug!("SoftBreak"); + if !$buf.is_empty() { + $buf.push(' '); + } } x => { looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); @@ -165,6 +169,7 @@ pub fn render(w: &mut fmt::Formatter, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { + debug!("CodeBlock"); let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -244,6 +249,7 @@ pub fn render(w: &mut fmt::Formatter, fn heading(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { + debug!("Heading"); let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -279,6 +285,7 @@ pub fn render(w: &mut fmt::Formatter, fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("InlineCode"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", @@ -288,6 +295,7 @@ pub fn render(w: &mut fmt::Formatter, fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, title: &str, id: &mut Option<&mut String>) { + debug!("Link"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Link(_, _))); @@ -302,6 +310,7 @@ pub fn render(w: &mut fmt::Formatter, fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String, id: &mut Option<&mut String>) { + debug!("Image"); event_loop_break!(parser, toc_builder, shorter, title, true, id, Event::End(Tag::Image(_, _))); buffer.push_str(&format!("\"{}\"", url, title)); @@ -310,6 +319,7 @@ pub fn render(w: &mut fmt::Formatter, fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Paragraph"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Paragraph)); @@ -318,6 +328,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableCell"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -329,6 +340,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_row(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableRow"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -348,6 +360,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_head(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableHead"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -367,6 +380,7 @@ pub fn render(w: &mut fmt::Formatter, fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("Table"); let mut content = String::new(); let mut rows = String::new(); while let Some(event) = parser.next() { @@ -392,6 +406,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("BlockQuote"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::BlockQuote)); @@ -400,6 +415,7 @@ pub fn render(w: &mut fmt::Formatter, fn list_item(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("ListItem"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -417,6 +433,7 @@ pub fn render(w: &mut fmt::Formatter, fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("List"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -435,6 +452,7 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Emphasis"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Emphasis)); @@ -443,6 +461,7 @@ pub fn render(w: &mut fmt::Formatter, fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Strong"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Strong)); @@ -452,6 +471,7 @@ pub fn render(w: &mut fmt::Formatter, fn footnote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("FootnoteDefinition"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::FootnoteDefinition(_))); @@ -460,6 +480,7 @@ pub fn render(w: &mut fmt::Formatter, fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Rule"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Rule)); @@ -508,6 +529,7 @@ pub fn render(w: &mut fmt::Formatter, rule(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::FootnoteDefinition(ref def)) => { + debug!("FootnoteDefinition"); let mut content = String::new(); let def = def.as_ref(); footnote(parser, &mut content, toc_builder, shorter, id); @@ -523,12 +545,22 @@ pub fn render(w: &mut fmt::Formatter, })); } Event::FootnoteReference(ref reference) => { + debug!("FootnoteReference"); let entry = parser.get_entry(reference.as_ref()); buffer.push_str(&format!("{0}\ ", (*entry).1)); } + Event::HardBreak => { + debug!("HardBreak"); + if shorter.is_fancy() { + buffer.push_str("
    "); + } else if !buffer.is_empty() { + buffer.push(' '); + } + } Event::Html(h) | Event::InlineHtml(h) => { + debug!("Html/InlineHtml"); buffer.push_str(&*h); } _ => {} diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 4d94c30847852..59fef8d20271b 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -82,7 +82,7 @@ fn unindent(s: &str) -> String { }); if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim().to_string() ]; + let mut unindented = vec![ lines[0].trim_left().to_string() ]; unindented.extend_from_slice(&lines[1..].iter().map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() @@ -160,4 +160,15 @@ mod unindent_tests { let r = unindent(&s); assert_eq!(r, "line1\nline2"); } + + #[test] + fn should_not_trim() { + let s = "\t line1 \n\t line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + + let s = " \tline1 \n \tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + } } diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs new file mode 100644 index 0000000000000..4604639c3c8d5 --- /dev/null +++ b/src/test/rustdoc/check-hard-break.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/fn.f.html +// @has - '

    hard break:
    after hard break

    ' +/// hard break: +/// after hard break +pub fn f() {} From 4de4a955052febfbcd28fd156a7585b90b5dd184 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Mar 2017 12:08:31 -0600 Subject: [PATCH 434/662] Add end whitespace ignore flag for tidy --- src/test/rustdoc/check-hard-break.rs | 2 +- src/tools/tidy/src/style.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs index 4604639c3c8d5..5c5e3f8136c73 100644 --- a/src/test/rustdoc/check-hard-break.rs +++ b/src/test/rustdoc/check-hard-break.rs @@ -10,7 +10,7 @@ #![crate_name = "foo"] -// ignore-tidy-linelength +// ignore-tidy-end-whitespace // @has foo/fn.f.html // @has - '

    hard break:
    after hard break

    ' diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2233f8c352974..012301299e0c5 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -110,6 +110,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_cr = contents.contains("ignore-tidy-cr"); let skip_tab = contents.contains("ignore-tidy-tab"); let skip_length = contents.contains("ignore-tidy-linelength"); + let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace"); for (i, line) in contents.split("\n").enumerate() { let mut err = |msg: &str| { println!("{}:{}: {}", file.display(), i + 1, msg); @@ -122,7 +123,7 @@ pub fn check(path: &Path, bad: &mut bool) { if line.contains("\t") && !skip_tab { err("tab character"); } - if line.ends_with(" ") || line.ends_with("\t") { + if !skip_end_whitespace && (line.ends_with(" ") || line.ends_with("\t")) { err("trailing whitespace"); } if line.contains("\r") && !skip_cr { From 30761556749ff4bce889f5b0ec9fd183aaa12f73 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 31 Mar 2017 11:04:25 -0700 Subject: [PATCH 435/662] travis: Compile OSX releases with Xcode 7 Unfortunately what we're using right now, Xcode 8.2, cannot compile LLVM for OSX 10.7. We've done this historically and Gecko would like to maintain this compabitiliby. This commit moves our release builders for OSX to using Xcode 7 which can compile LLVM for 10.7. The builders running tests continue to use Xcode 8.2, however, because the LLDB version with Xcode 7, 350, is blacklisted in running our LLDB tests. To continue running LLDB tests we'll stick with Xcode 8.2. --- .travis.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 148b59e8c64eb..f95893cd5e63d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,10 @@ matrix: - env: IMAGE=x86_64-gnu-distcheck - env: IMAGE=x86_64-gnu-incremental - # OSX builders + # OSX builders running tests, these run the full test suite. + # + # Note that the compiler is compiled to target 10.8 here because the Xcode + # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - env: > RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin @@ -68,6 +71,12 @@ matrix: osx_image: xcode8.2 install: *osx_install_sccache + # OSX builders producing releases. These do not run the full test suite and + # just produce a bunch of artifacts. + # + # Note that these are running in the `xcode7` image instead of the + # `xcode8.2` image as above. That's because we want to build releases for + # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7. - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended" @@ -75,10 +84,9 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 + osx_image: xcode7 install: *osx_install_sccache - env: > RUST_CHECK_TARGET=dist @@ -87,10 +95,9 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 + osx_image: xcode7 install: *osx_install_sccache # "alternate" deployments, these are "nightlies" but don't have assertions @@ -105,10 +112,9 @@ matrix: DEPLOY_ALT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 + osx_image: xcode7 install: *osx_install_sccache env: From 113b3b46a77222fe898b0a6678af451f29a7acc4 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Fri, 31 Mar 2017 17:26:55 -0300 Subject: [PATCH 436/662] Use 64 bits emulator to run android tests Also install headless jre instead of the full jre. --- src/ci/docker/arm-android/Dockerfile | 2 +- src/ci/docker/arm-android/start-emulator.sh | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index 4c89ce12531b4..04ca6d76c557b 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -13,7 +13,7 @@ RUN dpkg --add-architecture i386 && \ cmake \ unzip \ expect \ - openjdk-9-jre \ + openjdk-9-jre-headless \ sudo \ libstdc++6:i386 \ xz-utils \ diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh index 24c477d87f1a7..4a73637e9ddbf 100755 --- a/src/ci/docker/arm-android/start-emulator.sh +++ b/src/ci/docker/arm-android/start-emulator.sh @@ -10,7 +10,9 @@ # except according to those terms. set -ex -ANDROID_EMULATOR_FORCE_32BIT=true \ - nohup nohup emulator @arm-18 -no-window -partition-size 2047 \ - 0<&- &>/dev/null & + +# Setting SHELL to a file instead on a symlink helps android +# emulator identify the system +export SHELL=/bin/bash +nohup nohup emulator @arm-18 -no-window -partition-size 2047 0<&- &>/dev/null & exec "$@" From 2060266c1691f11a3c204ead056fe2e7a8c20e3b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 31 Mar 2017 23:52:35 +0100 Subject: [PATCH 437/662] Don't warn about `char` comparisons in constexprs --- src/librustc_const_eval/eval.rs | 11 +++++++++++ src/test/run-pass/const-err.rs | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c5d577ce571d4..54f5cff16ed6c 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -490,6 +490,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, _ => span_bug!(e.span, "typeck error"), }) } + (Char(a), Char(b)) => { + Bool(match op.node { + hir::BiEq => a == b, + hir::BiNe => a != b, + hir::BiLt => a < b, + hir::BiLe => a <= b, + hir::BiGe => a >= b, + hir::BiGt => a > b, + _ => span_bug!(e.span, "typeck error"), + }) + } _ => signal!(e, MiscBinaryOp), } diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs index a1c9ff8a21edb..f7f79356a0b9f 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -13,6 +13,10 @@ #![deny(const_err)] const X: *const u8 = b"" as _; +const Y: bool = 'A' == 'B'; +const Z: char = 'A'; +const W: bool = Z <= 'B'; + fn main() { let _ = ((-1 as i8) << 8 - 1) as f32; From 44d8b236f4da3b17bc4a7ac3d571d67acd3be020 Mon Sep 17 00:00:00 2001 From: projektir Date: Fri, 31 Mar 2017 18:58:32 -0400 Subject: [PATCH 438/662] Updating the description for BarrierWaitResult #29377 --- src/libstd/sync/barrier.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 295a49d6a8e89..a7b01e49d2bb6 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -50,12 +50,11 @@ struct BarrierState { generation_id: usize, } -/// A result returned from wait. +/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] +/// have rendezvoused. /// -/// Currently this opaque structure only has one method, [`.is_leader`]. Only -/// one thread will receive a result that will return `true` from this function. -/// -/// [`.is_leader`]: #method.is_leader +/// [`wait`]: struct.Barrier.html#method.wait +/// [`Barrier`]: struct.Barrier.html /// /// # Examples /// From 80bff6b59654cde4c36c7ae77ea06fb254ffe148 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 31 Mar 2017 18:04:42 -0500 Subject: [PATCH 439/662] rustdoc: format where clauses like rust-lang-nursery/fmt-rfcs#38 --- src/librustdoc/html/format.rs | 61 ++++++++++++------------- src/librustdoc/html/render.rs | 62 +++++++++++--------------- src/librustdoc/html/static/rustdoc.css | 13 +----- 3 files changed, 55 insertions(+), 81 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3589cc8fac617..3fb90f407ebc0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -49,14 +49,19 @@ pub struct MutableSpace(pub clean::Mutability); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); -/// Wrapper struct for emitting a where clause from Generics. -pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items pub struct CommaSep<'a, T: 'a>(pub &'a [T]); pub struct AbiSpace(pub Abi); +/// Wrapper struct for emitting a where clause from Generics. +pub struct WhereClause<'a>{ + pub gens: &'a clean::Generics, + pub indent: usize, + pub end_newline: bool, +} + pub struct HRef<'a> { pub did: DefId, pub text: &'a str, @@ -167,24 +172,27 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause(gens, pad) = self; + let &WhereClause{ gens, indent, end_newline } = self; if gens.where_predicates.is_empty() { return Ok(()); } let mut clause = String::new(); if f.alternate() { - clause.push_str(" where "); + clause.push_str(" where"); } else { - clause.push_str(" where "); + if end_newline { + clause.push_str("where"); + } else { + clause.push_str("where"); + } } for (i, pred) in gens.where_predicates.iter().enumerate() { - if i > 0 { - if f.alternate() { - clause.push_str(", "); - } else { - clause.push_str(",
    "); - } + if f.alternate() { + clause.push(' '); + } else { + clause.push_str("
    "); } + match pred { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; @@ -213,21 +221,18 @@ impl<'a> fmt::Display for WhereClause<'a> { } } } + + if i < gens.where_predicates.len() - 1 || end_newline { + clause.push(','); + } } if !f.alternate() { clause.push_str("
    "); - let plain = format!("{:#}", self); - if plain.len() + pad > 80 { - // break it onto its own line regardless, but make sure method impls and trait - // blocks keep their fixed padding (2 and 9, respectively) - let padding = if pad > 10 { - repeat(" ").take(8).collect::() - } else { - repeat(" ").take(pad + 6).collect::() - }; - clause = clause.replace("
    ", &format!("
    {}", padding)); - } else { - clause = clause.replace("
    ", " "); + let padding = repeat(" ").take(indent + 4).collect::(); + clause = clause.replace("
    ", &format!("
    {}", padding)); + clause.insert_str(0, &repeat(" ").take(indent).collect::()); + if !end_newline { + clause.insert_str(0, "
    "); } } write!(f, "{}", clause) @@ -838,43 +843,35 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool, use_absolute: bool) -> fmt::Result { - let mut plain = String::new(); - if f.alternate() { write!(f, "impl{:#} ", i.generics)?; } else { write!(f, "impl{} ", i.generics)?; } - plain.push_str(&format!("impl{:#} ", i.generics)); if let Some(ref ty) = i.trait_ { if i.polarity == Some(clean::ImplPolarity::Negative) { write!(f, "!")?; - plain.push_str("!"); } if link_trait { fmt::Display::fmt(ty, f)?; - plain.push_str(&format!("{:#}", ty)); } else { match *ty { clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.params, f)?; - plain.push_str(&format!("{:#}{:#}", last.name, last.params)); } _ => unreachable!(), } } write!(f, " for ")?; - plain.push_str(" for "); } fmt_type(&i.for_, f, use_absolute, true)?; - plain.push_str(&format!("{:#}", i.for_)); - fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; + fmt::Display::fmt(&WhereClause{ gens: &i.generics, indent: 0, end_newline: true }, f)?; Ok(()) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c571bcb08e4b7..4eb228ce68f46 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2012,7 +2012,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, - where_clause = WhereClause(&f.generics, 2), + where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, decl = Method(&f.decl, indent))?; document(w, cx, it) } @@ -2047,8 +2047,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, it.name.as_ref().unwrap(), t.generics, bounds, - // Where clauses in traits are indented nine spaces, per rustdoc.css - WhereClause(&t.generics, 9))?; + WhereClause { gens: &t.generics, indent: 0, end_newline: true })?; let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); @@ -2087,7 +2086,14 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, for m in &provided { write!(w, " ")?; render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; - write!(w, " {{ ... }}\n")?; + match m.inner { + clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { + write!(w, ",\n {{ ... }}\n")?; + }, + _ => { + write!(w, " {{ ... }}\n")?; + }, + } } write!(w, "}}")?; } @@ -2327,14 +2333,14 @@ fn render_assoc_item(w: &mut fmt::Formatter, name, *g); let mut indent = prefix.len(); - let where_indent = if parent == ItemType::Trait { + let (where_indent, end_newline) = if parent == ItemType::Trait { indent += 4; - 8 + (4, false) } else if parent == ItemType::Impl { - 2 + (0, true) } else { let prefix = prefix + &format!("{:#}", Method(d, indent)); - prefix.lines().last().unwrap().len() + 1 + (prefix.lines().last().unwrap().len() + 1, true) }; write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", @@ -2345,7 +2351,11 @@ fn render_assoc_item(w: &mut fmt::Formatter, name = name, generics = *g, decl = Method(d, indent), - where_clause = WhereClause(g, where_indent)) + where_clause = WhereClause { + gens: g, + indent: where_indent, + end_newline: end_newline, + }) } match item.inner { clean::StrippedItem(..) => Ok(()), @@ -2458,15 +2468,11 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, e: &clean::Enum) -> fmt::Result { write!(w, "
    ")?;
         render_attributes(w, it)?;
    -    let padding = format!("{}enum {}{:#} ",
    -                          VisSpace(&it.visibility),
    -                          it.name.as_ref().unwrap(),
    -                          e.generics).len();
         write!(w, "{}enum {}{}{}",
                VisSpace(&it.visibility),
                it.name.as_ref().unwrap(),
                e.generics,
    -           WhereClause(&e.generics, padding))?;
    +           WhereClause { gens: &e.generics, indent: 0, end_newline: true })?;
         if e.variants.is_empty() && !e.variants_stripped {
             write!(w, " {{}}")?;
         } else {
    @@ -2640,23 +2646,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                      fields: &[clean::Item],
                      tab: &str,
                      structhead: bool) -> fmt::Result {
    -    let mut plain = String::new();
         write!(w, "{}{}{}",
                VisSpace(&it.visibility),
                if structhead {"struct "} else {""},
                it.name.as_ref().unwrap())?;
    -    plain.push_str(&format!("{}{}{}",
    -                            VisSpace(&it.visibility),
    -                            if structhead {"struct "} else {""},
    -                            it.name.as_ref().unwrap()));
         if let Some(g) = g {
    -        plain.push_str(&format!("{:#}", g));
             write!(w, "{}", g)?
         }
         match ty {
             doctree::Plain => {
                 if let Some(g) = g {
    -                write!(w, "{}", WhereClause(g, plain.len() + 1))?
    +                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
                 }
                 let mut has_visible_fields = false;
                 write!(w, " {{")?;
    @@ -2685,35 +2685,30 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
             }
             doctree::Tuple => {
                 write!(w, "(")?;
    -            plain.push_str("(");
                 for (i, field) in fields.iter().enumerate() {
                     if i > 0 {
                         write!(w, ", ")?;
    -                    plain.push_str(", ");
                     }
                     match field.inner {
                         clean::StrippedItem(box clean::StructFieldItem(..)) => {
    -                        plain.push_str("_");
                             write!(w, "_")?
                         }
                         clean::StructFieldItem(ref ty) => {
    -                        plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty));
                             write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
                         }
                         _ => unreachable!()
                     }
                 }
                 write!(w, ")")?;
    -            plain.push_str(")");
                 if let Some(g) = g {
    -                write!(w, "{}", WhereClause(g, plain.len() + 1))?
    +                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
                 }
                 write!(w, ";")?;
             }
             doctree::Unit => {
                 // Needed for PhantomData.
                 if let Some(g) = g {
    -                write!(w, "{}", WhereClause(g, plain.len() + 1))?
    +                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
                 }
                 write!(w, ";")?;
             }
    @@ -2726,19 +2721,13 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
                     fields: &[clean::Item],
                     tab: &str,
                     structhead: bool) -> fmt::Result {
    -    let mut plain = String::new();
         write!(w, "{}{}{}",
                VisSpace(&it.visibility),
                if structhead {"union "} else {""},
                it.name.as_ref().unwrap())?;
    -    plain.push_str(&format!("{}{}{}",
    -                            VisSpace(&it.visibility),
    -                            if structhead {"union "} else {""},
    -                            it.name.as_ref().unwrap()));
         if let Some(g) = g {
             write!(w, "{}", g)?;
    -        plain.push_str(&format!("{:#}", g));
    -        write!(w, "{}", WhereClause(g, plain.len() + 1))?;
    +        write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?;
         }
     
         write!(w, " {{\n{}", tab)?;
    @@ -3037,13 +3026,12 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
     
     fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                     t: &clean::Typedef) -> fmt::Result {
    -    let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len();
         write!(w, "
    ")?;
         render_attributes(w, it)?;
         write!(w, "type {}{}{where_clause} = {type_};
    ", it.name.as_ref().unwrap(), t.generics, - where_clause = WhereClause(&t.generics, indent), + where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, type_ = t.type_)?; document(w, cx, it) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 4047f6045bcc5..77ae2b5870427 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -379,12 +379,6 @@ h4 > code, h3 > code, .invisible > code { .content .where.fmt-newline { display: block; } -/* Bit of whitespace to indent it */ -.content .method .where::before, -.content .fn .where::before, -.content .where.fmt-newline::before { - content: ' '; -} .content .methods > div { margin-left: 40px; } @@ -399,11 +393,6 @@ h4 > code, h3 > code, .invisible > code { font-size: 90%; } -/* Shift where in trait listing down a line */ -pre.trait .where::before { - content: '\a '; -} - nav { border-bottom: 1px solid; padding-bottom: 10px; @@ -772,4 +761,4 @@ span.since { nav.sub, .content .out-of-band, .collapse-toggle { display: none; } -} \ No newline at end of file +} From 3643d8165909c4a7959ed6cf9f3d1bd9cf3661b4 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 31 Mar 2017 19:02:00 -0500 Subject: [PATCH 440/662] rustdoc: fix alignment of fn arguments when on multiple lines --- src/librustdoc/html/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3fb90f407ebc0..fd069ed7e076b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -971,7 +971,7 @@ impl<'a> fmt::Display for Method<'a> { } } else { if i > 0 { - args.push_str("
    "); + args.push_str("
    "); args_plain.push_str(" "); } if !input.name.is_empty() { From 89c35ae76493b6ea2401d2f0271f0f35693b1198 Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Fri, 31 Mar 2017 17:05:45 -0700 Subject: [PATCH 441/662] Add links and examples to std::sync::mpsc docs (#29377) This change adds links to to `Receiver`, `Iter`, `TryIter`, `IntoIter`, `Sender`, `SyncSender`, `SendError`, `RecvError`, `TryRecvError`, `RecvTimeoutError`, `TrySendError`, `Sender::send`, `SyncSender::send`, `SyncSender::try_send`, `Receiver::recv`, `Receiver::recv_timeout`, `Receiver::iter`, and `Receiver::try_iter`. Examples added to `Receiver`, `Sender`, `Receiver::iter`. --- src/libstd/sync/mpsc/mod.rs | 167 +++++++++++++++++++++++++++++------- 1 file changed, 136 insertions(+), 31 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 288a589e589b7..fa31c6cedd2e6 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -298,7 +298,28 @@ mod mpsc_queue; mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by -/// one thread +/// one thread. +/// +/// Messages sent to the channel can be retrieved using [`recv`]. +/// +/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// use std::time::Duration; +/// let (send, recv) = channel(); +/// thread::spawn(move || { +/// send.send("Hello world!"); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// send.send("Delayed for 2 seconds"); +/// }); +/// println!("{:?}", recv.recv()); // Received immediately +/// println!("Waiting..."); +/// println!("{:?}", recv.recv()); // Received after 2 seconds +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver { inner: UnsafeCell>, @@ -312,9 +333,12 @@ unsafe impl Send for Receiver { } #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for Receiver { } -/// An iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be -/// returned when the corresponding channel has hung up. +/// An iterator over messages on a receiver, this iterator will block whenever +/// [`next`] is called, waiting for a new message, and [`None`] will be returned +/// when the corresponding channel has hung up. +/// +/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, T: 'a> { @@ -322,11 +346,13 @@ pub struct Iter<'a, T: 'a> { } /// An iterator that attempts to yield all pending values for a receiver. -/// `None` will be returned when there are no pending values remaining or -/// if the corresponding channel has hung up. +/// [`None`] will be returned when there are no pending values remaining or if +/// the corresponding channel has hung up. /// /// This Iterator will never block the caller in order to wait for data to -/// become available. Instead, it will return `None`. +/// become available. Instead, it will return [`None`]. +/// +/// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "receiver_try_iter", since = "1.15.0")] #[derive(Debug)] pub struct TryIter<'a, T: 'a> { @@ -334,8 +360,12 @@ pub struct TryIter<'a, T: 'a> { } /// An owning iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be +/// whenever [`next`] is called, waiting for a new message, and [`None`] will be /// returned when the corresponding channel has hung up. +/// +/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// #[stable(feature = "receiver_into_iter", since = "1.1.0")] #[derive(Debug)] pub struct IntoIter { @@ -344,6 +374,30 @@ pub struct IntoIter { /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// Messages can be sent through this channel with [`send`]. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// let (sender, receiver) = channel(); +/// let sender2 = sender.clone(); +/// // First thread owns sender +/// thread::spawn(move || { +/// sender.send(1); +/// }); +/// // Second thread owns sender2 +/// thread::spawn(move || { +/// sender2.send(2); +/// }); +/// let msg = receiver.recv().unwrap(); +/// let msg2 = receiver.recv().unwrap(); +/// assert_eq!(3, msg + msg2); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Sender { inner: UnsafeCell>, @@ -359,6 +413,10 @@ impl !Sync for Sender { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender { inner: Arc>, @@ -370,25 +428,32 @@ unsafe impl Send for SyncSender {} #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for SyncSender {} -/// An error returned from the `send` function on channels. +/// An error returned from the [`send`] function on channels. /// -/// A `send` operation can only fail if the receiving end of a channel is +/// A [`send`] operation can only fail if the receiving end of a channel is /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); -/// An error returned from the `recv` function on a `Receiver`. +/// An error returned from the [`recv`] function on a [`Receiver`]. /// -/// The `recv` operation can only fail if the sending half of a channel is +/// The [`recv`] operation can only fail if the sending half of a channel is /// disconnected, implying that no further messages will ever be received. +/// +/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; -/// This enumeration is the list of the possible reasons that `try_recv` could +/// This enumeration is the list of the possible reasons that [`try_recv`] could /// not return data when called. +/// +/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { @@ -403,8 +468,10 @@ pub enum TryRecvError { Disconnected, } -/// This enumeration is the list of possible errors that `recv_timeout` could +/// This enumeration is the list of possible errors that [`recv_timeout`] could /// not return data when called. +/// +/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { @@ -419,7 +486,9 @@ pub enum RecvTimeoutError { } /// This enumeration is the list of the possible error outcomes for the -/// `SyncSender::try_send` method. +/// [`SyncSender::try_send`] method. +/// +/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError { @@ -566,10 +635,13 @@ impl Sender { /// A successful send occurs when it is determined that the other end of /// the channel has not hung up already. An unsuccessful send would be one /// where the corresponding receiver has already been deallocated. Note - /// that a return value of `Err` means that the data will never be - /// received, but a return value of `Ok` does *not* mean that the data + /// that a return value of [`Err`] means that the data will never be + /// received, but a return value of [`Ok`] does *not* mean that the data /// will be received. It is possible for the corresponding receiver to - /// hang up immediately after this function returns `Ok`. + /// hang up immediately after this function returns [`Ok`]. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok /// /// This method will never block the current thread. /// @@ -712,9 +784,12 @@ impl SyncSender { /// time. If the buffer size is 0, however, it can be guaranteed that the /// receiver has indeed received the data if this function returns success. /// - /// This function will never panic, but it may return `Err` if the - /// `Receiver` has disconnected and is no longer able to receive + /// This function will never panic, but it may return [`Err`] if the + /// [`Receiver`] has disconnected and is no longer able to receive /// information. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t).map_err(SendError) @@ -722,13 +797,16 @@ impl SyncSender { /// Attempts to send a value on this channel without blocking. /// - /// This method differs from `send` by returning immediately if the + /// This method differs from [`send`] by returning immediately if the /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with `send`, this function has two failure cases + /// data. Compared with [`send`], this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// - /// See `SyncSender::send` for notes about guarantees of whether the + /// See [`SyncSender::send`] for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. + /// + /// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send + /// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError> { self.inner.try_send(t) @@ -829,15 +907,18 @@ impl Receiver { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and + /// sent to the corresponding [`Sender`], then this receiver will wake up and /// return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ``` @@ -917,15 +998,18 @@ impl Receiver { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and + /// sent to the corresponding [`Sender`], then this receiver will wake up and /// return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ```no_run @@ -1003,7 +1087,26 @@ impl Receiver { } /// Returns an iterator that will block waiting for messages, but never - /// `panic!`. It will return `None` when the channel has hung up. + /// [`panic!`]. It will return [`None`] when the channel has hung up. + /// + /// [`panic!`]: ../../../std/macro.panic.html + /// [`None`]: ../../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::channel; + /// use std::thread; + /// let (send, recv) = channel(); + /// thread::spawn(move || { + /// send.send(1u8); + /// send.send(2u8); + /// send.send(3u8); + /// }); + /// for x in recv.iter() { + /// println!("Got: {}", x); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { Iter { rx: self } @@ -1011,8 +1114,10 @@ impl Receiver { /// Returns an iterator that will attempt to yield all pending values. /// It will return `None` if there are no more pending values or if the - /// channel has hung up. The iterator will never `panic!` or block the + /// channel has hung up. The iterator will never [`panic!`] or block the /// user by waiting for values. + /// + /// [`panic!`]: ../../../std/macro.panic.html #[stable(feature = "receiver_try_iter", since = "1.15.0")] pub fn try_iter(&self) -> TryIter { TryIter { rx: self } From 1e2a61d4a6994c57cc8c8cd755734416e8117c45 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 1 Apr 2017 02:47:37 +0200 Subject: [PATCH 442/662] Change wording for push_front --- src/libcollections/vec_deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index c37bf752e86bc..22f2ff1a34618 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1073,7 +1073,7 @@ impl VecDeque { } } - /// Prepends an element to the front of the `VecDeque`. + /// Prepends an element to the `VecDeque`. /// /// # Examples /// From ae8ba78e9df9891c4a6ebedf87dfcdafcacc6e68 Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Fri, 31 Mar 2017 18:51:37 -0700 Subject: [PATCH 443/662] Fix broken links to std::iter::Iterator::next --- src/libstd/sync/mpsc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index fa31c6cedd2e6..4f3d3422fd21e 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -337,7 +337,7 @@ impl !Sync for Receiver { } /// [`next`] is called, waiting for a new message, and [`None`] will be returned /// when the corresponding channel has hung up. /// -/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] @@ -363,7 +363,7 @@ pub struct TryIter<'a, T: 'a> { /// whenever [`next`] is called, waiting for a new message, and [`None`] will be /// returned when the corresponding channel has hung up. /// -/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../../std/option/enum.Option.html#variant.None /// #[stable(feature = "receiver_into_iter", since = "1.1.0")] From 5198072c3a70b5b61271b79d2b92cc751bedafd8 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Fri, 31 Mar 2017 23:22:22 -0400 Subject: [PATCH 444/662] Added links to from_utf8 methods in Utf8Error --- src/libcore/str/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5056adeaeeec3..46264ea7b4f6d 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -152,11 +152,16 @@ impl fmt::Display for ParseBoolError { Section: Creating a string */ -/// Errors which can occur when attempting to interpret a sequence of `u8` +/// Errors which can occur when attempting to interpret a sequence of [`u8`] /// as a string. /// -/// As such, the `from_utf8` family of functions and methods for both `String`s -/// and `&str`s make use of this error, for example. +/// [`u8`]: ../../std/primitive.u8.html +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: ../../std/str/fn.from_utf8.html #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { From dab8e8121f4a2ba6322417ba7644f3a06973a785 Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Fri, 31 Mar 2017 23:22:59 -0700 Subject: [PATCH 445/662] Fix warnings in examples --- src/libstd/sync/mpsc/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 4f3d3422fd21e..33ffd5548fb88 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -312,13 +312,13 @@ mod spsc_queue; /// use std::time::Duration; /// let (send, recv) = channel(); /// thread::spawn(move || { -/// send.send("Hello world!"); +/// send.send("Hello world!").unwrap(); /// thread::sleep(Duration::from_secs(2)); // block for two seconds -/// send.send("Delayed for 2 seconds"); +/// send.send("Delayed for 2 seconds").unwrap(); /// }); -/// println!("{:?}", recv.recv()); // Received immediately +/// println!("{}", recv.recv().unwrap()); // Received immediately /// println!("Waiting..."); -/// println!("{:?}", recv.recv()); // Received after 2 seconds +/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver { @@ -388,11 +388,11 @@ pub struct IntoIter { /// let sender2 = sender.clone(); /// // First thread owns sender /// thread::spawn(move || { -/// sender.send(1); +/// sender.send(1).unwrap(); /// }); /// // Second thread owns sender2 /// thread::spawn(move || { -/// sender2.send(2); +/// sender2.send(2).unwrap(); /// }); /// let msg = receiver.recv().unwrap(); /// let msg2 = receiver.recv().unwrap(); @@ -1099,9 +1099,9 @@ impl Receiver { /// use std::thread; /// let (send, recv) = channel(); /// thread::spawn(move || { - /// send.send(1u8); - /// send.send(2u8); - /// send.send(3u8); + /// send.send(1u8).unwrap(); + /// send.send(2u8).unwrap(); + /// send.send(3u8).unwrap(); /// }); /// for x in recv.iter() { /// println!("Got: {}", x); From ef01ae7fe0652c050ec9af8f70990bb01309ffbc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 1 Apr 2017 00:31:37 -0600 Subject: [PATCH 446/662] Force footnote references to be sorted by id --- src/librustdoc/html/markdown.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index d1f2948bc2532..0b098fb14f190 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -585,11 +585,13 @@ pub fn render(w: &mut fmt::Formatter, } } if !parser.footnotes.is_empty() { + let mut v: Vec<_> = parser.footnotes.values().collect(); + v.sort_by(|a, b| a.1.cmp(&b.1)); buffer.push_str(&format!("

      {}
    ", - parser.footnotes.values() - .map(|&(ref s, _)| s.as_str()) - .collect::>() - .join(""))); + v.iter() + .map(|s| s.0.as_str()) + .collect::>() + .join(""))); } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) From d8fb322acc5314efc3026b889594c92c320dce85 Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Sat, 1 Apr 2017 00:07:55 -0700 Subject: [PATCH 447/662] Clean up std::ascii sub-level docs. * Change `utf8` variable names to `non_ascii` to be more clear, since ASCII and UTF-8 are compatible. * Fix `EscapeDefault` struct description to follow the typical iterator method format with a link to the generating function. * Add more `escape_default` examples to cover every case mentioned in the function description itself. --- src/libstd/ascii.rs | 52 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 1cac11f668d95..12ea9ab431da0 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -53,11 +53,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; /// let int_ascii = 97; /// /// assert!(ascii.is_ascii()); - /// assert!(!utf8.is_ascii()); + /// assert!(!non_ascii.is_ascii()); /// assert!(int_ascii.is_ascii()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -79,11 +79,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; /// let int_ascii = 97; /// /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❤', utf8.to_ascii_uppercase()); + /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); /// assert_eq!(65, int_ascii.to_ascii_uppercase()); /// ``` /// @@ -108,11 +108,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'A'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; /// let int_ascii = 65; /// /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❤', utf8.to_ascii_lowercase()); + /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); /// assert_eq!(97, int_ascii.to_ascii_lowercase()); /// ``` /// @@ -934,8 +934,12 @@ impl AsciiExt for char { } } -/// An iterator over the escaped version of a byte, constructed via -/// `std::ascii::escape_default`. +/// An iterator over the escaped version of a byte. +/// +/// This `struct` is created by the [`escape_default`] function. See its +/// documentation for more. +/// +/// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { range: Range, @@ -966,6 +970,38 @@ pub struct EscapeDefault { /// /// assert_eq!(b'\\', escaped.next().unwrap()); /// assert_eq!(b't', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\r'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'r', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\n'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'n', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\''); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\'', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'"'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'"', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\\'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\x9d'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'x', escaped.next().unwrap()); +/// assert_eq!(b'9', escaped.next().unwrap()); +/// assert_eq!(b'd', escaped.next().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { From a5d775d2b6b0b5f8e595d83b2fc10d74036aa36a Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Sat, 1 Apr 2017 00:47:58 -0700 Subject: [PATCH 448/662] Add more std::ascii module-level docs. --- src/libstd/ascii.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 12ea9ab431da0..b36253862094f 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -9,6 +9,20 @@ // except according to those terms. //! Operations on ASCII strings and characters. +//! +//! Most string operations in Rust act on UTF-8 strings. However, at times it +//! makes more sense to only consider the ASCII character set for a specific +//! operation. +//! +//! The [`AsciiExt`] trait provides methods that allow for character +//! operations that only act on the ASCII subset and leave non-ASCII characters +//! alone. +//! +//! The [`escape_default`] function provides an iterator over the bytes of an +//! escaped version of the character given. +//! +//! [`AsciiExt`]: trait.AsciiExt.html +//! [`escape_default`]: fn.escape_default.html #![stable(feature = "rust1", since = "1.0.0")] From 34cf28826f380fde33fedf377c1540e12d3b13a0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Mar 2017 12:49:13 -0700 Subject: [PATCH 449/662] rustc: Stabilize the `#![windows_subsystem]` attribute This commit stabilizes the `#![windows_subsystem]` attribute which is a conservative exposure of the `/SUBSYSTEM` linker flag on Widnows platforms. This is useful for creating applications as well as console programs. Closes #37499 --- src/doc/unstable-book/src/SUMMARY.md | 1 - src/doc/unstable-book/src/windows-subsystem.md | 10 ---------- src/libsyntax/feature_gate.rs | 12 +++--------- src/test/compile-fail/windows-subsystem-gated.rs | 16 ---------------- .../compile-fail/windows-subsystem-invalid.rs | 1 - src/test/run-make/windows-subsystem/console.rs | 1 - src/test/run-make/windows-subsystem/windows.rs | 1 - 7 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 src/doc/unstable-book/src/windows-subsystem.md delete mode 100644 src/test/compile-fail/windows-subsystem-gated.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec816a..72c2461c8bb5e 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -209,5 +209,4 @@ - [windows_handle](windows-handle.md) - [windows_net](windows-net.md) - [windows_stdio](windows-stdio.md) -- [windows_subsystem](windows-subsystem.md) - [zero_one](zero-one.md) diff --git a/src/doc/unstable-book/src/windows-subsystem.md b/src/doc/unstable-book/src/windows-subsystem.md deleted file mode 100644 index 80583352fbf96..0000000000000 --- a/src/doc/unstable-book/src/windows-subsystem.md +++ /dev/null @@ -1,10 +0,0 @@ -# `windows_subsystem` - -The tracking issue for this feature is: [#37499] - -[#37499]: https://github.com/rust-lang/rust/issues/37499 - ------------------------- - - - diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12d25ca4274fe..412803ddcd5a3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -292,9 +292,6 @@ declare_features! ( // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) (active, generic_param_attrs, "1.11.0", Some(34761)), - // The #![windows_subsystem] attribute - (active, windows_subsystem, "1.14.0", Some(37499)), - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -408,7 +405,8 @@ declare_features! ( (accepted, static_recursion, "1.17.0", Some(29719)), // pub(restricted) visibilities (RFC 1422) (accepted, pub_restricted, "1.17.0", Some(32409)), - + // The #![windows_subsystem] attribute + (accepted, windows_subsystem, "1.18.0", Some(37499)), ); // If you change this, please modify src/doc/unstable-book as well. You must // move that documentation into the relevant place in the other docs, and @@ -768,11 +766,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, - "windows_subsystem", - "the windows subsystem attribute \ - is currently unstable", - cfg_fn!(windows_subsystem))), + ("windows_subsystem", Whitelisted, Ungated), ("proc_macro_attribute", Normal, Gated(Stability::Unstable, "proc_macro", diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/compile-fail/windows-subsystem-gated.rs deleted file mode 100644 index 63f891a2af7bf..0000000000000 --- a/src/test/compile-fail/windows-subsystem-gated.rs +++ /dev/null @@ -1,16 +0,0 @@ -// 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. - -// gate-test-windows_subsystem - -#![windows_subsystem = "console"] -//~^ ERROR: the windows subsystem attribute is currently unstable - -fn main() {} diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs index e0003440719e6..7772cfd6a2c93 100644 --- a/src/test/compile-fail/windows-subsystem-invalid.rs +++ b/src/test/compile-fail/windows-subsystem-invalid.rs @@ -10,7 +10,6 @@ // error-pattern: invalid windows subsystem `wrong`, only `windows` and `console` are allowed -#![feature(windows_subsystem)] #![windows_subsystem = "wrong"] fn main() {} diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs index 3aedb0ecab722..ffad1e35ee660 100644 --- a/src/test/run-make/windows-subsystem/console.rs +++ b/src/test/run-make/windows-subsystem/console.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(windows_subsystem)] #![windows_subsystem = "console"] fn main() {} diff --git a/src/test/run-make/windows-subsystem/windows.rs b/src/test/run-make/windows-subsystem/windows.rs index 5d875a5a1bf1f..33cbe32059190 100644 --- a/src/test/run-make/windows-subsystem/windows.rs +++ b/src/test/run-make/windows-subsystem/windows.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(windows_subsystem)] #![windows_subsystem = "windows"] fn main() {} From 364241c709b3b769a0515b07b21c5748818291d8 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 1 Apr 2017 09:56:40 -0400 Subject: [PATCH 450/662] Added links to types in from_utf8 description --- src/libcore/str/mod.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f75a1f7ab6e0f..8356fcd3cbeed 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -210,11 +210,15 @@ impl Utf8Error { /// Converts a slice of bytes to a string slice. /// -/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`) -/// is made of bytes, so this function converts between the two. Not all byte -/// slices are valid string slices, however: `&str` requires that it is valid -/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and -/// then does the conversion. +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: ../../std/primitive.str.html +/// [`u8`]: ../../std/primitive.u8.html +/// [byteslice]: ../../std/primitive.slice.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of @@ -228,9 +232,12 @@ impl Utf8Error { /// /// [string]: ../../std/string/struct.String.html#method.from_utf8 /// -/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of -/// it, this function is one way to have a stack-allocated string. There is -/// an example of this in the examples section below. +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html /// /// # Errors /// From 8ad8ba619426d76b041905258cd571538e7d4ca8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Apr 2017 06:58:11 -0700 Subject: [PATCH 451/662] Update cargo submodule Pulls in a fix for rust-lang/rust#40956 --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 4e95c6b41eca3..4729175045b41 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 +Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 From 128a313ee26b06b32e6980b4092435d7d352347d Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 1 Apr 2017 21:58:30 +0530 Subject: [PATCH 452/662] Improve docs of core::option::IntoIter --- src/libcore/option.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index d997f3592fd76..027d370f88f41 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -964,9 +964,15 @@ impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} -/// An iterator over the item contained inside an [`Option`]. +/// An iterator over the value in [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// +/// This `struct` is created by [`Option::into_iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { inner: Item } From 029ace40719baa452c7ac27e42529ec3ae8256c8 Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 1 Apr 2017 22:09:10 +0530 Subject: [PATCH 453/662] Improve docs of core::option::IterMut --- src/libcore/option.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 027d370f88f41..2d50f1b0ae5c4 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -933,9 +933,15 @@ impl<'a, A> Clone for Iter<'a, A> { } } -/// An iterator over a mutable reference of the contained item in an [`Option`]. +/// An iterator over a mutable reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// +/// This `struct` is created by [`Option::iter_mut`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter_mut`]: enum.Option.html#method.iter_mut #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } From c414628782ab60817909de2b98d206782dc15200 Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 1 Apr 2017 22:17:48 +0530 Subject: [PATCH 454/662] Improve docs of core::option::Iter --- src/libcore/option.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 2d50f1b0ae5c4..2cdafbf2570e5 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -894,9 +894,15 @@ impl ExactSizeIterator for Item {} impl FusedIterator for Item {} unsafe impl TrustedLen for Item {} -/// An iterator over a reference of the contained item in an [`Option`]. +/// An iterator over a reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// +/// This `struct` is created by [`Option::iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter`]: enum.Option.html#method.iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } From 4c9f8ae4fd50b857e7a754087243100764a4e4de Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sun, 2 Apr 2017 06:10:34 +0530 Subject: [PATCH 455/662] Minor changes to core::option docs --- src/libcore/option.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 2cdafbf2570e5..1a48f27762580 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -896,9 +896,9 @@ unsafe impl TrustedLen for Item {} /// An iterator over a reference to the [`Some`] variant of an [`Option`]. /// -/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// -/// This `struct` is created by [`Option::iter`] function. +/// This `struct` is created by the [`Option::iter`] function. /// /// [`Option`]: enum.Option.html /// [`Some`]: enum.Option.html#variant.Some @@ -941,9 +941,9 @@ impl<'a, A> Clone for Iter<'a, A> { /// An iterator over a mutable reference to the [`Some`] variant of an [`Option`]. /// -/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// -/// This `struct` is created by [`Option::iter_mut`] function. +/// This `struct` is created by the [`Option::iter_mut`] function. /// /// [`Option`]: enum.Option.html /// [`Some`]: enum.Option.html#variant.Some @@ -978,9 +978,9 @@ unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} /// An iterator over the value in [`Some`] variant of an [`Option`]. /// -/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// -/// This `struct` is created by [`Option::into_iter`] function. +/// This `struct` is created by the [`Option::into_iter`] function. /// /// [`Option`]: enum.Option.html /// [`Some`]: enum.Option.html#variant.Some From bd698b9e8b02e27409123e71c0594523b926b850 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 19 Mar 2017 11:22:48 -0400 Subject: [PATCH 456/662] Don't panic if we have tidy errors. Otherwise we get the standard Rust panic message alongside "some tidy checks failed" which seems unnecessary. --- src/tools/tidy/src/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 501e35e03e8a7..d0e8cf9c343dc 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -16,9 +16,11 @@ extern crate regex; +use std::env; use std::fs; +use std::io::{self, Write}; use std::path::{PathBuf, Path}; -use std::env; +use std::process; macro_rules! t { ($e:expr, $p:expr) => (match $e { @@ -60,7 +62,8 @@ fn main() { } if bad { - panic!("some tidy checks failed"); + writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr"); + process::exit(1); } } From ff4febf8eafa86bc7a3130d68f81c852a9da3661 Mon Sep 17 00:00:00 2001 From: Peter Gerber Date: Sat, 1 Apr 2017 15:58:37 +0200 Subject: [PATCH 457/662] Improve documentation for `std::fs::DirBuilder` --- src/libstd/fs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index ca26dc9527c04..1b00eb95de2bc 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1726,9 +1726,9 @@ impl DirBuilder { } } - /// Indicate that directories create should be created recursively, creating - /// all parent directories if they do not exist with the same security and - /// permissions settings. + /// Indicates that directories should be created recursively, creating all + /// parent directories. Parents that do not exist are created with the same + /// security and permissions settings. /// /// This option defaults to `false`. /// @@ -1749,6 +1749,9 @@ impl DirBuilder { /// Create the specified directory with the options configured in this /// builder. /// + /// It is considered an error if the directory already exists unless + /// recursive mode is enabled. + /// /// # Examples /// /// ```no_run From 509ef4c496ffafdc635c94e52e4d19b01d0bfb6a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 2 Apr 2017 12:03:54 +0200 Subject: [PATCH 458/662] std::thread docs: fix link to current() --- src/libstd/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index edf928d61063e..18c00e7c5f1b6 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -158,7 +158,7 @@ //! [`Err`]: ../../std/result/enum.Result.html#variant.Err //! [`panic!`]: ../../std/macro.panic.html //! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`thread::current`]: ../../std/thread/fn.spawn.html +//! [`thread::current`]: ../../std/thread/fn.current.html //! [`Thread`]: ../../std/thread/struct.Thread.html //! [`park`]: ../../std/thread/fn.park.html //! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark From 09ac56d6efd41c02cbb7f8714d59bdd43f663ec8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 2 Apr 2017 16:18:39 +0300 Subject: [PATCH 459/662] mark build::cfg::start_new_block as inline(never) LLVM has a bug - PR32488 - where it fails to deduplicate allocas in some circumstances. The function `start_new_block` has allocas totalling 1216 bytes, and when LLVM inlines several copies of that function into the recursive function `expr::into`, that function's stack space usage goes into tens of kiBs, causing stack overflows. Mark `start_new_block` as inline(never) to keep it from being inlined, getting stack usage under control. Fixes #40493. Fixes #40573. --- src/librustc_mir/build/cfg.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 71e97e4bfe0d3..c503b8c7fe06f 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -25,6 +25,9 @@ impl<'tcx> CFG<'tcx> { &mut self.basic_blocks[blk] } + // llvm.org/PR32488 makes this function use an excess of stack space. Mark + // it as #[inline(never)] to keep rustc's stack use in check. + #[inline(never)] pub fn start_new_block(&mut self) -> BasicBlock { self.basic_blocks.push(BasicBlockData::new(None)) } From 255d9191a9509c4adfc086deacff5ec6680815a5 Mon Sep 17 00:00:00 2001 From: mandeep Date: Sun, 2 Apr 2017 11:21:05 -0500 Subject: [PATCH 460/662] Fixed typo in doc comments for swap_remove --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e00341..44ac4f1cff588 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -678,7 +678,7 @@ impl Vec { self.len = len; } - /// Removes an element from anywhere in the vector and return it, replacing + /// Removes an element from anywhere in the vector and returns it, replacing /// it with the last element. /// /// This does not preserve ordering, but is O(1). From b946ecd02018d1671c990057d7136176df60da35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Mar 2017 15:14:45 -0700 Subject: [PATCH 461/662] Suggest using enum when a variant is used as a type Given a file: ```rust enum Fruit { Apple(i64), Orange(i64), } fn should_return_fruit() -> Apple { Apple(5) } ``` Provide the following output: ```rust error[E0412]: cannot find type `Apple` in this scope --> file.rs:16:29 | 16 | fn should_return_fruit() -> Apple { | ^^^^^ not found in this scope | help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? --> file.rs:12:5 | 12 | Apple(i64), | ^^^^^^^^^^ error[E0425]: cannot find function `Apple` in this scope --> file.rs:17:5 | 17 | Apple(5) | ^^^^^ not found in this scope | = help: possible candidate is found in another module, you can import it into scope: `use Fruit::Apple;` ``` --- src/librustc_resolve/lib.rs | 30 +++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ++++++++++++ src/test/ui/did_you_mean/issue-35675.stderr | 74 +++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/test/ui/did_you_mean/issue-35675.rs create mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..a39cd3b0d551c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2220,6 +2220,7 @@ impl<'a> Resolver<'a> { -> PathResolution { let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); + let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; // Base error is amended with one short label and possibly some longer helps/notes. let report_errors = |this: &mut Self, def: Option| { @@ -2270,6 +2271,19 @@ impl<'a> Resolver<'a> { if !candidates.is_empty() { // Report import candidates as help and proceed searching for labels. show_candidates(&mut err, &candidates, def.is_some()); + } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { + let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); + for suggestion in enum_candidates { + let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", + variant_path, + enum_path); + if suggestion.path.span == DUMMY_SP { + err.help(&msg); + } else { + err.span_help(suggestion.path.span, &msg); + } + } } if path.len() == 1 && this.self_type_is_available() { if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) { @@ -3422,6 +3436,22 @@ fn path_names_to_string(path: &Path) -> String { names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::>()) } +/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { + let variant_path = &suggestion.path; + let variant_path_string = path_names_to_string(variant_path); + + let path_len = suggestion.path.segments.len(); + let enum_path = ast::Path { + span: suggestion.path.span, + segments: suggestion.path.segments[0..path_len - 1].to_vec(), + }; + let enum_path_string = path_names_to_string(&enum_path); + + (variant_path_string, enum_path_string) +} + + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs new file mode 100644 index 0000000000000..ff29f3ad4078b --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.rs @@ -0,0 +1,44 @@ +// Copyright 2017 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. + +enum Fruit { + Apple(i64), + Orange(i64), +} + +fn should_return_fruit() -> Apple { + Apple(5) +} + +fn should_return_fruit_too() -> Fruit::Apple { + Apple(5) +} + +fn foo() -> Ok { + Ok(()) +} + +fn bar() -> Variant3 { +} + +fn qux() -> Some { + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr new file mode 100644 index 0000000000000..43851d76029df --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -0,0 +1,74 @@ +error[E0412]: cannot find type `Apple` in this scope + --> $DIR/issue-35675.rs:16:29 + | +16 | fn should_return_fruit() -> Apple { + | ^^^^^ not found in this scope + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:17:5 + | +17 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Fruit::Apple` + --> $DIR/issue-35675.rs:20:33 + | +20 | fn should_return_fruit_too() -> Fruit::Apple { + | ^^^^^^^^^^^^ not a type + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:21:5 + | +21 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Ok` + --> $DIR/issue-35675.rs:24:13 + | +24 | fn foo() -> Ok { + | ^^ not a type + | + = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? + = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + +error[E0412]: cannot find type `Variant3` in this scope + --> $DIR/issue-35675.rs:28:13 + | +28 | fn bar() -> Variant3 { + | ^^^^^^^^ not found in this scope + | +help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + --> $DIR/issue-35675.rs:41:9 + | +41 | Variant3(usize), + | ^^^^^^^^^^^^^^^ + +error[E0573]: expected type, found variant `Some` + --> $DIR/issue-35675.rs:31:13 + | +31 | fn qux() -> Some { + | ^^^^ not a type + | + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + +error: aborting due to 7 previous errors + From b83352e44c36e81db7f00eb60e78ff3828c51c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 28 Mar 2017 18:56:29 -0700 Subject: [PATCH 462/662] Introduce `TyErr` independent from `TyInfer` Add a `TyErr` type to represent unknown types in places where parse errors have happened, while still able to build the AST. Initially only used to represent incorrectly written fn arguments and avoid "expected X parameters, found Y" errors when called with the appropriate amount of parameters. We cannot use `TyInfer` for this as `_` is not allowed as a valid argument type. Example output: ```rust error: expected one of `:` or `@`, found `,` --> file.rs:12:9 | 12 | fn bar(x, y: usize) {} | ^ error[E0061]: this function takes 2 parameters but 3 parameters were supplied --> file.rs:19:9 | 12 | fn bar(x, y) {} | --------------- defined here ... 19 | bar(1, 2, 3); | ^^^^^^^ expected 2 parameters ``` --- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/mod.rs | 2 + src/librustc/hir/print.rs | 3 ++ .../calculate_svh/svh_visitor.rs | 6 ++- src/librustc_typeck/astconv.rs | 3 ++ src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/ast.rs | 2 + src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 25 +++++++++- src/libsyntax/print/pprust.rs | 3 ++ src/libsyntax/visit.rs | 2 +- src/test/ui/span/issue-34264.rs | 20 ++++++++ src/test/ui/span/issue-34264.stderr | 49 +++++++++++++++++++ 14 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/span/issue-34264.rs create mode 100644 src/test/ui/span/issue-34264.stderr diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c7ad143c94979..2c8b145f126cd 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -578,7 +578,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyTypeof(expression) => { visitor.visit_nested_body(expression) } - TyInfer => {} + TyInfer | TyErr => {} } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69f4..acc6d21ddc696 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -555,6 +555,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty(&mut self, t: &Ty) -> P { let kind = match t.node { TyKind::Infer => hir::TyInfer, + TyKind::Err => hir::TyErr, TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d5000ac9c1866..0da405d1821d3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1351,6 +1351,8 @@ pub enum Ty_ { /// TyInfer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. TyInfer, + /// Placeholder for a type that has failed to be defined. + TyErr, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 04a65fd5e3aa4..4a5a35aa82ca0 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -450,6 +450,9 @@ impl<'a> State<'a> { hir::TyInfer => { word(&mut self.s, "_")?; } + hir::TyErr => { + word(&mut self.s, "?")?; + } } self.end() } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 5401b371888e9..4700b77be0762 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -432,7 +432,8 @@ enum SawTyComponent { SawTyObjectSum, SawTyImplTrait, SawTyTypeof, - SawTyInfer + SawTyInfer, + SawTyErr, } fn saw_ty(node: &Ty_) -> SawTyComponent { @@ -448,7 +449,8 @@ fn saw_ty(node: &Ty_) -> SawTyComponent { TyTraitObject(..) => SawTyObjectSum, TyImplTrait(..) => SawTyImplTrait, TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer + TyInfer => SawTyInfer, + TyErr => SawTyErr, } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 923ec05c22b77..66c4a81a5c0f2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1229,6 +1229,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // handled specially and will not descend into this routine. self.ty_infer(ast_ty.span) } + hir::TyErr => { + tcx.types.err + } }; cache.borrow_mut().insert(ast_ty.id, result_ty); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f3ea6c4467c40..ac72d7d29a24c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1805,7 +1805,7 @@ impl Clean for hir::Ty { } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)), - TyInfer => Infer, + TyInfer | TyErr => Infer, TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9eb86aa006d17..c6a3e8a2dedc4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1361,6 +1361,8 @@ pub enum TyKind { ImplicitSelf, // A macro in the type position. Mac(Mac), + /// Placeholder for a kind that has failed to be defined. + Err, } /// Inline assembly dialect. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a4e196ac5577..92e25b00e0ac1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -358,7 +358,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), node: match node { - TyKind::Infer | TyKind::ImplicitSelf => node, + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => node, TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855af..23fc1351426c2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -407,6 +407,25 @@ impl From> for LhsExpr { } } +/// Create a placeholder argument. +fn dummy_arg(span: Span) -> Arg { + let spanned = Spanned { + span: span, + node: keywords::Invalid.ident() + }; + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None), + span: span + }); + let ty = Ty { + node: TyKind::Err, + span: span, + id: ast::DUMMY_NODE_ID + }; + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } +} + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, tokens: TokenStream, @@ -4343,8 +4362,12 @@ impl<'a> Parser<'a> { Ok(arg) => Ok(Some(arg)), Err(mut e) => { e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - Ok(None) + // Create a placeholder argument for proper arg count (#34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(span))) } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f042a18d61036..e7feff2b79fce 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1095,6 +1095,9 @@ impl<'a> State<'a> { ast::TyKind::Infer => { word(&mut self.s, "_")?; } + ast::TyKind::Err => { + word(&mut self.s, "?")?; + } ast::TyKind::ImplicitSelf => { word(&mut self.s, "Self")?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a6e..b5e9a1892acc9 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -350,7 +350,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Typeof(ref expression) => { visitor.visit_expr(expression) } - TyKind::Infer | TyKind::ImplicitSelf => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } diff --git a/src/test/ui/span/issue-34264.rs b/src/test/ui/span/issue-34264.rs new file mode 100644 index 0000000000000..00482f50618db --- /dev/null +++ b/src/test/ui/span/issue-34264.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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 foo(Option, String) {} +fn bar(x, y: usize) {} + +fn main() { + foo(Some(42), 2); + foo(Some(42), 2, ""); + bar("", ""); + bar(1, 2); + bar(1, 2, 3); +} diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr new file mode 100644 index 0000000000000..c79db54eaef04 --- /dev/null +++ b/src/test/ui/span/issue-34264.stderr @@ -0,0 +1,49 @@ +error: expected one of `:` or `@`, found `<` + --> $DIR/issue-34264.rs:11:14 + | +11 | fn foo(Option, String) {} + | ^ + +error: expected one of `:` or `@`, found `)` + --> $DIR/issue-34264.rs:11:27 + | +11 | fn foo(Option, String) {} + | ^ + +error: expected one of `:` or `@`, found `,` + --> $DIR/issue-34264.rs:12:9 + | +12 | fn bar(x, y: usize) {} + | ^ + +error[E0061]: this function takes 2 parameters but 3 parameters were supplied + --> $DIR/issue-34264.rs:16:9 + | +11 | fn foo(Option, String) {} + | ------------------------------ defined here +... +16 | foo(Some(42), 2, ""); + | ^^^^^^^^^^^^^^^ expected 2 parameters + +error[E0308]: mismatched types + --> $DIR/issue-34264.rs:17:13 + | +17 | bar("", ""); + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + = help: here are some functions which might fulfill your needs: + - .len() + +error[E0061]: this function takes 2 parameters but 3 parameters were supplied + --> $DIR/issue-34264.rs:19:9 + | +12 | fn bar(x, y: usize) {} + | ---------------------- defined here +... +19 | bar(1, 2, 3); + | ^^^^^^^ expected 2 parameters + +error: aborting due to 3 previous errors + From 584b40578d8ab999031da0855f319a94db06dc47 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:18:27 -0600 Subject: [PATCH 463/662] Vastly improve the help output. - Don't print 'unknown subcommand' at the top of the help message. The help message now clearly instructs the user to provide a subcommand. - Clarify the usage line. Subcommand is required. Don't echo invalid input back out in the usage line (what the...???). args renamed to paths, because that's what all the args are referred to elsewhere. - List the available subcommands immediately following the usage line. It's the one required argument, after all. - Slightly improve the extra documentation for the build, test, and doc commands. - Don't print 'Available invocations:' at all. It occurred immediately before 'Available paths:'. - Clearly state that running with '-h -v' will produce a list of available paths. --- src/bootstrap/flags.rs | 53 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 556a362a8749a..1a260050a9422 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -90,19 +90,31 @@ impl Flags { opts.optflag("h", "help", "print this help message"); let usage = |n, opts: &Options| -> ! { - let subcommand = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py [options] [...]"); + let subcommand_help = format!("\ +Usage: x.py [options] [...] + +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts - println!("{}", opts.usage(&brief)); +To learn more about a subcommand, run `./x.py -h`"); + + println!("{}", opts.usage(&subcommand_help)); + + let subcommand = args.get(0).map(|s| &**s); match subcommand { Some("build") => { println!("\ Arguments: - This subcommand accepts a number of positional arguments of directories to - the crates and/or artifacts to compile. For example: + This subcommand accepts a number of paths to directories to the crates + and/or artifacts to compile. For example: ./x.py build src/libcore - ./x.py build src/libproc_macro + ./x.py build src/libcore src/libproc_macro ./x.py build src/libstd --stage 1 If no arguments are passed then the complete artifacts for that stage are @@ -120,8 +132,8 @@ Arguments: Some("test") => { println!("\ Arguments: - This subcommand accepts a number of positional arguments of directories to - tests that should be compiled and run. For example: + This subcommand accepts a number of paths to directories to tests that + should be compiled and run. For example: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map @@ -138,12 +150,12 @@ Arguments: Some("doc") => { println!("\ Arguments: - This subcommand accepts a number of positional arguments of directories of - documentation to build. For example: + This subcommand accepts a number of paths to directories of documentation + to build. For example: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon - ./x.py doc src/libstd + ./x.py doc src/doc/book src/libstd If no arguments are passed then everything is documented: @@ -155,6 +167,7 @@ Arguments: _ => {} } + if let Some(subcommand) = subcommand { if subcommand == "build" || subcommand == "test" || @@ -162,7 +175,6 @@ Arguments: subcommand == "doc" || subcommand == "clean" || subcommand == "dist" { - println!("Available invocations:"); if args.iter().any(|a| a == "-v") { let flags = Flags::parse(&["build".to_string()]); let mut config = Config::default(); @@ -171,7 +183,7 @@ Arguments: metadata::build(&mut build); step::build_rules(&build).print_help(subcommand); } else { - println!(" ... elided, run `./x.py {} -h -v` to see", + println!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand); } @@ -179,18 +191,6 @@ Arguments: } } -println!("\ -Subcommands: - build Compile either the compiler or libraries - test Build and run some test suites - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts - -To learn more about a subcommand, run `./x.py -h` -"); - process::exit(n); }; if args.len() == 0 { @@ -256,8 +256,7 @@ To learn more about a subcommand, run `./x.py -h` } } "--help" => usage(0, &opts), - cmd => { - println!("unknown subcommand: {}", cmd); + _ => { usage(1, &opts); } }; From 992a59efc3e3fd976728fc19a1a854afcbb06adf Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:20:51 -0600 Subject: [PATCH 464/662] Using an untyped, one-letter variable binding as an argument to a function and then not using it until over 100 lines later is just mean. --- src/bootstrap/flags.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 1a260050a9422..64b66d9c6bc34 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -89,7 +89,7 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |n, opts: &Options| -> ! { + let usage = |exit_code, opts: &Options| -> ! { let subcommand_help = format!("\ Usage: x.py [options] [...] @@ -191,7 +191,7 @@ Arguments: } } - process::exit(n); + process::exit(exit_code); }; if args.len() == 0 { println!("a subcommand must be passed"); From 5ba579e7f43e607315737899a779d8bd0f378f53 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:35:55 -0600 Subject: [PATCH 465/662] Save my TODO's as comments, so I don't forget. --- src/bootstrap/flags.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 64b66d9c6bc34..684a39953e2e6 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -212,6 +212,8 @@ Arguments: let remaining_as_path = |m: &Matches| { m.free.iter().map(|p| cwd.join(p)).collect::>() }; + // TODO: Parse subcommand nicely up at top, so options can occur before the subcommand. + // TODO: Get the subcommand-specific options below into the help output let m: Matches; let cmd = match &args[0][..] { From aa4bd0ec0ea0e4edd2a4507c776f9979a05005d1 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 1 Apr 2017 15:48:03 -0600 Subject: [PATCH 466/662] Finish the improvements I planned. - No more manual args manipulation -- getopts used for everything. As a result, options can be in any position, now, even before the subcommand. - The additional options for test, bench, and dist now appear in the help output. - No more single-letter variable bindings used internally for large scopes. - Don't output the time measurement when just invoking 'x.py' - Logic is now much more linear. We build strings up, and then print them. --- src/bootstrap/bootstrap.py | 5 +- src/bootstrap/flags.rs | 222 ++++++++++++++++++------------------- src/bootstrap/step.rs | 11 +- 3 files changed, 113 insertions(+), 125 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 73f3b1d1cebab..0e5991a51bc80 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -591,9 +591,10 @@ def bootstrap(): def main(): start_time = time() + help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap() - if ('-h' not in sys.argv) and ('--help' not in sys.argv): + if not help_triggered: print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): @@ -601,7 +602,7 @@ def main(): else: exit_code = 1 print(e) - if ('-h' not in sys.argv) and ('--help' not in sys.argv): + if not help_triggered: print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 684a39953e2e6..e60e279876c37 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Matches, Options}; +use getopts::{Options}; use Build; use config::Config; @@ -75,7 +75,22 @@ pub enum Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { + let mut extra_help = String::new(); + let mut subcommand_help = format!("\ +Usage: x.py [options] [...] + +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h`"); + let mut opts = Options::new(); + // Options common to all subcommands opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); @@ -89,26 +104,38 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |exit_code, opts: &Options| -> ! { - let subcommand_help = format!("\ -Usage: x.py [options] [...] - -Subcommands: - build Compile either the compiler or libraries - test Build and run some test suites - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts + // fn usage() + let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; -To learn more about a subcommand, run `./x.py -h`"); + // Get subcommand + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + let subcommand = match matches.free.get(0) { + Some(s) => { s }, + None => { + // No subcommand -- lets only show the general usage and subcommand help in this case. + println!("{}\n", subcommand_help); + process::exit(0); + } + }; - println!("{}", opts.usage(&subcommand_help)); + // Get any optional paths which occur after the subcommand + let cwd = t!(env::current_dir()); + let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); - let subcommand = args.get(0).map(|s| &**s); - match subcommand { - Some("build") => { - println!("\ + // Some subcommands have specific arguments help text + match subcommand.as_str() { + "build" => { + subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: @@ -125,12 +152,11 @@ Arguments: For a quick build with a usable compile, you can pass: - ./x.py build --stage 1 src/libtest -"); - } - - Some("test") => { - println!("\ + ./x.py build --stage 1 src/libtest"); + } + "test" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories to tests that should be compiled and run. For example: @@ -143,12 +169,13 @@ Arguments: compiled and tested. ./x.py test - ./x.py test --stage 1 -"); - } - - Some("doc") => { - println!("\ + ./x.py test --stage 1"); + } + "bench" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + } + "doc" => { + subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories of documentation to build. For example: @@ -160,111 +187,74 @@ Arguments: If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1 -"); - } - - _ => {} + ./x.py doc --stage 1"); } - - - if let Some(subcommand) = subcommand { - if subcommand == "build" || - subcommand == "test" || - subcommand == "bench" || - subcommand == "doc" || - subcommand == "clean" || - subcommand == "dist" { - if args.iter().any(|a| a == "-v") { - let flags = Flags::parse(&["build".to_string()]); - let mut config = Config::default(); - config.build = flags.build.clone(); - let mut build = Build::new(flags, config); - metadata::build(&mut build); - step::build_rules(&build).print_help(subcommand); - } else { - println!("Run `./x.py {} -h -v` to see a list of available paths.", - subcommand); - } - - println!(""); - } + "dist" => { + opts.optflag("", "install", "run installer as well"); } - - process::exit(exit_code); + _ => { } }; - if args.len() == 0 { - println!("a subcommand must be passed"); - usage(1, &opts); - } - let parse = |opts: &Options| { - let m = opts.parse(&args[1..]).unwrap_or_else(|e| { - println!("failed to parse options: {}", e); - usage(1, opts); - }); - if m.opt_present("h") { - usage(0, opts); + + // All subcommands can have an optional "Available paths" section + if matches.opt_present("verbose") { + let flags = Flags::parse(&["build".to_string()]); + let mut config = Config::default(); + config.build = flags.build.clone(); + let mut build = Build::new(flags, config); + metadata::build(&mut build); + let maybe_rules_help = step::build_rules(&build).get_help(subcommand); + if maybe_rules_help.is_some() { + extra_help.push_str(maybe_rules_help.unwrap().as_str()); } - return m - }; + } else { + extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.", + subcommand).as_str()); + } - let cwd = t!(env::current_dir()); - let remaining_as_path = |m: &Matches| { - m.free.iter().map(|p| cwd.join(p)).collect::>() - }; - // TODO: Parse subcommand nicely up at top, so options can occur before the subcommand. - // TODO: Get the subcommand-specific options below into the help output + // User passed in -h/--help? + if matches.opt_present("help") { + usage(0, &opts, &subcommand_help, &extra_help); + } - let m: Matches; - let cmd = match &args[0][..] { + let cmd = match subcommand.as_str() { "build" => { - m = parse(&opts); - Subcommand::Build { paths: remaining_as_path(&m) } + Subcommand::Build { paths: paths } } "test" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Test { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Bench { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } + Subcommand::Doc { paths: paths } } "clean" => { - m = parse(&opts); - if m.free.len() > 0 { - println!("clean takes no arguments"); - usage(1, &opts); + if matches.free.len() > 0 { + println!("\nclean takes no arguments\n"); + usage(1, &opts, &subcommand_help, &extra_help); } Subcommand::Clean } "dist" => { - opts.optflag("", "install", "run installer as well"); - m = parse(&opts); Subcommand::Dist { - paths: remaining_as_path(&m), - install: m.opt_present("install"), + paths: paths, + install: matches.opt_present("install"), } } - "--help" => usage(0, &opts), _ => { - usage(1, &opts); + usage(1, &opts, &subcommand_help, &extra_help); } }; - let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { + let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { Some(PathBuf::from("config.toml")) } else { @@ -272,31 +262,29 @@ Arguments: } }); - let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap()); - - let incremental = m.opt_present("i"); + let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); - if incremental { + if matches.opt_present("incremental") { if stage.is_none() { stage = Some(1); } } Flags { - verbose: m.opt_count("v"), + verbose: matches.opt_count("verbose"), stage: stage, - on_fail: m.opt_str("on-fail"), - keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap_or_else(|| { + on_fail: matches.opt_str("on-fail"), + keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), + build: matches.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() }), - host: split(m.opt_strs("host")), - target: split(m.opt_strs("target")), + host: split(matches.opt_strs("host")), + target: split(matches.opt_strs("target")), config: cfg_file, - src: m.opt_str("src").map(PathBuf::from), - jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), + src: matches.opt_str("src").map(PathBuf::from), + jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, - incremental: incremental, + incremental: matches.opt_present("incremental"), } } } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6eb12fed5abb2..5560b5b0333c8 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -978,26 +978,25 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } } - pub fn print_help(&self, command: &str) { + pub fn get_help(&self, command: &str) -> Option { let kind = match command { "build" => Kind::Build, "doc" => Kind::Doc, "test" => Kind::Test, "bench" => Kind::Bench, "dist" => Kind::Dist, - _ => return, + _ => return None, }; let rules = self.rules.values().filter(|r| r.kind == kind); let rules = rules.filter(|r| !r.path.contains("nowhere")); let mut rules = rules.collect::>(); rules.sort_by_key(|r| r.path); - println!("Available paths:\n"); + let mut help_string = String::from("Available paths:\n"); for rule in rules { - print!(" ./x.py {} {}", command, rule.path); - - println!(""); + help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str()); } + Some(help_string) } /// Construct the top-level build steps that we're going to be executing, From 2c9ae48149cb714e7cfd49c038af9b54e261da44 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 1 Apr 2017 23:16:46 -0600 Subject: [PATCH 467/662] Oops, we can't parse options until all options have been defined. Tiny bit of manual arg-parsing. Fixed tidy stuff too. --- src/bootstrap/flags.rs | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index e60e279876c37..9b45246bc5002 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -113,31 +113,28 @@ To learn more about a subcommand, run `./x.py -h`"); process::exit(exit_code); }; - // Get subcommand - let matches = opts.parse(&args[..]).unwrap_or_else(|e| { - // Invalid argument/option format - println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); - }); - let subcommand = match matches.free.get(0) { - Some(s) => { s }, - None => { - // No subcommand -- lets only show the general usage and subcommand help in this case. + // We can't use getopt to parse the options until we have completed specifying which + // options are valid, but under the current implementation, some options are conditional on + // the subcommand. Therefore we must manually identify the subcommand first, so that we can + // complete the definition of the options. Then we can use the getopt::Matches object from + // there on out. + let mut possible_subcommands = args.iter().collect::>(); + possible_subcommands.retain(|&s| !s.starts_with('-')); + let subcommand = match possible_subcommands.first() { + Some(s) => s, + None => { + // No subcommand -- show the general usage and subcommand help println!("{}\n", subcommand_help); process::exit(0); } }; - // Get any optional paths which occur after the subcommand - let cwd = t!(env::current_dir()); - let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); - // Some subcommands have specific arguments help text match subcommand.as_str() { "build" => { subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of paths to directories to the crates + This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: ./x.py build src/libcore @@ -195,6 +192,17 @@ Arguments: _ => { } }; + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Get any optional paths which occur after the subcommand + let cwd = t!(env::current_dir()); + let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); + + // All subcommands can have an optional "Available paths" section if matches.opt_present("verbose") { let flags = Flags::parse(&["build".to_string()]); From 6b7258670f606e6951e3ad34c02a598d595dfa6e Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 2 Apr 2017 10:28:36 -0600 Subject: [PATCH 468/662] Simplify a "use" statement as per @grunweg's feedback. --- src/bootstrap/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 9b45246bc5002..c374d27fe4f3e 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Options}; +use getopts::Options; use Build; use config::Config; From 1e5389853ca3a99a338f3a40cbb96150f711410c Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 2 Apr 2017 13:11:53 -0600 Subject: [PATCH 469/662] Fix breaking the 'clean' subcommand caused replacing a single-letter variable with the same value in two contexts where it was used differently. That's why you don't use "m" as a variable for hundreds of lines in an outer function, and re-use it in closures several times in the same function. Sheesh. --- src/bootstrap/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c374d27fe4f3e..2e133664a05b3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -244,7 +244,7 @@ Arguments: Subcommand::Doc { paths: paths } } "clean" => { - if matches.free.len() > 0 { + if paths.len() > 0 { println!("\nclean takes no arguments\n"); usage(1, &opts, &subcommand_help, &extra_help); } From efd6eab366ad44ac6e9b0b12cd4b9688ab71df6d Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 2 Apr 2017 16:26:43 -0600 Subject: [PATCH 470/662] Handle symlinks in src/bootstrap/clean.rs (mostly) -- resolves #40860. The broken condition can be replicated with: ``shell export MYARCH=x86_64-apple-darwin && mkdir -p build/$MYARCH/subdir && touch build/$MYARCH/subdir/file && ln -s build/$MYARCH/subdir/file build/$MYARCH/subdir/symlink `` `src/bootstrap/clean.rs` has a custom implementation of removing a tree `fn rm_rf` that used `std::path::Path::{is_file, is_dir, exists}` while recursively deleting directories and files. Unfortunately, `Path`'s implementation of `is_file()` and `is_dir()` and `exists()` always unconditionally follow symlinks, which is the exact opposite of standard implementations of deleting file trees. It appears that this custom implementation is being used to workaround a behavior in Windows where the files often get marked as read-only, which prevents us from simply using something nice and simple like `std::fs::remove_dir_all`, which properly deletes links instead of following them. So it looks like the fix is to use `.symlink_metadata()` to figure out whether tree items are files/symlinks/directories. The one corner case this won't cover is if there is a broken symlink in the "root" `build/$MYARCH` directory, because those initial entries are run through `Path::canonicalize()`, which panics with broken symlinks. So lets just never use symlinks in that one directory. :-) --- src/bootstrap/clean.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index e9547ee42d077..308a0ab3076dd 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -44,26 +44,25 @@ pub fn clean(build: &Build) { } fn rm_rf(path: &Path) { - if !path.exists() { - return - } - if path.is_file() { - return do_op(path, "remove file", |p| fs::remove_file(p)); - } - - for file in t!(fs::read_dir(path)) { - let file = t!(file).path(); + match path.symlink_metadata() { + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return; + } + panic!("failed to get metadata for file {}: {}", path.display(), e); + }, + Ok(metadata) => { + if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + do_op(path, "remove file", |p| fs::remove_file(p)); + return; + } - if file.is_dir() { - rm_rf(&file); - } else { - // On windows we can't remove a readonly file, and git will - // often clone files as readonly. As a result, we have some - // special logic to remove readonly files on windows. - do_op(&file, "remove file", |p| fs::remove_file(p)); - } - } - do_op(path, "remove dir", |p| fs::remove_dir(p)); + for file in t!(fs::read_dir(path)) { + rm_rf(&t!(file).path()); + } + do_op(path, "remove dir", |p| fs::remove_dir(p)); + }, + }; } fn do_op(path: &Path, desc: &str, mut f: F) @@ -71,9 +70,12 @@ fn do_op(path: &Path, desc: &str, mut f: F) { match f(path) { Ok(()) => {} + // On windows we can't remove a readonly file, and git will often clone files as readonly. + // As a result, we have some special logic to remove readonly files on windows. + // This is also the reason that we can't use things like fs::remove_dir_all(). Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => { - let mut p = t!(path.metadata()).permissions(); + let mut p = t!(path.symlink_metadata()).permissions(); p.set_readonly(false); t!(fs::set_permissions(path, p)); f(path).unwrap_or_else(|e| { From 29a6a9e8d23e9dc178851f0bc49e2b46afcc8c49 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 3 Apr 2017 02:03:12 +0200 Subject: [PATCH 471/662] iter: Use underlying find/rfind for the same methods in Rev --- src/libcore/iter/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 04394e0a3a876..273f9d0e6f6d3 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -358,12 +358,24 @@ impl Iterator for Rev where I: DoubleEndedIterator { fn next(&mut self) -> Option<::Item> { self.iter.next_back() } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + fn find

    (&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.rfind(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option<::Item> { self.iter.next() } + + fn rfind

    (&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.find(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] From 74f8ea263e119f947264f373229a8f1a940ae877 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 3 Apr 2017 02:03:12 +0200 Subject: [PATCH 472/662] iter: Simplification in rfind's provided implementation - Prefer simpler constructs instead of going through &mut I's Iterator implementation. --- src/libcore/iter/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 34f14ef53f893..798dda1992813 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -467,7 +467,7 @@ pub trait DoubleEndedIterator: Iterator { Self: Sized, P: FnMut(&Self::Item) -> bool { - for x in self.by_ref().rev() { + while let Some(x) = self.next_back() { if predicate(&x) { return Some(x) } } None From 7b89bd7ccacd0908d7e22a5cf383c8cc147bc3d5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 31 Mar 2017 13:52:46 +0100 Subject: [PATCH 473/662] Add ptr::offset_to --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/offset-to.md | 7 +++ src/libcollections/lib.rs | 1 + src/libcollections/vec.rs | 12 ++-- src/libcore/ptr.rs | 76 ++++++++++++++++++++++++++ src/libcore/slice/mod.rs | 7 ++- 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 src/doc/unstable-book/src/offset-to.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index fe491d7f9018e..0c3b7990c93b8 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -123,6 +123,7 @@ - [no_debug](no-debug.md) - [non_ascii_idents](non-ascii-idents.md) - [nonzero](nonzero.md) +- [offset_to](offset-to.md) - [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md) - [on_unimplemented](on-unimplemented.md) - [once_poison](once-poison.md) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md new file mode 100644 index 0000000000000..376f3ff5d2199 --- /dev/null +++ b/src/doc/unstable-book/src/offset-to.md @@ -0,0 +1,7 @@ +# `offset_to` + +The tracking issue for this feature is: [#0] + +[#0]: https://github.com/rust-lang/rust/issues/0 + +------------------------ diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa9..2b345e3d0a59f 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -61,6 +61,7 @@ #![feature(unique)] #![feature(untagged_unions)] #![cfg_attr(test, feature(rand, test))] +#![feature(offset_to)] #![no_std] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e00341..f12380a9ea535 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2073,14 +2073,10 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { - let diff = (self.end as usize) - (self.ptr as usize); - let size = mem::size_of::(); - let exact = diff / - (if size == 0 { - 1 - } else { - size - }); + let exact = match self.ptr.offset_to(self.end) { + Some(x) => x as usize, + None => (self.end as usize).wrapping_sub(self.ptr as usize), + }; (exact, Some(exact)) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d2830a6d00cec..6bcce76af04e3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -500,6 +500,44 @@ impl *const T { intrinsics::arith_offset(self, count) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "0")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option where T: Sized { + let size = mem::size_of::(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } #[lang = "mut_ptr"] @@ -653,6 +691,44 @@ impl *mut T { Some(&mut *self) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "0")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option where T: Sized { + let size = mem::size_of::(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } // Equality for pointers diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index af492b3c63976..5a978ccc74153 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1502,9 +1502,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the arithmetic difference if `T` is zero size. #[inline(always)] fn ptrdistance(start: *const T, end: *const T) -> usize { - let diff = (end as usize).wrapping_sub(start as usize); - let size = mem::size_of::(); - diff / (if size == 0 { 1 } else { size }) + match start.offset_to(end) { + Some(x) => x as usize, + None => (end as usize).wrapping_sub(start as usize), + } } // Extension methods for raw pointers, used by the iterators From 282029526646fc93cd8bc098191c4e110a4c4938 Mon Sep 17 00:00:00 2001 From: "Stephen M. Coakley" Date: Sat, 1 Apr 2017 22:17:59 -0500 Subject: [PATCH 474/662] Derive Hash for ThreadId + better example --- src/libstd/thread/mod.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index edf928d61063e..21f9757ad116b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -652,8 +652,8 @@ pub fn park_timeout(dur: Duration) { /// A unique identifier for a running thread. /// /// A `ThreadId` is an opaque object that has a unique value for each thread -/// that creates one. `ThreadId`s do not correspond to a thread's system- -/// designated identifier. +/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's +/// system-designated identifier. /// /// # Examples /// @@ -662,17 +662,15 @@ pub fn park_timeout(dur: Duration) { /// /// use std::thread; /// -/// let handler = thread::Builder::new() -/// .spawn(|| { -/// let thread = thread::current(); -/// let thread_id = thread.id(); -/// }) -/// .unwrap(); +/// let other_thread = thread::spawn(|| { +/// thread::current().id() +/// }); /// -/// handler.join().unwrap(); +/// let other_thread_id = other_thread.join().unwrap(); +/// assert!(thread::current().id() != other_thread_id); /// ``` #[unstable(feature = "thread_id", issue = "21507")] -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Clone, Copy, Eq, PartialEq, Hash)] pub struct ThreadId(u64); impl ThreadId { @@ -795,14 +793,12 @@ impl Thread { /// /// use std::thread; /// - /// let handler = thread::Builder::new() - /// .spawn(|| { - /// let thread = thread::current(); - /// println!("thread id: {:?}", thread.id()); - /// }) - /// .unwrap(); + /// let other_thread = thread::spawn(|| { + /// thread::current().id() + /// }); /// - /// handler.join().unwrap(); + /// let other_thread_id = other_thread.join().unwrap(); + /// assert!(thread::current().id() != other_thread_id); /// ``` #[unstable(feature = "thread_id", issue = "21507")] pub fn id(&self) -> ThreadId { From 9c1b7ae3f37a34a39f837ad8ae90da3fad052798 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Mon, 3 Apr 2017 10:14:10 -0400 Subject: [PATCH 475/662] Revert "Implement AsRawFd/IntoRawFd for RawFd" This reverts commit 2cf686f2cdd6446a3cd47df0305ead40fabe85df (#40842) RawFd is a type alias for c_int, which is itself a type alias for i32. As a result, adding AsRawFd and IntoRawFd impls for RawFd actually adds them for i32. As a result, the reverted commit makes this valid: ``` use std::os::unix::io::AsRawFd; fn arf(_: T) {} fn main() { arf(32i32) } ``` Implimenting AsRawFd and IntoRawFd for i32 breaks the promises of both those traits that their methods return a valid RawFd. r? @aturon cc @Mic92 @kamalmarhubi --- src/libstd/sys/unix/ext/io.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 75aa72e3cff8c..296235e173d13 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -72,13 +72,6 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for RawFd { - fn as_raw_fd(&self) -> RawFd { - *self - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -91,14 +84,6 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for RawFd { - fn into_raw_fd(self) -> RawFd { - self - } -} - #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { fn into_raw_fd(self) -> RawFd { From f74ca38686e84542657136bd063f8042d9bbb641 Mon Sep 17 00:00:00 2001 From: mandeep Date: Mon, 3 Apr 2017 09:51:34 -0500 Subject: [PATCH 476/662] Refactored swap_remove doc comment upon discussing with BurntSushi and steveklabnik --- src/libcollections/vec.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 44ac4f1cff588..8a3fa94d4c1ea 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -678,8 +678,9 @@ impl Vec { self.len = len; } - /// Removes an element from anywhere in the vector and returns it, replacing - /// it with the last element. + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is O(1). /// From e7c2160f8a36468c38a0c4d9fb2a71bd6c4fefd8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Mar 2017 18:32:17 +0100 Subject: [PATCH 477/662] Fix mutex's docs inconsistency --- src/libstd/sync/mutex.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index d79be2944c9e3..f2c178a1ad503 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -30,7 +30,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// /// The mutexes in this module implement a strategy called "poisoning" where a /// mutex is considered poisoned whenever a thread panics while holding the -/// lock. Once a mutex is poisoned, all other threads are unable to access the +/// mutex. Once a mutex is poisoned, all other threads are unable to access the /// data by default as it is likely tainted (some invariant is not being /// upheld). /// @@ -115,7 +115,7 @@ pub struct Mutex { // Note that this mutex is in a *box*, not inlined into the struct itself. // Once a native mutex has been used once, its address can never change (it // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner lock to + // ensure that the native mutex is used correctly we box the inner mutex to // give it a constant address. inner: Box, poison: poison::Flag, @@ -183,7 +183,7 @@ impl Mutex { /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the local thread until it is available to acquire - /// the mutex. Upon returning, the thread is the only thread with the mutex + /// the mutex. Upon returning, the thread is the only thread with the lock /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// @@ -267,9 +267,9 @@ impl Mutex { } } - /// Determines whether the lock is poisoned. + /// Determines whether the mutex is poisoned. /// - /// If another thread is active, the lock can still become poisoned at any + /// If another thread is active, the mutex can still become poisoned at any /// time. You should not trust a `false` value for program correctness /// without additional synchronization. /// @@ -312,7 +312,7 @@ impl Mutex { #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult where T: Sized { // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. + // `self` so there's no need to lock the inner mutex. // // To get the inner value, we'd like to call `data.into_inner()`, // but because `Mutex` impl-s `Drop`, we can't move out of it, so @@ -353,7 +353,7 @@ impl Mutex { #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. + // there's no need to lock the inner mutex. let data = unsafe { &mut *self.data.get() }; poison::map_result(self.poison.borrow(), |_| data ) } From 73f6f5e0968ebe032a0730e2e3dfccea5a61c384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Apr 2017 07:46:35 -0700 Subject: [PATCH 478/662] Sort enum suggestions --- src/librustc_resolve/lib.rs | 14 ++++++++------ src/test/ui/did_you_mean/issue-35675.stderr | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a39cd3b0d551c..e191fadc01beb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2273,15 +2273,17 @@ impl<'a> Resolver<'a> { show_candidates(&mut err, &candidates, def.is_some()); } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); - for suggestion in enum_candidates { - let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); + enum_candidates.sort(); + for (sp, variant_path, enum_path) in enum_candidates { let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", variant_path, enum_path); - if suggestion.path.span == DUMMY_SP { + if sp == DUMMY_SP { err.help(&msg); } else { - err.span_help(suggestion.path.span, &msg); + err.span_help(sp, &msg); } } } @@ -3437,7 +3439,7 @@ fn path_names_to_string(path: &Path) -> String { } /// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) { let variant_path = &suggestion.path; let variant_path_string = path_names_to_string(variant_path); @@ -3448,7 +3450,7 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) }; let enum_path_string = path_names_to_string(&enum_path); - (variant_path_string, enum_path_string) + (suggestion.path.span, variant_path_string, enum_path_string) } diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr index 43851d76029df..3d615785b25fa 100644 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -46,8 +46,8 @@ error[E0573]: expected type, found variant `Ok` 24 | fn foo() -> Ok { | ^^ not a type | - = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? error[E0412]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:28:13 @@ -67,8 +67,8 @@ error[E0573]: expected type, found variant `Some` 31 | fn qux() -> Some { | ^^^^ not a type | - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? error: aborting due to 7 previous errors From 13c744f30d1540f36a6437224d16e3aea0a2ff71 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 3 Apr 2017 16:53:04 +0200 Subject: [PATCH 479/662] Move libXtest into libX/tests This change moves: 1. `libcoretest` into `libcore/tests` 2. `libcollectionstest` into `libcollections/tests` This is a follow-up to #39561. --- src/libcollections/Cargo.toml | 4 ++-- .../tests}/binary_heap.rs | 0 src/{libcollectionstest => libcollections/tests}/btree/map.rs | 0 src/{libcollectionstest => libcollections/tests}/btree/mod.rs | 0 src/{libcollectionstest => libcollections/tests}/btree/set.rs | 0 src/{libcollectionstest => libcollections/tests}/cow_str.rs | 0 src/{libcollectionstest => libcollections/tests}/fmt.rs | 0 src/{libcollectionstest => libcollections/tests}/lib.rs | 0 .../tests}/linked_list.rs | 0 src/{libcollectionstest => libcollections/tests}/slice.rs | 0 src/{libcollectionstest => libcollections/tests}/str.rs | 0 src/{libcollectionstest => libcollections/tests}/string.rs | 0 src/{libcollectionstest => libcollections/tests}/vec.rs | 0 src/{libcollectionstest => libcollections/tests}/vec_deque.rs | 0 src/libcore/Cargo.toml | 4 ++-- src/libcore/num/bignum.rs | 2 +- src/libcore/num/diy_float.rs | 2 +- src/libcore/num/flt2dec/mod.rs | 2 +- src/libcore/num/mod.rs | 2 +- src/{libcoretest => libcore/tests}/any.rs | 0 src/{libcoretest => libcore/tests}/array.rs | 0 src/{libcoretest => libcore/tests}/atomic.rs | 0 src/{libcoretest => libcore/tests}/cell.rs | 0 src/{libcoretest => libcore/tests}/char.rs | 0 src/{libcoretest => libcore/tests}/clone.rs | 0 src/{libcoretest => libcore/tests}/cmp.rs | 0 src/{libcoretest => libcore/tests}/fmt/builders.rs | 0 src/{libcoretest => libcore/tests}/fmt/float.rs | 0 src/{libcoretest => libcore/tests}/fmt/mod.rs | 0 src/{libcoretest => libcore/tests}/fmt/num.rs | 0 src/{libcoretest => libcore/tests}/hash/mod.rs | 0 src/{libcoretest => libcore/tests}/hash/sip.rs | 0 src/{libcoretest => libcore/tests}/intrinsics.rs | 0 src/{libcoretest => libcore/tests}/iter.rs | 0 src/{libcoretest => libcore/tests}/lib.rs | 0 src/{libcoretest => libcore/tests}/mem.rs | 0 src/{libcoretest => libcore/tests}/nonzero.rs | 0 src/{libcoretest => libcore/tests}/num/bignum.rs | 0 src/{libcoretest => libcore/tests}/num/dec2flt/mod.rs | 0 src/{libcoretest => libcore/tests}/num/dec2flt/parse.rs | 0 src/{libcoretest => libcore/tests}/num/dec2flt/rawfp.rs | 0 src/{libcoretest => libcore/tests}/num/flt2dec/estimator.rs | 0 src/{libcoretest => libcore/tests}/num/flt2dec/mod.rs | 0 .../tests}/num/flt2dec/strategy/dragon.rs | 0 .../tests}/num/flt2dec/strategy/grisu.rs | 0 src/{libcoretest => libcore/tests}/num/i16.rs | 0 src/{libcoretest => libcore/tests}/num/i32.rs | 0 src/{libcoretest => libcore/tests}/num/i64.rs | 0 src/{libcoretest => libcore/tests}/num/i8.rs | 0 src/{libcoretest => libcore/tests}/num/int_macros.rs | 0 src/{libcoretest => libcore/tests}/num/mod.rs | 0 src/{libcoretest => libcore/tests}/num/u16.rs | 0 src/{libcoretest => libcore/tests}/num/u32.rs | 0 src/{libcoretest => libcore/tests}/num/u64.rs | 0 src/{libcoretest => libcore/tests}/num/u8.rs | 0 src/{libcoretest => libcore/tests}/num/uint_macros.rs | 0 src/{libcoretest => libcore/tests}/ops.rs | 0 src/{libcoretest => libcore/tests}/option.rs | 0 src/{libcoretest => libcore/tests}/ptr.rs | 0 src/{libcoretest => libcore/tests}/result.rs | 0 src/{libcoretest => libcore/tests}/slice.rs | 0 src/{libcoretest => libcore/tests}/str.rs | 2 +- src/{libcoretest => libcore/tests}/tuple.rs | 0 src/tools/tidy/src/pal.rs | 2 +- 64 files changed, 10 insertions(+), 10 deletions(-) rename src/{libcollectionstest => libcollections/tests}/binary_heap.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/map.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/mod.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/set.rs (100%) rename src/{libcollectionstest => libcollections/tests}/cow_str.rs (100%) rename src/{libcollectionstest => libcollections/tests}/fmt.rs (100%) rename src/{libcollectionstest => libcollections/tests}/lib.rs (100%) rename src/{libcollectionstest => libcollections/tests}/linked_list.rs (100%) rename src/{libcollectionstest => libcollections/tests}/slice.rs (100%) rename src/{libcollectionstest => libcollections/tests}/str.rs (100%) rename src/{libcollectionstest => libcollections/tests}/string.rs (100%) rename src/{libcollectionstest => libcollections/tests}/vec.rs (100%) rename src/{libcollectionstest => libcollections/tests}/vec_deque.rs (100%) rename src/{libcoretest => libcore/tests}/any.rs (100%) rename src/{libcoretest => libcore/tests}/array.rs (100%) rename src/{libcoretest => libcore/tests}/atomic.rs (100%) rename src/{libcoretest => libcore/tests}/cell.rs (100%) rename src/{libcoretest => libcore/tests}/char.rs (100%) rename src/{libcoretest => libcore/tests}/clone.rs (100%) rename src/{libcoretest => libcore/tests}/cmp.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/builders.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/float.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/mod.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/num.rs (100%) rename src/{libcoretest => libcore/tests}/hash/mod.rs (100%) rename src/{libcoretest => libcore/tests}/hash/sip.rs (100%) rename src/{libcoretest => libcore/tests}/intrinsics.rs (100%) rename src/{libcoretest => libcore/tests}/iter.rs (100%) rename src/{libcoretest => libcore/tests}/lib.rs (100%) rename src/{libcoretest => libcore/tests}/mem.rs (100%) rename src/{libcoretest => libcore/tests}/nonzero.rs (100%) rename src/{libcoretest => libcore/tests}/num/bignum.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/parse.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/rawfp.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/estimator.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/strategy/dragon.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/strategy/grisu.rs (100%) rename src/{libcoretest => libcore/tests}/num/i16.rs (100%) rename src/{libcoretest => libcore/tests}/num/i32.rs (100%) rename src/{libcoretest => libcore/tests}/num/i64.rs (100%) rename src/{libcoretest => libcore/tests}/num/i8.rs (100%) rename src/{libcoretest => libcore/tests}/num/int_macros.rs (100%) rename src/{libcoretest => libcore/tests}/num/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/u16.rs (100%) rename src/{libcoretest => libcore/tests}/num/u32.rs (100%) rename src/{libcoretest => libcore/tests}/num/u64.rs (100%) rename src/{libcoretest => libcore/tests}/num/u8.rs (100%) rename src/{libcoretest => libcore/tests}/num/uint_macros.rs (100%) rename src/{libcoretest => libcore/tests}/ops.rs (100%) rename src/{libcoretest => libcore/tests}/option.rs (100%) rename src/{libcoretest => libcore/tests}/ptr.rs (100%) rename src/{libcoretest => libcore/tests}/result.rs (100%) rename src/{libcoretest => libcore/tests}/slice.rs (100%) rename src/{libcoretest => libcore/tests}/str.rs (90%) rename src/{libcoretest => libcore/tests}/tuple.rs (100%) diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 02b2171a224d0..7e92404bc0d6f 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -13,8 +13,8 @@ core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } [[test]] -name = "collectionstest" -path = "../libcollectionstest/lib.rs" +name = "collectionstests" +path = "../libcollections/tests/lib.rs" [[bench]] name = "collectionsbenches" diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollections/tests/binary_heap.rs similarity index 100% rename from src/libcollectionstest/binary_heap.rs rename to src/libcollections/tests/binary_heap.rs diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollections/tests/btree/map.rs similarity index 100% rename from src/libcollectionstest/btree/map.rs rename to src/libcollections/tests/btree/map.rs diff --git a/src/libcollectionstest/btree/mod.rs b/src/libcollections/tests/btree/mod.rs similarity index 100% rename from src/libcollectionstest/btree/mod.rs rename to src/libcollections/tests/btree/mod.rs diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollections/tests/btree/set.rs similarity index 100% rename from src/libcollectionstest/btree/set.rs rename to src/libcollections/tests/btree/set.rs diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollections/tests/cow_str.rs similarity index 100% rename from src/libcollectionstest/cow_str.rs rename to src/libcollections/tests/cow_str.rs diff --git a/src/libcollectionstest/fmt.rs b/src/libcollections/tests/fmt.rs similarity index 100% rename from src/libcollectionstest/fmt.rs rename to src/libcollections/tests/fmt.rs diff --git a/src/libcollectionstest/lib.rs b/src/libcollections/tests/lib.rs similarity index 100% rename from src/libcollectionstest/lib.rs rename to src/libcollections/tests/lib.rs diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollections/tests/linked_list.rs similarity index 100% rename from src/libcollectionstest/linked_list.rs rename to src/libcollections/tests/linked_list.rs diff --git a/src/libcollectionstest/slice.rs b/src/libcollections/tests/slice.rs similarity index 100% rename from src/libcollectionstest/slice.rs rename to src/libcollections/tests/slice.rs diff --git a/src/libcollectionstest/str.rs b/src/libcollections/tests/str.rs similarity index 100% rename from src/libcollectionstest/str.rs rename to src/libcollections/tests/str.rs diff --git a/src/libcollectionstest/string.rs b/src/libcollections/tests/string.rs similarity index 100% rename from src/libcollectionstest/string.rs rename to src/libcollections/tests/string.rs diff --git a/src/libcollectionstest/vec.rs b/src/libcollections/tests/vec.rs similarity index 100% rename from src/libcollectionstest/vec.rs rename to src/libcollections/tests/vec.rs diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollections/tests/vec_deque.rs similarity index 100% rename from src/libcollectionstest/vec_deque.rs rename to src/libcollections/tests/vec_deque.rs diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index e847c7fa3a0ec..5af63aa970f2c 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -10,8 +10,8 @@ test = false bench = false [[test]] -name = "coretest" -path = "../libcoretest/lib.rs" +name = "coretests" +path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 8904322ca48f7..b5553fb29475b 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -19,7 +19,7 @@ //! inputs, but we don't do so to avoid the code bloat. Each bignum is still //! tracked for the actual usages, so it normally doesn't matter. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_bignum", diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs index 11eea753f93f9..6635d95155f4b 100644 --- a/src/libcore/num/diy_float.rs +++ b/src/libcore/num/diy_float.rs @@ -10,7 +10,7 @@ //! Extended precision "soft float", for internal use only. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_diy_float", diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index f6c03a59f81e4..5123e42df61ca 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -118,7 +118,7 @@ provide a large enough buffer and `Part` array, and to assemble the final string from resulting `Part`s itself. All algorithms and formatting functions are accompanied by extensive tests -in `coretest::num::flt2dec` module. It also shows how to use individual +in `coretests::num::flt2dec` module. It also shows how to use individual functions. */ diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index df343c9d45f20..f665cfdee77ae 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -90,7 +90,7 @@ impl fmt::UpperHex for Wrapping { mod wrapping; -// All these modules are technically private and only exposed for libcoretest: +// All these modules are technically private and only exposed for coretests: pub mod flt2dec; pub mod dec2flt; pub mod bignum; diff --git a/src/libcoretest/any.rs b/src/libcore/tests/any.rs similarity index 100% rename from src/libcoretest/any.rs rename to src/libcore/tests/any.rs diff --git a/src/libcoretest/array.rs b/src/libcore/tests/array.rs similarity index 100% rename from src/libcoretest/array.rs rename to src/libcore/tests/array.rs diff --git a/src/libcoretest/atomic.rs b/src/libcore/tests/atomic.rs similarity index 100% rename from src/libcoretest/atomic.rs rename to src/libcore/tests/atomic.rs diff --git a/src/libcoretest/cell.rs b/src/libcore/tests/cell.rs similarity index 100% rename from src/libcoretest/cell.rs rename to src/libcore/tests/cell.rs diff --git a/src/libcoretest/char.rs b/src/libcore/tests/char.rs similarity index 100% rename from src/libcoretest/char.rs rename to src/libcore/tests/char.rs diff --git a/src/libcoretest/clone.rs b/src/libcore/tests/clone.rs similarity index 100% rename from src/libcoretest/clone.rs rename to src/libcore/tests/clone.rs diff --git a/src/libcoretest/cmp.rs b/src/libcore/tests/cmp.rs similarity index 100% rename from src/libcoretest/cmp.rs rename to src/libcore/tests/cmp.rs diff --git a/src/libcoretest/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs similarity index 100% rename from src/libcoretest/fmt/builders.rs rename to src/libcore/tests/fmt/builders.rs diff --git a/src/libcoretest/fmt/float.rs b/src/libcore/tests/fmt/float.rs similarity index 100% rename from src/libcoretest/fmt/float.rs rename to src/libcore/tests/fmt/float.rs diff --git a/src/libcoretest/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs similarity index 100% rename from src/libcoretest/fmt/mod.rs rename to src/libcore/tests/fmt/mod.rs diff --git a/src/libcoretest/fmt/num.rs b/src/libcore/tests/fmt/num.rs similarity index 100% rename from src/libcoretest/fmt/num.rs rename to src/libcore/tests/fmt/num.rs diff --git a/src/libcoretest/hash/mod.rs b/src/libcore/tests/hash/mod.rs similarity index 100% rename from src/libcoretest/hash/mod.rs rename to src/libcore/tests/hash/mod.rs diff --git a/src/libcoretest/hash/sip.rs b/src/libcore/tests/hash/sip.rs similarity index 100% rename from src/libcoretest/hash/sip.rs rename to src/libcore/tests/hash/sip.rs diff --git a/src/libcoretest/intrinsics.rs b/src/libcore/tests/intrinsics.rs similarity index 100% rename from src/libcoretest/intrinsics.rs rename to src/libcore/tests/intrinsics.rs diff --git a/src/libcoretest/iter.rs b/src/libcore/tests/iter.rs similarity index 100% rename from src/libcoretest/iter.rs rename to src/libcore/tests/iter.rs diff --git a/src/libcoretest/lib.rs b/src/libcore/tests/lib.rs similarity index 100% rename from src/libcoretest/lib.rs rename to src/libcore/tests/lib.rs diff --git a/src/libcoretest/mem.rs b/src/libcore/tests/mem.rs similarity index 100% rename from src/libcoretest/mem.rs rename to src/libcore/tests/mem.rs diff --git a/src/libcoretest/nonzero.rs b/src/libcore/tests/nonzero.rs similarity index 100% rename from src/libcoretest/nonzero.rs rename to src/libcore/tests/nonzero.rs diff --git a/src/libcoretest/num/bignum.rs b/src/libcore/tests/num/bignum.rs similarity index 100% rename from src/libcoretest/num/bignum.rs rename to src/libcore/tests/num/bignum.rs diff --git a/src/libcoretest/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs similarity index 100% rename from src/libcoretest/num/dec2flt/mod.rs rename to src/libcore/tests/num/dec2flt/mod.rs diff --git a/src/libcoretest/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs similarity index 100% rename from src/libcoretest/num/dec2flt/parse.rs rename to src/libcore/tests/num/dec2flt/parse.rs diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs similarity index 100% rename from src/libcoretest/num/dec2flt/rawfp.rs rename to src/libcore/tests/num/dec2flt/rawfp.rs diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs similarity index 100% rename from src/libcoretest/num/flt2dec/estimator.rs rename to src/libcore/tests/num/flt2dec/estimator.rs diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs similarity index 100% rename from src/libcoretest/num/flt2dec/mod.rs rename to src/libcore/tests/num/flt2dec/mod.rs diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs similarity index 100% rename from src/libcoretest/num/flt2dec/strategy/dragon.rs rename to src/libcore/tests/num/flt2dec/strategy/dragon.rs diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs similarity index 100% rename from src/libcoretest/num/flt2dec/strategy/grisu.rs rename to src/libcore/tests/num/flt2dec/strategy/grisu.rs diff --git a/src/libcoretest/num/i16.rs b/src/libcore/tests/num/i16.rs similarity index 100% rename from src/libcoretest/num/i16.rs rename to src/libcore/tests/num/i16.rs diff --git a/src/libcoretest/num/i32.rs b/src/libcore/tests/num/i32.rs similarity index 100% rename from src/libcoretest/num/i32.rs rename to src/libcore/tests/num/i32.rs diff --git a/src/libcoretest/num/i64.rs b/src/libcore/tests/num/i64.rs similarity index 100% rename from src/libcoretest/num/i64.rs rename to src/libcore/tests/num/i64.rs diff --git a/src/libcoretest/num/i8.rs b/src/libcore/tests/num/i8.rs similarity index 100% rename from src/libcoretest/num/i8.rs rename to src/libcore/tests/num/i8.rs diff --git a/src/libcoretest/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs similarity index 100% rename from src/libcoretest/num/int_macros.rs rename to src/libcore/tests/num/int_macros.rs diff --git a/src/libcoretest/num/mod.rs b/src/libcore/tests/num/mod.rs similarity index 100% rename from src/libcoretest/num/mod.rs rename to src/libcore/tests/num/mod.rs diff --git a/src/libcoretest/num/u16.rs b/src/libcore/tests/num/u16.rs similarity index 100% rename from src/libcoretest/num/u16.rs rename to src/libcore/tests/num/u16.rs diff --git a/src/libcoretest/num/u32.rs b/src/libcore/tests/num/u32.rs similarity index 100% rename from src/libcoretest/num/u32.rs rename to src/libcore/tests/num/u32.rs diff --git a/src/libcoretest/num/u64.rs b/src/libcore/tests/num/u64.rs similarity index 100% rename from src/libcoretest/num/u64.rs rename to src/libcore/tests/num/u64.rs diff --git a/src/libcoretest/num/u8.rs b/src/libcore/tests/num/u8.rs similarity index 100% rename from src/libcoretest/num/u8.rs rename to src/libcore/tests/num/u8.rs diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs similarity index 100% rename from src/libcoretest/num/uint_macros.rs rename to src/libcore/tests/num/uint_macros.rs diff --git a/src/libcoretest/ops.rs b/src/libcore/tests/ops.rs similarity index 100% rename from src/libcoretest/ops.rs rename to src/libcore/tests/ops.rs diff --git a/src/libcoretest/option.rs b/src/libcore/tests/option.rs similarity index 100% rename from src/libcoretest/option.rs rename to src/libcore/tests/option.rs diff --git a/src/libcoretest/ptr.rs b/src/libcore/tests/ptr.rs similarity index 100% rename from src/libcoretest/ptr.rs rename to src/libcore/tests/ptr.rs diff --git a/src/libcoretest/result.rs b/src/libcore/tests/result.rs similarity index 100% rename from src/libcoretest/result.rs rename to src/libcore/tests/result.rs diff --git a/src/libcoretest/slice.rs b/src/libcore/tests/slice.rs similarity index 100% rename from src/libcoretest/slice.rs rename to src/libcore/tests/slice.rs diff --git a/src/libcoretest/str.rs b/src/libcore/tests/str.rs similarity index 90% rename from src/libcoretest/str.rs rename to src/libcore/tests/str.rs index b7d9ba4463d98..08daafccc5404 100644 --- a/src/libcoretest/str.rs +++ b/src/libcore/tests/str.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// All `str` tests live in libcollectiontest::str +// All `str` tests live in collectionstests::str diff --git a/src/libcoretest/tuple.rs b/src/libcore/tests/tuple.rs similarity index 100% rename from src/libcoretest/tuple.rs rename to src/libcore/tests/tuple.rs diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 3808c05c6b939..0dbf0d4316abd 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -75,7 +75,7 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[ "src/libtest", // Probably should defer to unstable std::sys APIs // std testing crates, ok for now at least - "src/libcoretest", + "src/libcore/tests", // non-std crates "src/test", From 7a07a73eb15d497efcd544ec6e332160ee46dd5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 3 Apr 2017 21:17:47 +0200 Subject: [PATCH 480/662] Replace ^ with html balise --- src/libcore/intrinsics.rs | 6 +++--- src/libcore/num/dec2flt/rawfp.rs | 13 +++++++------ src/librustc/ty/layout.rs | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ae8b6bb45113..d8db450fb1c1f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1253,17 +1253,17 @@ extern "rust-intrinsic" { #[cfg(not(stage0))] pub fn unchecked_shr(x: T, y: T) -> T; - /// Returns (a + b) mod 2^N, where N is the width of T in bits. + /// Returns (a + b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) pub fn overflowing_add(a: T, b: T) -> T; - /// Returns (a - b) mod 2^N, where N is the width of T in bits. + /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) pub fn overflowing_sub(a: T, b: T) -> T; - /// Returns (a * b) mod 2^N, where N is the width of T in bits. + /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index e3b58b6cc7ce9..45fa721a5a33e 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -10,12 +10,12 @@ //! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled. //! Normal floating point numbers have a canonical representation as (frac, exp) such that the -//! value is 2^exp * (1 + sum(frac[N-i] / 2^i)) where N is the number of bits. Subnormals are -//! slightly different and weird, but the same principle applies. +//! value is 2exp * (1 + sum(frac[N-i] / 2i)) where N is the number of bits. +//! Subnormals are slightly different and weird, but the same principle applies. //! -//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * 2^e. -//! Besides making the "hidden bit" explicit, this changes the exponent by the so-called -//! mantissa shift. +//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * +//! 2e. Besides making the "hidden bit" explicit, this changes the exponent by the +//! so-called mantissa shift. //! //! Put another way, normally floats are written as (1) but here they are written as (2): //! @@ -94,7 +94,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp /// represented, the other code in this module makes sure to never let that happen. fn from_int(x: u64) -> Self; - /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig(). + /// Get the value 10e from a pre-computed table. Panics for e >= + /// ceil_log5_of_max_sig(). fn short_fast_pow10(e: usize) -> Self; // FIXME Everything that follows should be associated constants, but taking the value of an diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 123db6e89476c..571ef30b6b909 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -267,7 +267,7 @@ impl Size { /// Alignment of a type in bytes, both ABI-mandated and preferred. /// Since alignments are always powers of 2, we can pack both in one byte, -/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768. +/// giving each a nibble (4 bits) for a maximum alignment of 215 = 32768. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Align { raw: u8 From 541512b0bf71bf2d57f42a66519a927b6e2503d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Apr 2017 07:18:43 -0700 Subject: [PATCH 481/662] travis: Split all dist builders in two Previously we would use one builder on Travis to produce two sets of host compilers for two different targets. Unfortunately though we've recently increased how much we're building for each target so this is starting to take unnecessarily long (#40804). This commit splits the dist builders in two by ensuring that we only dist one target on each builder, which should take a much shorter amount of time. This should also unblock other work such as landing the RLS (#40584). --- .travis.yml | 18 ++- .../Dockerfile | 12 +- .../aarch64-linux-gnu.config | 0 .../dist-aarch64-linux/build-toolchains.sh | 37 ++++++ src/ci/docker/dist-arm-linux/Dockerfile | 9 +- .../docker/dist-arm-linux/build-toolchains.sh | 8 -- src/ci/docker/dist-armhf-linux/Dockerfile | 77 ++++++++++++ .../arm-linux-gnueabihf.config | 0 .../dist-armhf-linux/build-toolchains.sh | 37 ++++++ src/ci/docker/dist-armv7-linux/Dockerfile | 77 ++++++++++++ .../armv7-linux-gnueabihf.config | 0 .../build-toolchains.sh | 8 -- .../Dockerfile | 7 +- .../build-toolchain.sh | 0 .../Dockerfile | 1 - .../build-binutils.sh | 0 .../build-cmake.sh | 0 .../build-curl.sh | 0 .../build-gcc.sh | 0 .../build-git.sh | 0 .../build-headers.sh | 0 .../build-openssl.sh | 0 .../build-python.sh | 0 .../shared.sh | 0 src/ci/docker/dist-mips-linux/Dockerfile | 2 - src/ci/docker/dist-mips64-linux/Dockerfile | 2 - src/ci/docker/dist-mips64el-linux/Dockerfile | 31 +++++ src/ci/docker/dist-mipsel-linux/Dockerfile | 31 +++++ src/ci/docker/dist-powerpc64-linux/Dockerfile | 10 +- .../docker/dist-powerpc64le-linux/Dockerfile | 77 ++++++++++++ .../build-powerpc64le-toolchain.sh | 0 .../docker/dist-powerpc64le-linux/shared.sh | 25 ++++ .../Dockerfile | 11 +- .../build-s390x-toolchain.sh | 0 ...prevent-AS-from-complaining-about-z9.patch | 0 .../s390x-linux-gnu.config | 0 src/ci/docker/dist-x86_64-freebsd/Dockerfile | 39 ++++++ .../dist-x86_64-freebsd/build-toolchain.sh | 112 ++++++++++++++++++ src/ci/docker/dist-x86_64-linux/Dockerfile | 95 +++++++++++++++ .../dist-x86_64-linux/build-binutils.sh | 26 ++++ .../docker/dist-x86_64-linux/build-cmake.sh | 25 ++++ src/ci/docker/dist-x86_64-linux/build-curl.sh | 43 +++++++ src/ci/docker/dist-x86_64-linux/build-gcc.sh | 33 ++++++ src/ci/docker/dist-x86_64-linux/build-git.sh | 24 ++++ .../docker/dist-x86_64-linux/build-headers.sh | 25 ++++ .../docker/dist-x86_64-linux/build-openssl.sh | 27 +++++ .../docker/dist-x86_64-linux/build-python.sh | 30 +++++ src/ci/docker/dist-x86_64-linux/shared.sh | 25 ++++ src/ci/docker/dist-x86_64-netbsd/Dockerfile | 78 ++++++++++++ .../build-netbsd-toolchain.sh | 0 50 files changed, 996 insertions(+), 66 deletions(-) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-aarch64-linux}/Dockerfile (79%) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-aarch64-linux}/aarch64-linux-gnu.config (100%) create mode 100755 src/ci/docker/dist-aarch64-linux/build-toolchains.sh create mode 100644 src/ci/docker/dist-armhf-linux/Dockerfile rename src/ci/docker/{dist-arm-linux => dist-armhf-linux}/arm-linux-gnueabihf.config (100%) create mode 100755 src/ci/docker/dist-armhf-linux/build-toolchains.sh create mode 100644 src/ci/docker/dist-armv7-linux/Dockerfile rename src/ci/docker/{dist-armv7-aarch64-linux => dist-armv7-linux}/armv7-linux-gnueabihf.config (100%) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-armv7-linux}/build-toolchains.sh (88%) rename src/ci/docker/{dist-freebsd => dist-i686-freebsd}/Dockerfile (77%) rename src/ci/docker/{dist-freebsd => dist-i686-freebsd}/build-toolchain.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/Dockerfile (98%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-binutils.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-cmake.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-curl.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-gcc.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-git.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-headers.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-openssl.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-python.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/shared.sh (100%) create mode 100644 src/ci/docker/dist-mips64el-linux/Dockerfile create mode 100644 src/ci/docker/dist-mipsel-linux/Dockerfile create mode 100644 src/ci/docker/dist-powerpc64le-linux/Dockerfile rename src/ci/docker/{dist-powerpc64-linux => dist-powerpc64le-linux}/build-powerpc64le-toolchain.sh (100%) create mode 100644 src/ci/docker/dist-powerpc64le-linux/shared.sh rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/Dockerfile (83%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/build-s390x-toolchain.sh (100%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch (100%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/s390x-linux-gnu.config (100%) create mode 100644 src/ci/docker/dist-x86_64-freebsd/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh create mode 100644 src/ci/docker/dist-x86_64-linux/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-linux/build-binutils.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-cmake.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-curl.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-gcc.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-git.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-headers.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-openssl.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-python.sh create mode 100644 src/ci/docker/dist-x86_64-linux/shared.sh create mode 100644 src/ci/docker/dist-x86_64-netbsd/Dockerfile rename src/ci/docker/{dist-s390x-linux-netbsd => dist-x86_64-netbsd}/build-netbsd-toolchain.sh (100%) diff --git a/.travis.yml b/.travis.yml index 8fe92ff7d0288..a8c9337fa81b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,19 +15,27 @@ matrix: - env: IMAGE=arm-android - env: IMAGE=armhf-gnu - env: IMAGE=cross DEPLOY=1 + - env: IMAGE=dist-aarch64-linux DEPLOY=1 - env: IMAGE=dist-android DEPLOY=1 - env: IMAGE=dist-arm-linux DEPLOY=1 - - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1 - - env: IMAGE=dist-freebsd DEPLOY=1 - - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-armhf-linux DEPLOY=1 + - env: IMAGE=dist-armv7-linux DEPLOY=1 - env: IMAGE=dist-fuchsia DEPLOY=1 + - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-i686-freebsd DEPLOY=1 + - env: IMAGE=dist-i686-linux DEPLOY=1 - env: IMAGE=dist-mips-linux DEPLOY=1 - env: IMAGE=dist-mips64-linux DEPLOY=1 + - env: IMAGE=dist-mips64el-linux DEPLOY=1 + - env: IMAGE=dist-mipsel-linux DEPLOY=1 - env: IMAGE=dist-powerpc-linux DEPLOY=1 - env: IMAGE=dist-powerpc64-linux DEPLOY=1 - - env: IMAGE=dist-s390x-linux-netbsd DEPLOY=1 - - env: IMAGE=dist-x86-linux DEPLOY=1 + - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 + - env: IMAGE=dist-s390x-linux DEPLOY=1 + - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 + - env: IMAGE=dist-x86_64-linux DEPLOY=1 - env: IMAGE=dist-x86_64-musl DEPLOY=1 + - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 - env: IMAGE=emscripten - env: IMAGE=i686-gnu - env: IMAGE=i686-gnu-nopt diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile similarity index 79% rename from src/ci/docker/dist-armv7-aarch64-linux/Dockerfile rename to src/ci/docker/dist-aarch64-linux/Dockerfile index 369e5a7dffe2a..c468a689a0565 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -56,8 +56,7 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY armv7-linux-gnueabihf.config /tmp/ -COPY armv7-linux-gnueabihf.config aarch64-linux-gnu.config build-toolchains.sh /tmp/ +COPY aarch64-linux-gnu.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root @@ -67,17 +66,12 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \ - CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ \ - CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ - AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ - CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ -ENV HOSTS=armv7-unknown-linux-gnueabihf -ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu +ENV HOSTS=aarch64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config rename to src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config diff --git a/src/ci/docker/dist-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh new file mode 100755 index 0000000000000..94f785c96f815 --- /dev/null +++ b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../aarch64-linux-gnu.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 7facc52390ff4..1e448dd43fd5f 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -56,7 +56,7 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY arm-linux-gnueabihf.config arm-linux-gnueabi.config build-toolchains.sh /tmp/ +COPY arm-linux-gnueabi.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root @@ -66,17 +66,12 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ - CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ \ - CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ - AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ - CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ ENV HOSTS=arm-unknown-linux-gnueabi -ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/build-toolchains.sh b/src/ci/docker/dist-arm-linux/build-toolchains.sh index ed1406bd7cfa7..f78ecf9381a1f 100755 --- a/src/ci/docker/dist-arm-linux/build-toolchains.sh +++ b/src/ci/docker/dist-arm-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../arm-linux-gnueabihf.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile new file mode 100644 index 0000000000000..cad96b4bde480 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY arm-linux-gnueabihf.config build-toolchains.sh /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin + +ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ + AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ + CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + +ENV HOSTS=arm-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config rename to src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/dist-armhf-linux/build-toolchains.sh new file mode 100755 index 0000000000000..df1134d5483c2 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../arm-linux-gnueabihf.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile new file mode 100644 index 0000000000000..d5be52eba5c2e --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-toolchains.sh armv7-linux-gnueabihf.config /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin + +ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ + AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ + CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + +ENV HOSTS=armv7-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config rename to src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-armv7-linux/build-toolchains.sh similarity index 88% rename from src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh rename to src/ci/docker/dist-armv7-linux/build-toolchains.sh index ebd5ef4cfc492..2d395fee792ec 100755 --- a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh +++ b/src/ci/docker/dist-armv7-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../aarch64-linux-gnu.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile similarity index 77% rename from src/ci/docker/dist-freebsd/Dockerfile rename to src/ci/docker/dist-i686-freebsd/Dockerfile index 633f58ea474b4..beda2512741e9 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config COPY build-toolchain.sh /tmp/ -RUN /tmp/build-toolchain.sh x86_64 RUN /tmp/build-toolchain.sh i686 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -30,15 +29,11 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ \ AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \ CC_i686_unknown_freebsd=i686-unknown-freebsd10-gcc \ CXX_i686_unknown_freebsd=i686-unknown-freebsd10-g++ -ENV HOSTS=x86_64-unknown-freebsd -ENV HOSTS=$HOSTS,i686-unknown-freebsd +ENV HOSTS=i686-unknown-freebsd ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-freebsd/build-toolchain.sh b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh similarity index 100% rename from src/ci/docker/dist-freebsd/build-toolchain.sh rename to src/ci/docker/dist-i686-freebsd/build-toolchain.sh diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile similarity index 98% rename from src/ci/docker/dist-x86-linux/Dockerfile rename to src/ci/docker/dist-i686-linux/Dockerfile index 18c7a4d2b3e7f..4540f4b0ceb21 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -80,7 +80,6 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu -ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ diff --git a/src/ci/docker/dist-x86-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-binutils.sh rename to src/ci/docker/dist-i686-linux/build-binutils.sh diff --git a/src/ci/docker/dist-x86-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-cmake.sh rename to src/ci/docker/dist-i686-linux/build-cmake.sh diff --git a/src/ci/docker/dist-x86-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-curl.sh rename to src/ci/docker/dist-i686-linux/build-curl.sh diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-gcc.sh rename to src/ci/docker/dist-i686-linux/build-gcc.sh diff --git a/src/ci/docker/dist-x86-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-git.sh rename to src/ci/docker/dist-i686-linux/build-git.sh diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-headers.sh rename to src/ci/docker/dist-i686-linux/build-headers.sh diff --git a/src/ci/docker/dist-x86-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-openssl.sh rename to src/ci/docker/dist-i686-linux/build-openssl.sh diff --git a/src/ci/docker/dist-x86-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-python.sh rename to src/ci/docker/dist-i686-linux/build-python.sh diff --git a/src/ci/docker/dist-x86-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/shared.sh rename to src/ci/docker/dist-i686-linux/shared.sh diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 938c53ae48837..e3df1cc7192d8 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -13,7 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips-linux-gnu \ - g++-mipsel-linux-gnu \ libssl-dev \ pkg-config @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips-unknown-linux-gnu -ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 45de8100b4f27..e4b3bc378c89a 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -13,7 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips64-linux-gnuabi64 \ - g++-mips64el-linux-gnuabi64 \ libssl-dev \ pkg-config @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile new file mode 100644 index 0000000000000..06f42397a3ea5 --- /dev/null +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mips64el-linux-gnuabi64 \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mips64el-unknown-linux-gnuabi64 + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile new file mode 100644 index 0000000000000..17f9913b5aec2 --- /dev/null +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mipsel-linux-gnu \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mipsel-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 7413c327323e5..7c143b414d464 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -62,10 +62,6 @@ RUN ./build-powerpc64-toolchain.sh USER root -RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY build-powerpc64le-toolchain.sh /tmp/ -RUN ./build-powerpc64le-toolchain.sh - RUN curl -o /usr/local/bin/sccache \ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache @@ -75,13 +71,9 @@ ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ - AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile new file mode 100644 index 0000000000000..19b0d625d3616 --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh similarity index 100% rename from src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh rename to src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh diff --git a/src/ci/docker/dist-powerpc64le-linux/shared.sh b/src/ci/docker/dist-powerpc64le-linux/shared.sh new file mode 100644 index 0000000000000..97e6d2908cf8a --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 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. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile similarity index 83% rename from src/ci/docker/dist-s390x-linux-netbsd/Dockerfile rename to src/ci/docker/dist-s390x-linux/Dockerfile index 4180006690fc9..0d218771cf1c6 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -60,27 +60,20 @@ COPY patches/ /tmp/patches/ COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ RUN ./build-s390x-toolchain.sh -COPY build-netbsd-toolchain.sh /tmp/ -RUN ./build-netbsd-toolchain.sh - USER root RUN curl -o /usr/local/bin/sccache \ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache -ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ - AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ - CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ - CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot \ CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ -ENV HOSTS=x86_64-unknown-netbsd -ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu +ENV HOSTS=s390x-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh rename to src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch rename to src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config rename to src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile new file mode 100644 index 0000000000000..14444d69d2a8c --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + bzip2 \ + xz-utils \ + wget \ + libssl-dev \ + pkg-config + +COPY build-toolchain.sh /tmp/ +RUN /tmp/build-toolchain.sh x86_64 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ + +ENV HOSTS=x86_64-unknown-freebsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh new file mode 100755 index 0000000000000..5642e6fc937f9 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# 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. + +set -ex + +ARCH=$1 +BINUTILS=2.25.1 +GCC=5.3.0 + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +hide_output ../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile new file mode 100644 index 0000000000000..021c6683cc1ce --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -0,0 +1,95 @@ +FROM centos:5 + +WORKDIR /build + +RUN yum upgrade -y && yum install -y \ + curl \ + bzip2 \ + gcc \ + gcc-c++ \ + make \ + glibc-devel \ + perl \ + zlib-devel \ + file \ + xz \ + which \ + pkgconfig \ + wget \ + autoconf \ + gettext + +ENV PATH=/rustroot/bin:$PATH +ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib +ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig +WORKDIR /tmp +COPY shared.sh build-binutils.sh /tmp/ + +# We need a build of openssl which supports SNI to download artifacts from +# static.rust-lang.org. This'll be used to link into libcurl below (and used +# later as well), so build a copy of OpenSSL with dynamic libraries into our +# generic root. +COPY build-openssl.sh /tmp/ +RUN ./build-openssl.sh + +# The `curl` binary on CentOS doesn't support SNI which is needed for fetching +# some https urls we have, so install a new version of libcurl + curl which is +# using the openssl we just built previously. +# +# Note that we also disable a bunch of optional features of curl that we don't +# really need. +COPY build-curl.sh /tmp/ +RUN ./build-curl.sh + +# binutils < 2.22 has a bug where the 32-bit executables it generates +# immediately segfault in Rust, so we need to install our own binutils. +# +# See https://github.com/rust-lang/rust/issues/20440 for more info +RUN ./build-binutils.sh + +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY build-gcc.sh /tmp/ +RUN ./build-gcc.sh + +# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ +COPY build-python.sh /tmp/ +RUN ./build-python.sh + +# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for +# cloning, so download and build it here. +COPY build-git.sh /tmp/ +RUN ./build-git.sh + +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY build-cmake.sh /tmp/ +RUN ./build-cmake.sh + +# for sanitizers, we need kernel headers files newer than the ones CentOS ships +# with so we install newer ones here +COPY build-headers.sh /tmp/ +RUN ./build-headers.sh + +RUN curl -Lo /rustroot/dumb-init \ + https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \ + chmod +x /rustroot/dumb-init +ENTRYPOINT ["/rustroot/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV HOSTS=x86_64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS \ + --host=$HOSTS \ + --enable-extended \ + --enable-sanitizers +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS + +# This is the only builder which will create source tarballs +ENV DIST_SRC 1 + +# When we build cargo in this container, we don't want it to use the system +# libcurl, instead it should compile its own. +ENV LIBCURL_NO_PKG_CONFIG 1 diff --git a/src/ci/docker/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/dist-x86_64-linux/build-binutils.sh new file mode 100755 index 0000000000000..80aa1f2a01613 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-binutils.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex + +source shared.sh + +curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - + +mkdir binutils-build +cd binutils-build +hide_output ../binutils-2.25.1/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf binutils-build +rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/dist-x86_64-linux/build-cmake.sh new file mode 100755 index 0000000000000..82e46455cb0f0 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-cmake.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex +source shared.sh + +curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - + +mkdir cmake-build +cd cmake-build +hide_output ../cmake-3.6.3/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf cmake-build +rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh new file mode 100755 index 0000000000000..b7d22755a571b --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex +source shared.sh + +VERSION=7.51.0 + +curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - + +mkdir curl-build +cd curl-build +hide_output ../curl-$VERSION/configure \ + --prefix=/rustroot \ + --with-ssl=/rustroot \ + --disable-sspi \ + --disable-gopher \ + --disable-smtp \ + --disable-smb \ + --disable-imap \ + --disable-pop3 \ + --disable-tftp \ + --disable-telnet \ + --disable-manual \ + --disable-dict \ + --disable-rtsp \ + --disable-ldaps \ + --disable-ldap +hide_output make -j10 +hide_output make install + +cd .. +rm -rf curl-build +rm -rf curl-$VERSION +yum erase -y curl diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh new file mode 100755 index 0000000000000..ab2562538d6d7 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex + +source shared.sh + +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --prefix=/rustroot \ + --enable-languages=c,c++ +hide_output make -j10 +hide_output make install +ln -nsf gcc /rustroot/bin/cc + +cd .. +rm -rf gcc-build +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh new file mode 100755 index 0000000000000..92fa66b496d93 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-git.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex +source shared.sh + +curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - + +cd git-2.10.0 +make configure +hide_output ./configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-x86_64-linux/build-headers.sh b/src/ci/docker/dist-x86_64-linux/build-headers.sh new file mode 100755 index 0000000000000..4ce38fd9205e2 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-headers.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex +source shared.sh + +curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x + +cd linux-3.2.84 +hide_output make mrproper +hide_output make INSTALL_HDR_PATH=dest headers_install + +find dest/include \( -name .install -o -name ..install.cmd \) -delete +yes | cp -fr dest/include/* /usr/include + +cd .. +rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh new file mode 100755 index 0000000000000..64b1abf82a827 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex +source shared.sh + +VERSION=1.0.2j + +curl https://www.openssl.org/source/openssl-$VERSION.tar.gz | tar xzf - + +cd openssl-$VERSION +hide_output ./config --prefix=/rustroot shared -fPIC +hide_output make -j10 +hide_output make install +cd .. +rm -rf openssl-$VERSION + +# Make the system cert collection available to the new install. +ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-x86_64-linux/build-python.sh b/src/ci/docker/dist-x86_64-linux/build-python.sh new file mode 100755 index 0000000000000..a7a450f3c8de7 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-python.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright 2017 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. + +set -ex +source shared.sh + +curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ + tar xzf - + +mkdir python-build +cd python-build + +# Gotta do some hackery to tell python about our custom OpenSSL build, but other +# than that fairly normal. +CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ + hide_output ../Python-2.7.12/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf python-build +rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-x86_64-linux/shared.sh b/src/ci/docker/dist-x86_64-linux/shared.sh new file mode 100644 index 0000000000000..97e6d2908cf8a --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 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. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile new file mode 100644 index 0000000000000..053300b9c1688 --- /dev/null +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -0,0 +1,78 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin + +ENV \ + AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ + CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ + CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot + +ENV HOSTS=x86_64-unknown-netbsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh rename to src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh From 802c11c33e4efee699d35dfe60604cfcad38ec62 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 3 Apr 2017 22:14:45 +0200 Subject: [PATCH 482/662] switch to vault.centos.org --- src/ci/docker/dist-x86-linux/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 18c7a4d2b3e7f..0c86568d71e18 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -2,6 +2,12 @@ FROM centos:5 WORKDIR /build +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1vault.centos.org/' /etc/yum.repos.d/*.repo + RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ From 3fb1a849ddd162444e2894bce52f7bb2dbc53d69 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 3 Apr 2017 13:46:50 -0700 Subject: [PATCH 483/662] Add a common Build::src_is_git flag --- src/bootstrap/lib.rs | 8 ++++---- src/bootstrap/sanity.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84254d7d6ae51..f80ba017f0774 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -162,6 +162,7 @@ pub struct Build { cxx: HashMap, crates: HashMap, is_sudo: bool, + src_is_git: bool, } #[derive(Debug)] @@ -233,6 +234,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let src_is_git = src.join(".git").is_dir(); Build { flags: flags, @@ -251,6 +253,7 @@ impl Build { lldb_version: None, lldb_python_dir: None, is_sudo: is_sudo, + src_is_git: src_is_git, } } @@ -307,10 +310,7 @@ impl Build { OutOfSync, } - if !self.config.submodules { - return - } - if fs::metadata(self.src.join(".git")).is_err() { + if !self.src_is_git || !self.config.submodules { return } let git = || { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 235ce9360eff4..d1b235f4691dc 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -65,7 +65,7 @@ pub fn check(build: &mut Build) { // If we've got a git directory we're gona need git to update // submodules and learn about various other aspects. - if fs::metadata(build.src.join(".git")).is_ok() { + if build.src_is_git { need_cmd("git".as_ref()); } From e9cfc300a3a5b5a6f6f27df3305338f4b451366d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 3 Apr 2017 13:46:53 -0700 Subject: [PATCH 484/662] Only use cargo-vendor if building from git sources --- src/bootstrap/dist.rs | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index ec992b47a6e4b..6472b1a928caf 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -433,29 +433,32 @@ pub fn rust_src(build: &Build) { copy(&build.src.join(item), &dst_src.join(item)); } - // Get cargo-vendor installed, if it isn't already. - let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.cargo); - for line in output(cmd.arg("install").arg("--list")).lines() { - has_cargo_vendor |= line.starts_with("cargo-vendor "); - } - if !has_cargo_vendor { + // If we're building from git sources, we need to vendor a complete distribution. + if build.src_is_git { + // Get cargo-vendor installed, if it isn't already. + let mut has_cargo_vendor = false; + let mut cmd = Command::new(&build.cargo); + for line in output(cmd.arg("install").arg("--list")).lines() { + has_cargo_vendor |= line.starts_with("cargo-vendor "); + } + if !has_cargo_vendor { + let mut cmd = Command::new(&build.cargo); + cmd.arg("install") + .arg("--force") + .arg("--debug") + .arg("--vers").arg(CARGO_VENDOR_VERSION) + .arg("cargo-vendor") + .env("RUSTC", &build.rustc); + build.run(&mut cmd); + } + + // Vendor all Cargo dependencies let mut cmd = Command::new(&build.cargo); - cmd.arg("install") - .arg("--force") - .arg("--debug") - .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &build.rustc); + cmd.arg("vendor") + .current_dir(&dst_src.join("src")); build.run(&mut cmd); } - // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.cargo); - cmd.arg("vendor") - .current_dir(&dst_src.join("src")); - build.run(&mut cmd); - // Create source tarball in rust-installer format let mut cmd = Command::new(SH_CMD); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) From 5787808d07b27d12a397cd20bd630a2ed1f35ca2 Mon Sep 17 00:00:00 2001 From: mandeep Date: Mon, 3 Apr 2017 15:48:12 -0500 Subject: [PATCH 485/662] Removed trailing whitespace on line 682 --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 8a3fa94d4c1ea..be613e06b02e8 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -679,7 +679,7 @@ impl Vec { } /// Removes an element from the vector and returns it. - /// + /// /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is O(1). From 6dc8869f389e5b98d69b449befcf763cf897db67 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 3 Apr 2017 22:51:06 +0200 Subject: [PATCH 486/662] use fixed ip for vault.centos.org until updates have propagated to all mirrors --- src/ci/docker/dist-x86-linux/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 0c86568d71e18..a2afe4b1290f6 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1vault.centos.org/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ From b02cb1978c9c7532c93af4761fc61a72cb529da8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Apr 2017 00:24:08 +0200 Subject: [PATCH 487/662] Handle ordered lists as well --- src/librustdoc/html/markdown.rs | 16 ++++++++++++---- src/test/rustdoc/test-lists.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc/test-lists.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 0b098fb14f190..245a3946a3709 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -427,12 +427,15 @@ pub fn render(w: &mut fmt::Formatter, looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } + if shorter.is_compact() { + break + } } buffer.push_str(&format!("

  • {}
  • ", content)); } fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, is_sorted_list: bool) { debug!("List"); let mut content = String::new(); while let Some(event) = parser.next() { @@ -445,8 +448,13 @@ pub fn render(w: &mut fmt::Formatter, looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } + if shorter.is_compact() { + break + } } - buffer.push_str(&format!("
      {}
    ", content)); + buffer.push_str(&format!("<{0}>{1}", + if is_sorted_list { "ol" } else { "ul" }, + content)); } fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, @@ -516,8 +524,8 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::BlockQuote) => { blockquote(parser, buffer, toc_builder, shorter); } - Event::Start(Tag::List(_)) => { - list(parser, buffer, toc_builder, shorter); + Event::Start(Tag::List(x)) => { + list(parser, buffer, toc_builder, shorter, x.is_some()); } Event::Start(Tag::Emphasis) => { emphasis(parser, buffer, toc_builder, shorter, id); diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs new file mode 100644 index 0000000000000..71a826a2bed7f --- /dev/null +++ b/src/test/rustdoc/test-lists.rs @@ -0,0 +1,32 @@ +// Copyright 2017 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. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/fn.f.html +// @has - "
    pub fn f()
    1. list
      1. fooooo
      2. x
    2. foo
    " +/// 1. list +/// 1. fooooo +/// 2. x +/// 2. foo +pub fn f() {} + +// @has foo/fn.foo2.html +// @has - "
    pub fn foo2()
    • normal list
      • sub list

      • new elem still same elem

        and again same elem!

    • new big elem
    " +/// * normal list +/// * sub list +/// * new elem +/// still same elem +/// +/// and again same elem! +/// * new big elem +pub fn foo2() {} \ No newline at end of file From 4d32ff4e498c391d65b44d26cfb453651dc3da7b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 3 Apr 2017 15:28:06 -0700 Subject: [PATCH 488/662] Loosen src_is_git to just check exists() --- src/bootstrap/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f80ba017f0774..8303a40bb6965 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -234,7 +234,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); - let src_is_git = src.join(".git").is_dir(); + let src_is_git = src.join(".git").exists(); Build { flags: flags, From 6a9448b523b95dbc850e856508342644fc17db45 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 3 Apr 2017 22:23:32 +0000 Subject: [PATCH 489/662] Fix bug parsing `#[derive]` macro invocations. --- src/librustc_resolve/macros.rs | 6 ++++-- src/libsyntax/ext/derive.rs | 3 ++- src/libsyntax/parse/parser.rs | 20 ++++++++++++++++++++ src/test/run-pass/issue-40962.rs | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-40962.rs diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 05f30f039c8f0..966cb7ee8d8d8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> { let name = unwrap_or!(attrs[i].name(), continue); if name == "derive" { - let result = attrs[i].parse_list(&self.session.parse_sess, - |parser| parser.parse_path(PathStyle::Mod)); + let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { + parser.parse_path_allowing_meta(PathStyle::Mod) + }); + let mut traits = match result { Ok(traits) => traits, Err(mut e) => { diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index c79040424f619..e7c5d8278d977 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec return true; } - match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { + match attr.parse_list(cx.parse_sess, + |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { Ok(ref traits) if traits.is_empty() => { cx.span_warn(attr.span, "empty trait list in `derive`"); false diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855af..a89811d8abb0b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1754,6 +1754,26 @@ impl<'a> Parser<'a> { }) } + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. + /// This is used when parsing derive macro paths in `#[derive]` attributes. + pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(ident) = meta_ident { + self.bump(); + return Ok(ast::Path::from_ident(self.prev_span, ident)); + } + self.parse_path(mode) + } + /// Examples: /// - `a::b::c` /// - `a::b::c(V) -> W` diff --git a/src/test/run-pass/issue-40962.rs b/src/test/run-pass/issue-40962.rs new file mode 100644 index 0000000000000..b35cfa12eab18 --- /dev/null +++ b/src/test/run-pass/issue-40962.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { + ($i:meta) => { + #[derive($i)] + struct S; + } +} + +m!(Clone); + +fn main() {} From ab4f4428e778d45e0e8db2a254e55f5ec786410c Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Mon, 3 Apr 2017 16:09:19 -0700 Subject: [PATCH 490/662] Fix styling issues --- src/libstd/sync/mpsc/mod.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 33ffd5548fb88..0da65a4f2e12f 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -23,12 +23,12 @@ //! //! These channels come in two flavors: //! -//! 1. An asynchronous, infinitely buffered channel. The [`channel()`] function +//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function //! will return a `(Sender, Receiver)` tuple where all sends will be //! **asynchronous** (they never block). The channel conceptually has an //! infinite buffer. //! -//! 2. A synchronous, bounded channel. The [`sync_channel()`] function will +//! 2. A synchronous, bounded channel. The [`sync_channel`] function will //! return a `(SyncSender, Receiver)` tuple where the storage for pending //! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note @@ -39,8 +39,8 @@ //! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html //! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html //! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -//! [`channel()`]: ../../../std/sync/mpsc/fn.channel.html -//! [`sync_channel()`]: ../../../std/sync/mpsc/fn.sync_channel.html +//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html +//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html //! //! ## Disconnection //! @@ -51,12 +51,12 @@ //! //! Once half of a channel has been deallocated, most operations can no longer //! continue to make progress, so [`Err`] will be returned. Many applications -//! will continue to [`unwrap()`] the results returned from this module, +//! will continue to [`unwrap`] the results returned from this module, //! instigating a propagation of failure among threads if one unexpectedly dies. //! //! [`Result`]: ../../../std/result/enum.Result.html //! [`Err`]: ../../../std/result/enum.Result.html#variant.Err -//! [`unwrap()`]: ../../../std/result/enum.Result.html#method.unwrap +//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap //! //! # Examples //! @@ -310,12 +310,15 @@ mod spsc_queue; /// use std::sync::mpsc::channel; /// use std::thread; /// use std::time::Duration; +/// /// let (send, recv) = channel(); +/// /// thread::spawn(move || { /// send.send("Hello world!").unwrap(); /// thread::sleep(Duration::from_secs(2)); // block for two seconds /// send.send("Delayed for 2 seconds").unwrap(); /// }); +/// /// println!("{}", recv.recv().unwrap()); // Received immediately /// println!("Waiting..."); /// println!("{}", recv.recv().unwrap()); // Received after 2 seconds @@ -384,18 +387,23 @@ pub struct IntoIter { /// ```rust /// use std::sync::mpsc::channel; /// use std::thread; +/// /// let (sender, receiver) = channel(); /// let sender2 = sender.clone(); +/// /// // First thread owns sender /// thread::spawn(move || { /// sender.send(1).unwrap(); /// }); +/// /// // Second thread owns sender2 /// thread::spawn(move || { /// sender2.send(2).unwrap(); /// }); +/// /// let msg = receiver.recv().unwrap(); /// let msg2 = receiver.recv().unwrap(); +/// /// assert_eq!(3, msg + msg2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1097,12 +1105,15 @@ impl Receiver { /// ```rust /// use std::sync::mpsc::channel; /// use std::thread; + /// /// let (send, recv) = channel(); + /// /// thread::spawn(move || { /// send.send(1u8).unwrap(); /// send.send(2u8).unwrap(); /// send.send(3u8).unwrap(); /// }); + /// /// for x in recv.iter() { /// println!("Got: {}", x); /// } From 20cb7005b0c1e12383a4c2f9031c5c5f5c907efc Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Mon, 3 Apr 2017 19:15:31 -0600 Subject: [PATCH 491/662] Handle options-with-arguments before subcommands such as './x.py -j 10 build' and detect pathological cases like './x.py --option-that-takes-argument clean build' --- src/bootstrap/flags.rs | 60 +++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2e133664a05b3..3af3b76163c1e 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -119,7 +119,13 @@ To learn more about a subcommand, run `./x.py -h`"); // complete the definition of the options. Then we can use the getopt::Matches object from // there on out. let mut possible_subcommands = args.iter().collect::>(); - possible_subcommands.retain(|&s| !s.starts_with('-')); + possible_subcommands.retain(|&s| + (s == "build") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist")); let subcommand = match possible_subcommands.first() { Some(s) => s, None => { @@ -129,7 +135,43 @@ To learn more about a subcommand, run `./x.py -h`"); } }; - // Some subcommands have specific arguments help text + // Some subcommands get extra options + match subcommand.as_str() { + "test" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), + "bench" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), + "dist" => opts.optflag("", "install", "run installer as well"), + _ => { } + }; + + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Extra sanity check to make sure we didn't hit this crazy corner case: + // + // ./x.py --frobulate clean build + // ^-- option ^ ^- actual subcommand + // \_ arg to option could be mistaken as subcommand + let mut pass_sanity_check = true; + match matches.free.get(0) { + Some(check_subcommand) => { + if &check_subcommand != subcommand { + pass_sanity_check = false; + } + }, + None => { + pass_sanity_check = false; + } + } + if !pass_sanity_check { + println!("{}\n", subcommand_help); + println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n"); + process::exit(1); + } + // Extra help text for some commands match subcommand.as_str() { "build" => { subcommand_help.push_str("\n @@ -152,7 +194,6 @@ Arguments: ./x.py build --stage 1 src/libtest"); } "test" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories to tests that @@ -168,9 +209,6 @@ Arguments: ./x.py test ./x.py test --stage 1"); } - "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - } "doc" => { subcommand_help.push_str("\n Arguments: @@ -186,18 +224,8 @@ Arguments: ./x.py doc ./x.py doc --stage 1"); } - "dist" => { - opts.optflag("", "install", "run installer as well"); - } _ => { } }; - - // Done specifying what options are possible, so do the getopts parsing - let matches = opts.parse(&args[..]).unwrap_or_else(|e| { - // Invalid argument/option format - println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); - }); // Get any optional paths which occur after the subcommand let cwd = t!(env::current_dir()); let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); From 018c5c929820af8e8b455a64a9d7d5456b01b1ed Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 4 Apr 2017 10:43:16 +0900 Subject: [PATCH 492/662] Make 'overlapping_inherent_impls' lint a hard error --- .../coherence/inherent_impls_overlap.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 4b36072243c81..33280fb931aaf 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -11,7 +11,6 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::lint; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt}; @@ -53,12 +52,16 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for &item2 in &impl_items2[..] { if (name, namespace) == name_and_namespace(item2) { - let msg = format!("duplicate definitions with name `{}`", name); - let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); - self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, - node_id, - self.tcx.span_of_impl(item1).unwrap(), - msg); + struct_span_err!(self.tcx.sess, + self.tcx.span_of_impl(item1).unwrap(), + E0592, + "duplicate definitions with name `{}`", + name) + .span_label(self.tcx.span_of_impl(item1).unwrap(), + &format!("duplicate definitions for `{}`", name)) + .span_label(self.tcx.span_of_impl(item2).unwrap(), + &format!("other definition for `{}`", name)) + .emit(); } } } From 4143d409eed1393a830fcc089dc68d94a20a223f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 16:30:31 +1300 Subject: [PATCH 493/662] save-analysis: only index path references once --- src/librustc_save_analysis/dump_visitor.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 7a7fa4eda05a6..491618f7952d8 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1401,15 +1401,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, debug!("visit_expr {:?}", ex.node); self.process_macro_use(ex.span, ex.id); match ex.node { - ast::ExprKind::Call(ref _f, ref _args) => { - // Don't need to do anything for function calls, - // because just walking the callee path does what we want. - visit::walk_expr(self, ex); - } - ast::ExprKind::Path(_, ref path) => { - self.process_path(ex.id, path, None); - visit::walk_expr(self, ex); - } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id); let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) { @@ -1507,6 +1498,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, self.visit_expr(element); self.nest_tables(count.id, |v| v.visit_expr(count)); } + // In particular, we take this branch for call and path expressions, + // where we'll index the idents involved just by continuing to walk. _ => { visit::walk_expr(self, ex) } From ccdbb31a4773fcb44d046f02a822e54dfe132970 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 18:04:30 +1300 Subject: [PATCH 494/662] save-analysis: index extern blocks --- src/librustc_save_analysis/dump_visitor.rs | 35 +++++++++++++ src/librustc_save_analysis/lib.rs | 55 +++++++++++++++++++++ src/test/run-make/save-analysis-fail/foo.rs | 5 ++ 3 files changed, 95 insertions(+) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 491618f7952d8..3fd0ce45e3610 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1599,4 +1599,39 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); } + + fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(fn_data, FunctionData, item.span); + if !self.span.filter_generated(Some(fn_data.span), item.span) { + self.dumper.function(fn_data.clone().lower(self.tcx)); + } + + self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, + &fn_data.qualname)); + self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); + } + + for arg in &decl.inputs { + self.visit_ty(&arg.ty); + } + + if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { + self.visit_ty(&ret_ty); + } + } + ast::ForeignItemKind::Static(ref ty, _) => { + if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(var_data, VariableData, item.span); + if !self.span.filter_generated(Some(var_data.span), item.span) { + self.dumper.variable(var_data.lower(self.tcx)); + } + } + + self.visit_ty(ty); + } + } + } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1de9fbc8e4941..b34cffd2d15bd 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -120,6 +120,46 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result } + pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option { + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + Some(Data::FunctionData(FunctionData { + id: item.id, + name: item.ident.to_string(), + qualname: qualname, + declaration: None, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + value: make_signature(decl, generics), + visibility: From::from(&item.vis), + parent: None, + docs: docs_for_attrs(&item.attrs), + sig: self.sig_base_extern(item), + })) + } + ast::ForeignItemKind::Static(ref ty, m) => { + let keyword = if m { keywords::Mut } else { keywords::Static }; + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + Some(Data::VariableData(VariableData { + id: item.id, + kind: VariableKind::Static, + name: item.ident.to_string(), + qualname: qualname, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + parent: None, + value: String::new(), + type_value: ty_to_string(ty), + visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), + sig: Some(self.sig_base_extern(item)), + })) + } + } + } + pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemKind::Fn(ref decl, .., ref generics, _) => { @@ -751,6 +791,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature { + let text = self.span_utils.signature_string_for_span(item.span); + let name = item.ident.to_string(); + let ident_start = text.find(&name).expect("Name not in signature?"); + let ident_end = ident_start + name.len(); + Signature { + span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + text: text, + ident_start: ident_start, + ident_end: ident_end, + defs: vec![], + refs: vec![], + } + } + #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs index e331f65abb7b3..a996aa4fad5a7 100644 --- a/src/test/run-make/save-analysis-fail/foo.rs +++ b/src/test/run-make/save-analysis-fail/foo.rs @@ -448,3 +448,8 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +extern { + static EXTERN_FOO: u8; + fn extern_foo(a: u8, b: i32) -> String; +} From d76daf5c616f7969752e5370287f4495b95fe00c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Mar 2017 10:43:11 +1300 Subject: [PATCH 495/662] rebased --- src/librustc_save_analysis/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b34cffd2d15bd..44615071a56a7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -125,6 +125,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + filter!(self.span_utils, sub_span, item.span, None); Some(Data::FunctionData(FunctionData { id: item.id, name: item.ident.to_string(), @@ -137,11 +138,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base_extern(item), + attributes: item.attrs.clone(), })) } ast::ForeignItemKind::Static(ref ty, m) => { let keyword = if m { keywords::Mut } else { keywords::Static }; let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + filter!(self.span_utils, sub_span, item.span, None); Some(Data::VariableData(VariableData { id: item.id, kind: VariableKind::Static, @@ -155,6 +158,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base_extern(item)), + attributes: item.attrs.clone(), })) } } @@ -797,7 +801,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ident_start = text.find(&name).expect("Name not in signature?"); let ident_end = ident_start + name.len(); Signature { - span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, text: text, ident_start: ident_start, ident_end: ident_end, From e753dfa9a945043c7c465fc3f1e9389585e096d0 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Tue, 28 Mar 2017 16:16:23 +0900 Subject: [PATCH 496/662] Fixed ICEs with pattern matching in const fn. Fixes #38199, fixes #31577, fixes #29093, and fixes #40012. --- src/librustc_mir/transform/qualify_consts.rs | 6 ++--- src/librustc_typeck/check/dropck.rs | 9 ++++--- .../compile-fail/const-match-pattern-arm.rs | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/const-match-pattern-arm.rs diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9d236bd013c43..cdbc0bd8858a5 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -722,11 +722,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } Rvalue::Discriminant(..) => { - // FIXME discriminant + // FIXME implement discriminant const qualify self.add(Qualif::NOT_CONST); - if self.mode != Mode::Fn { - bug!("implement discriminant const qualify"); - } + // Discriminants in consts will error elsewhere as an unimplemented expression type } Rvalue::Box(_) => { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 90d2a15cf0863..9f41373dab1b7 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -278,9 +278,12 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", typ, scope); - let parent_scope = rcx.tcx.region_maps.opt_encl_scope(scope).unwrap_or_else(|| { - span_bug!(span, "no enclosing scope found for scope: {:?}", scope) - }); + + let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) { + Some(parent_scope) => parent_scope, + // If no enclosing scope, then it must be the root scope which cannot be outlived. + None => return + }; let result = iterate_over_potentially_unsafe_regions_in_type( &mut DropckContext { diff --git a/src/test/compile-fail/const-match-pattern-arm.rs b/src/test/compile-fail/const-match-pattern-arm.rs new file mode 100644 index 0000000000000..452aa87d6ba56 --- /dev/null +++ b/src/test/compile-fail/const-match-pattern-arm.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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. + +const x: bool = match Some(true) { + Some(value) => true, + //~^ ERROR: constant contains unimplemented expression type [E0019] + _ => false +}; + +const y: bool = { + match Some(true) { + Some(value) => true, + //~^ ERROR: constant contains unimplemented expression type [E0019] + _ => false + } +}; + +fn main() {} From 6132fb83b45cc9c519c2fee29e497460db06ba2a Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Mon, 3 Apr 2017 22:41:55 -0700 Subject: [PATCH 497/662] Replace magic number with readable sig constant SIG_ERR is defined as 'pub const SIG_ERR: sighandler_t = !0 as sighandler_t;' --- src/libstd/sys/unix/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c57751a01d7c1..854d380d128c9 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -92,7 +92,7 @@ pub fn init() { #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} From 09f42ee3331815347767b5a821813a927758a421 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 4 Apr 2017 21:00:56 +0900 Subject: [PATCH 498/662] Move 'overlapping_inherent_impls' test to ui --- .../overlapping_inherent_impls.rs} | 6 ++-- .../overlapping_inherent_impls.stderr | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) rename src/test/{compile-fail/inherent-overlap.rs => ui/codemap_tests/overlapping_inherent_impls.rs} (84%) create mode 100644 src/test/ui/codemap_tests/overlapping_inherent_impls.stderr diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs similarity index 84% rename from src/test/compile-fail/inherent-overlap.rs rename to src/test/ui/codemap_tests/overlapping_inherent_impls.rs index 18e77ddfd2c5b..a626b63b31ba0 100644 --- a/src/test/compile-fail/inherent-overlap.rs +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs @@ -16,7 +16,7 @@ struct Foo; impl Foo { - fn id() {} //~ ERROR duplicate definitions + fn id() {} } impl Foo { @@ -26,7 +26,7 @@ impl Foo { struct Bar(T); impl Bar { - fn bar(&self) {} //~ ERROR duplicate definitions + fn bar(&self) {} } impl Bar { @@ -36,7 +36,7 @@ impl Bar { struct Baz(T); impl Baz { - fn baz(&self) {} //~ ERROR duplicate definitions + fn baz(&self) {} } impl Baz> { diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr new file mode 100644 index 0000000000000..de8a24cf33f44 --- /dev/null +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -0,0 +1,29 @@ +error[E0592]: duplicate definitions with name `id` + --> $DIR/overlapping_inherent_impls.rs:19:5 + | +19 | fn id() {} + | ^^^^^^^^^^ duplicate definitions for `id` +... +23 | fn id() {} + | ---------- other definition for `id` + +error[E0592]: duplicate definitions with name `bar` + --> $DIR/overlapping_inherent_impls.rs:29:5 + | +29 | fn bar(&self) {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `bar` +... +33 | fn bar(&self) {} + | ---------------- other definition for `bar` + +error[E0592]: duplicate definitions with name `baz` + --> $DIR/overlapping_inherent_impls.rs:39:5 + | +39 | fn baz(&self) {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `baz` +... +43 | fn baz(&self) {} + | ---------------- other definition for `baz` + +error: aborting due to 3 previous errors + From db60b0b374ef4999e3c960a7230b18bcddf82ea0 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 4 Apr 2017 21:08:56 +0900 Subject: [PATCH 499/662] Move 'coherence-overlapping-inherent-impl-trait' test to ui --- .../coherence-overlapping-inherent-impl-trait.rs | 2 +- .../coherence-overlapping-inherent-impl-trait.stderr | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) rename src/test/{compile-fail => ui/codemap_tests}/coherence-overlapping-inherent-impl-trait.rs (88%) create mode 100644 src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr diff --git a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs similarity index 88% rename from src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs rename to src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs index 158d3606104a9..a72ad0351e33b 100644 --- a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs @@ -11,6 +11,6 @@ #![allow(dead_code)] trait C {} -impl C { fn f() {} } //~ ERROR duplicate definitions with name `f` +impl C { fn f() {} } impl C { fn f() {} } fn main() { } diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr new file mode 100644 index 0000000000000..7f1ab929c6fc2 --- /dev/null +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr @@ -0,0 +1,10 @@ +error[E0592]: duplicate definitions with name `f` + --> $DIR/coherence-overlapping-inherent-impl-trait.rs:14:10 + | +14 | impl C { fn f() {} } + | ^^^^^^^^^ duplicate definitions for `f` +15 | impl C { fn f() {} } + | --------- other definition for `f` + +error: aborting due to previous error + From dd7fc23a21d60233e5c1b08376cc6cca6b9e1d53 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 4 Apr 2017 15:46:48 +0200 Subject: [PATCH 500/662] fix rollup --- src/ci/docker/dist-x86_64-linux/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 021c6683cc1ce..bd36c75f9f06a 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -2,6 +2,12 @@ FROM centos:5 WORKDIR /build +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo + RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ From aab2cca046670295bc1a430a8b1c23d755f9bd5a Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 27 Mar 2017 15:55:56 -0700 Subject: [PATCH 501/662] On-demandify reachability --- src/librustc/middle/reachable.rs | 17 ++++++++++++++--- src/librustc/ty/maps.rs | 12 ++++++++++++ src/librustc_driver/driver.rs | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index b0e39442af98c..e5dd48534a6a1 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,11 +15,11 @@ // makes all other generics or inline functions that it references // reachable as well. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum}; use ty::{self, TyCtxt}; +use ty::maps::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; @@ -362,7 +362,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { - let _task = tcx.dep_graph.in_task(DepNode::Reachability); + ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) +} + +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { + debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); @@ -408,3 +412,10 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { // Return the set of reachable symbols. reachable_context.reachable_symbols } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + reachable_set, + ..*providers + }; +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4a183191cef29..823bdc9e092ac 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -15,6 +15,7 @@ use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; @@ -209,6 +210,11 @@ impl<'tcx> QueryDescription for queries::typeck_item_bodies<'tcx> { } } +impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("reachability") + } +} macro_rules! define_maps { (<$tcx:tt> @@ -440,6 +446,8 @@ define_maps! { <'tcx> /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, + pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } @@ -451,6 +459,10 @@ fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } +fn reachability_dep_node(_: CrateNum) -> DepNode { + DepNode::Reachability +} + fn mir_shim(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 977382b33adf7..3f99d5123c9e8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -889,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); + reachable::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); From 768e7078785dd418968f26d79b1ff323403999ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:08:52 -0400 Subject: [PATCH 502/662] kill the `CheckLoops` DepNode --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc_passes/loops.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5aea2bcaa4f5c..5142fd3c028db 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,7 +60,6 @@ pub enum DepNode { CheckStaticRecursion, ResolveLifetimes, RegionResolveCrate, - CheckLoops, PluginRegistrar, StabilityIndex, CollectItem(D), @@ -219,7 +218,6 @@ impl DepNode { CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), - CheckLoops => Some(CheckLoops), PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 421181c68c4cd..2ea235af10378 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -11,7 +11,6 @@ use self::Context::*; use rustc::session::Session; -use rustc::dep_graph::DepNode; use rustc::hir::map::Map; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; @@ -50,7 +49,6 @@ struct CheckLoopVisitor<'a, 'hir: 'a> { } pub fn check_crate(sess: &Session, map: &Map) { - let _task = map.dep_graph.in_task(DepNode::CheckLoops); let krate = map.krate(); krate.visit_all_item_likes(&mut CheckLoopVisitor { sess: sess, From f3b876c4b2dec93ead8ebdcbf5eb5a0be4fa46a0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:09:12 -0400 Subject: [PATCH 503/662] kill `CheckStaticRecursion` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc_passes/static_recursion.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5142fd3c028db..0521b50df4d2d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -57,7 +57,6 @@ pub enum DepNode { // Represents different phases in the compiler. CollectLanguageItems, - CheckStaticRecursion, ResolveLifetimes, RegionResolveCrate, PluginRegistrar, @@ -215,7 +214,6 @@ impl DepNode { MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), CollectLanguageItems => Some(CollectLanguageItems), - CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), PluginRegistrar => Some(PluginRegistrar), diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index fc05471ead30b..d0bf49b7b337d 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -11,7 +11,6 @@ // This compiler pass detects constants that refer to themselves // recursively. -use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::session::{CompileResult, Session}; use rustc::hir::def::{Def, CtorKind}; @@ -88,8 +87,6 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> { } pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> CompileResult { - let _task = hir_map.dep_graph.in_task(DepNode::CheckStaticRecursion); - let mut visitor = CheckCrateVisitor { sess: sess, hir_map: hir_map, From 60381cd9c29c51615975894e898b47da65f0b124 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 4 Apr 2017 18:11:03 +0300 Subject: [PATCH 504/662] cstore: return an immutable borrow from `visible_parent_map` Fixes #41053. --- src/librustc/middle/cstore.rs | 4 +-- src/librustc_metadata/cstore_impl.rs | 16 +++++++++--- src/test/run-pass/auxiliary/issue_41053.rs | 11 ++++++++ src/test/run-pass/issue-41053.rs | 30 ++++++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/auxiliary/issue_41053.rs create mode 100644 src/test/run-pass/issue-41053.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 8bc0cf2577b5d..dd1941ba48af8 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -172,7 +172,7 @@ pub trait CrateStore { fn stability(&self, def: DefId) -> Option; fn deprecation(&self, def: DefId) -> Option; fn visibility(&self, def: DefId) -> ty::Visibility; - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap>; + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; fn item_attrs(&self, def_id: DefId) -> Vec; fn fn_arg_names(&self, did: DefId) -> Vec; @@ -302,7 +302,7 @@ impl CrateStore for DummyCrateStore { fn stability(&self, def: DefId) -> Option { bug!("stability") } fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { bug!("visible_parent_map") } fn item_generics_cloned(&self, def: DefId) -> ty::Generics diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 41a2e8a8d55e3..b286cb8050ea0 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -507,12 +507,19 @@ impl CrateStore for cstore::CStore { /// Returns a map from a sufficiently visible external item (i.e. an external item that is /// visible from at least one local module) to a sufficiently visible parent (considering /// modules that re-export the external item to be parents). - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { - let mut visible_parent_map = self.visible_parent_map.borrow_mut(); - if !visible_parent_map.is_empty() { return visible_parent_map; } + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { + { + let visible_parent_map = self.visible_parent_map.borrow(); + if !visible_parent_map.is_empty() { + return visible_parent_map; + } + } use std::collections::vec_deque::VecDeque; use std::collections::hash_map::Entry; + + let mut visible_parent_map = self.visible_parent_map.borrow_mut(); + for cnum in (1 .. self.next_crate_num().as_usize()).map(CrateNum::new) { let cdata = self.get_crate_data(cnum); @@ -556,6 +563,7 @@ impl CrateStore for cstore::CStore { } } - visible_parent_map + drop(visible_parent_map); + self.visible_parent_map.borrow() } } diff --git a/src/test/run-pass/auxiliary/issue_41053.rs b/src/test/run-pass/auxiliary/issue_41053.rs new file mode 100644 index 0000000000000..68e92b104298c --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_41053.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +pub struct Test; diff --git a/src/test/run-pass/issue-41053.rs b/src/test/run-pass/issue-41053.rs new file mode 100644 index 0000000000000..769d841e364d7 --- /dev/null +++ b/src/test/run-pass/issue-41053.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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:issue_41053.rs + +pub trait Trait { fn foo(&self) {} } + +pub struct Foo; + +impl Iterator for Foo { + type Item = Box; + fn next(&mut self) -> Option> { + extern crate issue_41053; + impl ::Trait for issue_41053::Test { + fn foo(&self) {} + } + Some(Box::new(issue_41053::Test)) + } +} + +fn main() { + Foo.next().unwrap().foo(); +} From a83734dd96e303f484972dba9b446b3dda478f2e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:19:36 -0400 Subject: [PATCH 505/662] remove `EffectCheck` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc/middle/effect.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 0521b50df4d2d..b3878819378f7 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -64,7 +64,6 @@ pub enum DepNode { CollectItem(D), CollectItemSig(D), Coherence, - EffectCheck, Liveness, Resolve, EntryPoint, @@ -219,7 +218,6 @@ impl DepNode { PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), - EffectCheck => Some(EffectCheck), Liveness => Some(Liveness), Resolve => Some(Resolve), EntryPoint => Some(EntryPoint), diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5af8e7e52d888..d2b8ed8c29707 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -12,7 +12,6 @@ //! `unsafe`. use self::RootUnsafeContext::*; -use dep_graph::DepNode; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; use lint; @@ -241,8 +240,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::EffectCheck); - let mut visitor = EffectCheckVisitor { tcx: tcx, tables: &ty::TypeckTables::empty(), From 6bc3d65948c3606c29beb8da359d2a45a36e5c15 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 4 Apr 2017 10:31:57 -0500 Subject: [PATCH 506/662] rustdoc: properly indent fn signatures in traits --- src/librustdoc/html/format.rs | 28 +++++++++++++++----- src/librustdoc/html/render.rs | 50 +++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fd069ed7e076b..9e45ccaff32ba 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -41,8 +41,6 @@ pub struct UnsafetySpace(pub hir::Unsafety); /// with a space after it. #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); -/// Wrapper struct for properly emitting a method declaration. -pub struct Method<'a>(pub &'a clean::FnDecl, pub usize); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -55,10 +53,23 @@ pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); pub struct CommaSep<'a, T: 'a>(pub &'a [T]); pub struct AbiSpace(pub Abi); +/// Wrapper struct for properly emitting a method declaration. +pub struct Method<'a> { + /// The declaration to emit. + pub decl: &'a clean::FnDecl, + /// The length of the function's "name", used to determine line-wrapping. + pub name_len: usize, + /// The number of spaces to indent each successive line with, if line-wrapping is necessary. + pub indent: usize, +} + /// Wrapper struct for emitting a where clause from Generics. pub struct WhereClause<'a>{ + /// The Generics from which to emit a where clause. pub gens: &'a clean::Generics, + /// The number of spaces to indent each line with. pub indent: usize, + /// Whether the where clause needs to add a comma and newline after the last bound. pub end_newline: bool, } @@ -936,8 +947,7 @@ impl fmt::Display for clean::FnDecl { impl<'a> fmt::Display for Method<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let decl = self.0; - let indent = self.1; + let &Method { decl, name_len, indent } = self; let amp = if f.alternate() { "&" } else { "&" }; let mut args = String::new(); let mut args_plain = String::new(); @@ -1004,15 +1014,19 @@ impl<'a> fmt::Display for Method<'a> { format!("{}", decl.output) }; - let pad = repeat(" ").take(indent).collect::(); + let pad = repeat(" ").take(name_len).collect::(); let plain = format!("{pad}({args}){arrow}", pad = pad, args = args_plain, arrow = arrow_plain); let output = if plain.len() > 80 { - let pad = "
        "; - format!("({args}
    ){arrow}", args = args.replace("
    ", pad), arrow = arrow) + let full_pad = format!("
    {}", repeat(" ").take(indent + 4).collect::()); + let close_pad = format!("
    {}", repeat(" ").take(indent).collect::()); + format!("({args}{close}){arrow}", + args = args.replace("
    ", &full_pad), + close = close_pad, + arrow = arrow) } else { format!("({args}){arrow}", args = args.replace("
    ", ""), arrow = arrow) }; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4eb228ce68f46..be69f6b8ec223 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1995,13 +1995,13 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, UnstableFeatures::Allow => f.constness, _ => hir::Constness::NotConst }; - let indent = format!("{}{}{}{:#}fn {}{:#}", - VisSpace(&it.visibility), - ConstnessSpace(vis_constness), - UnsafetySpace(f.unsafety), - AbiSpace(f.abi), - it.name.as_ref().unwrap(), - f.generics).len(); + let name_len = format!("{}{}{}{:#}fn {}{:#}", + VisSpace(&it.visibility), + ConstnessSpace(vis_constness), + UnsafetySpace(f.unsafety), + AbiSpace(f.abi), + it.name.as_ref().unwrap(), + f.generics).len(); write!(w, "
    ")?;
         render_attributes(w, it)?;
         write!(w, "{vis}{constness}{unsafety}{abi}fn \
    @@ -2013,7 +2013,11 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                name = it.name.as_ref().unwrap(),
                generics = f.generics,
                where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
    -           decl = Method(&f.decl, indent))?;
    +           decl = Method {
    +               decl: &f.decl,
    +               name_len: name_len,
    +               indent: 0,
    +           })?;
         document(w, cx, it)
     }
     
    @@ -2326,21 +2330,17 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                 UnstableFeatures::Allow => constness,
                 _ => hir::Constness::NotConst
             };
    -        let prefix = format!("{}{}{:#}fn {}{:#}",
    -                             ConstnessSpace(vis_constness),
    -                             UnsafetySpace(unsafety),
    -                             AbiSpace(abi),
    -                             name,
    -                             *g);
    -        let mut indent = prefix.len();
    -        let (where_indent, end_newline) = if parent == ItemType::Trait {
    -            indent += 4;
    +        let mut head_len = format!("{}{}{:#}fn {}{:#}",
    +                                   ConstnessSpace(vis_constness),
    +                                   UnsafetySpace(unsafety),
    +                                   AbiSpace(abi),
    +                                   name,
    +                                   *g).len();
    +        let (indent, end_newline) = if parent == ItemType::Trait {
    +            head_len += 4;
                 (4, false)
    -        } else if parent == ItemType::Impl {
    -            (0, true)
             } else {
    -            let prefix = prefix + &format!("{:#}", Method(d, indent));
    -            (prefix.lines().last().unwrap().len() + 1, true)
    +            (0, true)
             };
             write!(w, "{}{}{}fn {name}\
                        {generics}{decl}{where_clause}",
    @@ -2350,10 +2350,14 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                    href = href,
                    name = name,
                    generics = *g,
    -               decl = Method(d, indent),
    +               decl = Method {
    +                   decl: d,
    +                   name_len: head_len,
    +                   indent: indent,
    +               },
                    where_clause = WhereClause {
                        gens: g,
    -                   indent: where_indent,
    +                   indent: indent,
                        end_newline: end_newline,
                    })
         }
    
    From cd14a323f42cf57695e713a4f4fd00fddc10efd5 Mon Sep 17 00:00:00 2001
    From: "Stephen M. Coakley" 
    Date: Tue, 4 Apr 2017 10:44:57 -0500
    Subject: [PATCH 507/662] Use derived Debug for ThreadId
    
    ---
     src/libstd/thread/mod.rs | 9 +--------
     1 file changed, 1 insertion(+), 8 deletions(-)
    
    diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
    index 21f9757ad116b..9116f54173650 100644
    --- a/src/libstd/thread/mod.rs
    +++ b/src/libstd/thread/mod.rs
    @@ -670,7 +670,7 @@ pub fn park_timeout(dur: Duration) {
     /// assert!(thread::current().id() != other_thread_id);
     /// ```
     #[unstable(feature = "thread_id", issue = "21507")]
    -#[derive(Clone, Copy, Eq, PartialEq, Hash)]
    +#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
     pub struct ThreadId(u64);
     
     impl ThreadId {
    @@ -699,13 +699,6 @@ impl ThreadId {
         }
     }
     
    -#[unstable(feature = "thread_id", issue = "21507")]
    -impl fmt::Debug for ThreadId {
    -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    -        f.pad("ThreadId { .. }")
    -    }
    -}
    -
     ////////////////////////////////////////////////////////////////////////////////
     // Thread
     ////////////////////////////////////////////////////////////////////////////////
    
    From 3409f8d7cdfa2c60c5638930e3e68bbb6a911fc4 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
    Date: Tue, 4 Apr 2017 08:58:27 -0700
    Subject: [PATCH 508/662] Do not recommend private fields called as method
    
    ---
     src/librustc_typeck/check/method/suggest.rs   | 26 ++++++++++-------
     .../confuse-field-and-method/private-field.rs | 29 +++++++++++++++++++
     .../private-field.stderr                      |  8 +++++
     3 files changed, 52 insertions(+), 11 deletions(-)
     create mode 100644 src/test/ui/suggestions/confuse-field-and-method/private-field.rs
     create mode 100644 src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
    
    diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
    index 67ee7ef586530..4b975d7b324f9 100644
    --- a/src/librustc_typeck/check/method/suggest.rs
    +++ b/src/librustc_typeck/check/method/suggest.rs
    @@ -196,19 +196,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     
                                         let field_ty = field.ty(tcx, substs);
     
    -                                    if self.is_fn_ty(&field_ty, span) {
    -                                        err.help(&format!("use `({0}.{1})(...)` if you \
    -                                                           meant to call the function \
    -                                                           stored in the `{1}` field",
    -                                                          expr_string,
    -                                                          item_name));
    +                                    if tcx.vis_is_accessible_from(field.vis, self.body_id) {
    +                                        if self.is_fn_ty(&field_ty, span) {
    +                                            err.help(&format!("use `({0}.{1})(...)` if you \
    +                                                               meant to call the function \
    +                                                               stored in the `{1}` field",
    +                                                              expr_string,
    +                                                              item_name));
    +                                        } else {
    +                                            err.help(&format!("did you mean to write `{0}.{1}` \
    +                                                               instead of `{0}.{1}(...)`?",
    +                                                              expr_string,
    +                                                              item_name));
    +                                        }
    +                                        err.span_label(span, &"field, not a method");
                                         } else {
    -                                        err.help(&format!("did you mean to write `{0}.{1}` \
    -                                                           instead of `{0}.{1}(...)`?",
    -                                                          expr_string,
    -                                                          item_name));
    +                                        err.span_label(span, &"private field, not a method");
                                         }
    -                                    err.span_label(span, &"field, not a method");
                                         break;
                                     }
                                 }
    diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.rs b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs
    new file mode 100644
    index 0000000000000..94cf38fb32f2f
    --- /dev/null
    +++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs
    @@ -0,0 +1,29 @@
    +// Copyright 2017 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.
    +
    +pub mod animal {
    +    pub struct Dog {
    +        pub age: usize,
    +        dog_age: usize,
    +    }
    +
    +    impl Dog {
    +        pub fn new(age: usize) -> Dog {
    +            Dog { age: age, dog_age: age * 7 }
    +        }
    +    }
    +}
    +
    +fn main() {
    +    let dog = animal::Dog::new(3);
    +    let dog_age = dog.dog_age();
    +    //let dog_age = dog.dog_age;
    +    println!("{}", dog_age);
    +}
    diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
    new file mode 100644
    index 0000000000000..d07885915d2b7
    --- /dev/null
    +++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
    @@ -0,0 +1,8 @@
    +error: no method named `dog_age` found for type `animal::Dog` in the current scope
    +  --> $DIR/private-field.rs:26:23
    +   |
    +26 |     let dog_age = dog.dog_age();
    +   |                       ^^^^^^^ private field, not a method
    +
    +error: aborting due to previous error
    +
    
    From a2a4fad6f787869bc3ae96e02082938e0a6dbef9 Mon Sep 17 00:00:00 2001
    From: Niko Matsakis 
    Date: Tue, 4 Apr 2017 11:28:48 -0400
    Subject: [PATCH 509/662] kill `Liveness`
    
    ---
     src/librustc/dep_graph/dep_node.rs | 2 --
     src/librustc/middle/liveness.rs    | 2 --
     2 files changed, 4 deletions(-)
    
    diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
    index b3878819378f7..59d04ea8c771c 100644
    --- a/src/librustc/dep_graph/dep_node.rs
    +++ b/src/librustc/dep_graph/dep_node.rs
    @@ -64,7 +64,6 @@ pub enum DepNode {
         CollectItem(D),
         CollectItemSig(D),
         Coherence,
    -    Liveness,
         Resolve,
         EntryPoint,
         CheckEntryFn,
    @@ -218,7 +217,6 @@ impl DepNode {
                 PluginRegistrar => Some(PluginRegistrar),
                 StabilityIndex => Some(StabilityIndex),
                 Coherence => Some(Coherence),
    -            Liveness => Some(Liveness),
                 Resolve => Some(Resolve),
                 EntryPoint => Some(EntryPoint),
                 CheckEntryFn => Some(CheckEntryFn),
    diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
    index 7cae08efc0de0..b7da8480c1cef 100644
    --- a/src/librustc/middle/liveness.rs
    +++ b/src/librustc/middle/liveness.rs
    @@ -109,7 +109,6 @@ use self::LoopKind::*;
     use self::LiveNodeKind::*;
     use self::VarKind::*;
     
    -use dep_graph::DepNode;
     use hir::def::*;
     use ty::{self, TyCtxt, ParameterEnvironment};
     use traits::{self, Reveal};
    @@ -196,7 +195,6 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
     }
     
     pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    -    let _task = tcx.dep_graph.in_task(DepNode::Liveness);
         tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor());
         tcx.sess.abort_if_errors();
     }
    
    From a4d7c1fec361219d237f39b5e32c09c72ca69fac Mon Sep 17 00:00:00 2001
    From: Niko Matsakis 
    Date: Tue, 4 Apr 2017 12:06:35 -0400
    Subject: [PATCH 510/662] push `borrowck` into its own task
    
    ---
     src/librustc/hir/map/mod.rs           | 21 ++++++++++++++++++
     src/librustc/ty/maps.rs               |  2 ++
     src/librustc_borrowck/borrowck/mod.rs | 32 +++++++++++++--------------
     src/librustc_borrowck/lib.rs          |  2 ++
     src/librustc_driver/driver.rs         |  1 +
     5 files changed, 42 insertions(+), 16 deletions(-)
    
    diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
    index d7aa36b24f942..cfafec00ae20d 100644
    --- a/src/librustc/hir/map/mod.rs
    +++ b/src/librustc/hir/map/mod.rs
    @@ -442,6 +442,27 @@ impl<'hir> Map<'hir> {
             self.local_def_id(self.body_owner(id))
         }
     
    +    /// Given a body owner's id, returns the `BodyId` associated with it.
    +    pub fn body_owned_by(&self, id: NodeId) -> BodyId {
    +        if let Some(entry) = self.find_entry(id) {
    +            if let Some(body_id) = entry.associated_body() {
    +                // For item-like things and closures, the associated
    +                // body has its own distinct id, and that is returned
    +                // by `associated_body`.
    +                body_id
    +            } else {
    +                // For some expressions, the expression is its own body.
    +                if let EntryExpr(_, expr) = entry {
    +                    BodyId { node_id: expr.id }
    +                } else {
    +                    span_bug!(self.span(id), "id `{}` has no associated body", id);
    +                }
    +            }
    +        } else {
    +            bug!("no entry for id `{}`", id)
    +        }
    +    }
    +
         pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
             match self.get(id) {
                 NodeItem(&Item { node: ItemTrait(..), .. }) => id,
    diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
    index 4a183191cef29..219dbc4998e04 100644
    --- a/src/librustc/ty/maps.rs
    +++ b/src/librustc/ty/maps.rs
    @@ -423,6 +423,8 @@ define_maps! { <'tcx>
     
         pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
     
    +    pub borrowck: BorrowCheck(DefId) -> (),
    +
         /// Gets a complete map from all types to their inherent impls.
         /// Not meant to be used directly outside of coherence.
         /// (Defined only for LOCAL_CRATE)
    diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
    index 0915c57b588eb..e0b4a23010d2f 100644
    --- a/src/librustc_borrowck/borrowck/mod.rs
    +++ b/src/librustc_borrowck/borrowck/mod.rs
    @@ -22,7 +22,6 @@ pub use self::mir::elaborate_drops::ElaborateDrops;
     
     use self::InteriorKind::*;
     
    -use rustc::dep_graph::DepNode;
     use rustc::hir::map as hir_map;
     use rustc::hir::map::blocks::FnLikeNode;
     use rustc::cfg;
    @@ -37,12 +36,13 @@ use rustc::middle::mem_categorization::Categorization;
     use rustc::middle::mem_categorization::ImmutabilityBlame;
     use rustc::middle::region;
     use rustc::ty::{self, TyCtxt};
    +use rustc::ty::maps::Providers;
     
     use std::fmt;
     use std::rc::Rc;
     use std::hash::{Hash, Hasher};
     use syntax::ast;
    -use syntax_pos::{MultiSpan, Span};
    +use syntax_pos::{DUMMY_SP, MultiSpan, Span};
     use errors::DiagnosticBuilder;
     
     use rustc::hir;
    @@ -62,16 +62,16 @@ pub struct LoanDataFlowOperator;
     pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
     
     pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    -    tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task);
    -
    -    fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
    -        tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| {
    -            tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id),
    -                                    tcx,
    -                                    body_id,
    -                                    borrowck_fn);
    -        });
    -    }
    +    tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
    +        ty::queries::borrowck::get(tcx, DUMMY_SP, body_owner_def_id);
    +    });
    +}
    +
    +pub fn provide(providers: &mut Providers) {
    +    *providers = Providers {
    +        borrowck: borrowck,
    +        ..*providers
    +    };
     }
     
     /// Collection of conclusions determined via borrow checker analyses.
    @@ -81,11 +81,11 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
         pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
     }
     
    -fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) {
    -    debug!("borrowck_fn(body_id={:?})", body_id);
    +fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
    +    debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
     
    -    let owner_id = tcx.hir.body_owner(body_id);
    -    let owner_def_id = tcx.hir.local_def_id(owner_id);
    +    let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
    +    let body_id = tcx.hir.body_owned_by(owner_id);
         let attributes = tcx.get_attrs(owner_def_id);
         let tables = tcx.item_tables(owner_def_id);
     
    diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
    index d3b22884a3d8c..a1d3357faf566 100644
    --- a/src/librustc_borrowck/lib.rs
    +++ b/src/librustc_borrowck/lib.rs
    @@ -51,4 +51,6 @@ mod borrowck;
     
     pub mod graphviz;
     
    +pub use borrowck::provide;
    +
     __build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
    diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
    index 977382b33adf7..13486d898cff3 100644
    --- a/src/librustc_driver/driver.rs
    +++ b/src/librustc_driver/driver.rs
    @@ -887,6 +887,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
         let mut local_providers = ty::maps::Providers::default();
         mir::provide(&mut local_providers);
         rustc_privacy::provide(&mut local_providers);
    +    borrowck::provide(&mut local_providers);
         typeck::provide(&mut local_providers);
         ty::provide(&mut local_providers);
     
    
    From b012adc354100ee95c1695ae7934e86683f1774e Mon Sep 17 00:00:00 2001
    From: Tim Neumann 
    Date: Tue, 4 Apr 2017 18:14:14 +0200
    Subject: [PATCH 511/662] update image name for DEPLOY_ALT
    
    ---
     .travis.yml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/.travis.yml b/.travis.yml
    index a8c9337fa81b2..e5b57a389ecbe 100644
    --- a/.travis.yml
    +++ b/.travis.yml
    @@ -112,7 +112,7 @@ matrix:
         # turned on, they're deployed to a different location primarily for projects
         # which are stuck on nightly and don't want llvm assertions in the artifacts
         # that they use.
    -    - env: IMAGE=dist-x86-linux DEPLOY_ALT=1
    +    - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1
         - env: >
             RUST_CHECK_TARGET=dist
             RUST_CONFIGURE_ARGS="--enable-extended"
    
    From 5bffa0aa50f7456249e4ffdd3e7cbf72f743a56d Mon Sep 17 00:00:00 2001
    From: QuietMisdreavus 
    Date: Tue, 4 Apr 2017 11:16:16 -0500
    Subject: [PATCH 512/662] rustdoc: don't add a space before `{` on traits with
     where clauses
    
    cc #41025
    ---
     src/librustdoc/html/render.rs | 11 ++++++++---
     1 file changed, 8 insertions(+), 3 deletions(-)
    
    diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
    index be69f6b8ec223..b1ac6a5127f2a 100644
    --- a/src/librustdoc/html/render.rs
    +++ b/src/librustdoc/html/render.rs
    @@ -2045,13 +2045,18 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         // Output the trait definition
         write!(w, "
    ")?;
         render_attributes(w, it)?;
    -    write!(w, "{}{}trait {}{}{}{} ",
    +    write!(w, "{}{}trait {}{}{}",
                VisSpace(&it.visibility),
                UnsafetySpace(t.unsafety),
                it.name.as_ref().unwrap(),
                t.generics,
    -           bounds,
    -           WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
    +           bounds)?;
    +
    +    if !t.generics.where_predicates.is_empty() {
    +        write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
    +    } else {
    +        write!(w, " ")?;
    +    }
     
         let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>();
         let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>();
    
    From 8c01ce3d2552529af7597a60329d0552d2b0f325 Mon Sep 17 00:00:00 2001
    From: Alex Crichton 
    Date: Mon, 3 Apr 2017 11:41:45 -0700
    Subject: [PATCH 513/662] std: Use `poll` instead of `select`
    
    This gives us the benefit of supporting file descriptors over the limit that
    select supports, which...
    
    Closes #40894
    ---
     src/libstd/sys/unix/pipe.rs | 22 +++++++++-------------
     1 file changed, 9 insertions(+), 13 deletions(-)
    
    diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
    index 51e00fc1ab96a..706256ff10ec9 100644
    --- a/src/libstd/sys/unix/pipe.rs
    +++ b/src/libstd/sys/unix/pipe.rs
    @@ -8,11 +8,9 @@
     // option. This file may not be copied, modified, or distributed
     // except according to those terms.
     
    -use cmp;
     use io;
     use libc::{self, c_int};
     use mem;
    -use ptr;
     use sys::{cvt, cvt_r};
     use sys::fd::FileDesc;
     
    @@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe,
         p1.set_nonblocking(true)?;
         p2.set_nonblocking(true)?;
     
    -    let max = cmp::max(p1.raw(), p2.raw());
    +    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
    +    fds[0].fd = p1.raw();
    +    fds[0].events = libc::POLLIN;
    +    fds[1].fd = p2.raw();
    +    fds[1].events = libc::POLLIN;
         loop {
    -        // wait for either pipe to become readable using `select`
    -        cvt_r(|| unsafe {
    -            let mut read: libc::fd_set = mem::zeroed();
    -            libc::FD_SET(p1.raw(), &mut read);
    -            libc::FD_SET(p2.raw(), &mut read);
    -            libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
    -                         ptr::null_mut())
    -        })?;
    +        // wait for either pipe to become readable using `poll`
    +        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
     
             // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
             // EAGAIN. If we hit EOF, then this will happen because the underlying
    @@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe,
                     }
                 }
             };
    -        if read(&p1, v1)? {
    +        if fds[0].revents != 0 && read(&p1, v1)? {
                 p2.set_nonblocking(false)?;
                 return p2.read_to_end(v2).map(|_| ());
             }
    -        if read(&p2, v2)? {
    +        if fds[1].revents != 0 && read(&p2, v2)? {
                 p1.set_nonblocking(false)?;
                 return p1.read_to_end(v1).map(|_| ());
             }
    
    From 2e3f0d845113995c26a9d59dd69146975a692516 Mon Sep 17 00:00:00 2001
    From: Jason Orendorff 
    Date: Mon, 3 Apr 2017 15:25:30 -0500
    Subject: [PATCH 514/662] add [T]::rsplit() and rsplit_mut() #41020
    
    ---
     src/doc/unstable-book/src/SUMMARY.md      |   1 +
     src/doc/unstable-book/src/slice-rsplit.md |  10 ++
     src/libcollections/lib.rs                 |   1 +
     src/libcollections/slice.rs               |  68 +++++++++++
     src/libcore/slice/mod.rs                  | 139 ++++++++++++++++++++++
     5 files changed, 219 insertions(+)
     create mode 100644 src/doc/unstable-book/src/slice-rsplit.md
    
    diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
    index 292f5a1ec816a..52f33244695ea 100644
    --- a/src/doc/unstable-book/src/SUMMARY.md
    +++ b/src/doc/unstable-book/src/SUMMARY.md
    @@ -171,6 +171,7 @@
     - [slice_concat_ext](slice-concat-ext.md)
     - [slice_get_slice](slice-get-slice.md)
     - [slice_patterns](slice-patterns.md)
    +- [slice_rsplit](slice-rsplit.md)
     - [sort_internals](sort-internals.md)
     - [sort_unstable](sort-unstable.md)
     - [specialization](specialization.md)
    diff --git a/src/doc/unstable-book/src/slice-rsplit.md b/src/doc/unstable-book/src/slice-rsplit.md
    new file mode 100644
    index 0000000000000..8c2954f7294e0
    --- /dev/null
    +++ b/src/doc/unstable-book/src/slice-rsplit.md
    @@ -0,0 +1,10 @@
    +# `slice_rsplit`
    +
    +The tracking issue for this feature is: [#41020]
    +
    +[#41020]: https://github.com/rust-lang/rust/issues/41020
    +
    +------------------------
    +
    +The `slice_rsplit` feature enables two methods on slices:
    +`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`.
    diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
    index 00448b6abb2cf..ff020f53e0e77 100644
    --- a/src/libcollections/lib.rs
    +++ b/src/libcollections/lib.rs
    @@ -52,6 +52,7 @@
     #![feature(shared)]
     #![feature(slice_get_slice)]
     #![feature(slice_patterns)]
    +#![feature(slice_rsplit)]
     #![cfg_attr(not(test), feature(sort_unstable))]
     #![feature(specialization)]
     #![feature(staged_api)]
    diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
    index 6f8843c2374bc..6cff315a6ccd9 100644
    --- a/src/libcollections/slice.rs
    +++ b/src/libcollections/slice.rs
    @@ -115,6 +115,8 @@ pub use core::slice::{Iter, IterMut};
     pub use core::slice::{SplitMut, ChunksMut, Split};
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
    +#[unstable(feature = "slice_rsplit", issue = "41020")]
    +pub use core::slice::{RSplit, RSplitMut};
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use core::slice::{from_raw_parts, from_raw_parts_mut};
     #[unstable(feature = "slice_get_slice", issue = "35729")]
    @@ -779,6 +781,72 @@ impl [T] {
             core_slice::SliceExt::split_mut(self, pred)
         }
     
    +    /// Returns an iterator over subslices separated by elements that match
    +    /// `pred`, starting at the end of the slice and working backwards.
    +    /// The matched element is not contained in the subslices.
    +    ///
    +    /// # Examples
    +    ///
    +    /// ```
    +    /// #![feature(slice_rsplit)]
    +    ///
    +    /// let slice = [11, 22, 33, 0, 44, 55];
    +    /// let mut iter = slice.rsplit(|num| *num == 0);
    +    ///
    +    /// assert_eq!(iter.next().unwrap(), &[44, 55]);
    +    /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
    +    /// assert_eq!(iter.next(), None);
    +    /// ```
    +    ///
    +    /// As with `split()`, if the first or last element is matched, an empty
    +    /// slice will be the first (or last) item returned by the iterator.
    +    ///
    +    /// ```
    +    /// #![feature(slice_rsplit)]
    +    ///
    +    /// let v = &[0, 1, 1, 2, 3, 5, 8];
    +    /// let mut it = v.rsplit(|n| *n % 2 == 0);
    +    /// assert_eq!(it.next().unwrap(), &[]);
    +    /// assert_eq!(it.next().unwrap(), &[3, 5]);
    +    /// assert_eq!(it.next().unwrap(), &[1, 1]);
    +    /// assert_eq!(it.next().unwrap(), &[]);
    +    /// assert_eq!(it.next(), None);
    +    /// ```
    +    #[unstable(feature = "slice_rsplit", issue = "41020")]
    +    #[inline]
    +    pub fn rsplit(&self, pred: F) -> RSplit
    +        where F: FnMut(&T) -> bool
    +    {
    +        core_slice::SliceExt::rsplit(self, pred)
    +    }
    +
    +    /// Returns an iterator over mutable subslices separated by elements that
    +    /// match `pred`, starting at the end of the slice and working
    +    /// backwards. The matched element is not contained in the subslices.
    +    ///
    +    /// # Examples
    +    ///
    +    /// ```
    +    /// #![feature(slice_rsplit)]
    +    ///
    +    /// let mut v = [100, 400, 300, 200, 600, 500];
    +    ///
    +    /// let mut count = 0;
    +    /// for group in v.rsplit_mut(|num| *num % 3 == 0) {
    +    ///     count += 1;
    +    ///     group[0] = count;
    +    /// }
    +    /// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
    +    /// ```
    +    ///
    +    #[unstable(feature = "slice_rsplit", issue = "41020")]
    +    #[inline]
    +    pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut
    +        where F: FnMut(&T) -> bool
    +    {
    +        core_slice::SliceExt::rsplit_mut(self, pred)
    +    }
    +
         /// Returns an iterator over subslices separated by elements that match
         /// `pred`, limited to returning at most `n` items. The matched element is
         /// not contained in the subslices.
    diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
    index 45667bb42993d..1e0037755c1ab 100644
    --- a/src/libcore/slice/mod.rs
    +++ b/src/libcore/slice/mod.rs
    @@ -81,6 +81,10 @@ pub trait SliceExt {
         fn split

    (&self, pred: P) -> Split where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + fn rsplit

    (&self, pred: P) -> RSplit + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn

    (&self, n: usize, pred: P) -> SplitN where P: FnMut(&Self::Item) -> bool; @@ -159,6 +163,10 @@ pub trait SliceExt { fn split_mut

    (&mut self, pred: P) -> SplitMut where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + fn rsplit_mut

    (&mut self, pred: P) -> RSplitMut + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn_mut

    (&mut self, n: usize, pred: P) -> SplitNMut where P: FnMut(&Self::Item) -> bool; @@ -293,6 +301,13 @@ impl SliceExt for [T] { } } + #[inline] + fn rsplit

    (&self, pred: P) -> RSplit + where P: FnMut(&T) -> bool + { + RSplit { inner: self.split(pred) } + } + #[inline] fn splitn

    (&self, n: usize, pred: P) -> SplitN where P: FnMut(&T) -> bool @@ -475,6 +490,13 @@ impl SliceExt for [T] { SplitMut { v: self, pred: pred, finished: false } } + #[inline] + fn rsplit_mut

    (&mut self, pred: P) -> RSplitMut + where P: FnMut(&T) -> bool + { + RSplitMut { inner: self.split_mut(pred) } + } + #[inline] fn splitn_mut

    (&mut self, n: usize, pred: P) -> SplitNMut where P: FnMut(&T) -> bool @@ -1735,6 +1757,123 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where #[unstable(feature = "fused", issue = "35602")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} +/// An iterator over subslices separated by elements that match a predicate +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? +pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: Split<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSplit") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the subslices of the vector which are separated +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: SplitMut<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSplitMut") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} + /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. From a45fedfa384fba4f972c2af26adb9cf7a0522725 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 3 Apr 2017 15:27:42 -0500 Subject: [PATCH 515/662] simplify implementation of [T]::splitn and friends #41020 --- src/libcore/slice/mod.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 1e0037755c1ab..6e3f11ec7fbae 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -315,8 +315,7 @@ impl SliceExt for [T] { SplitN { inner: GenericSplitN { iter: self.split(pred), - count: n, - invert: false + count: n } } } @@ -327,9 +326,8 @@ impl SliceExt for [T] { { RSplitN { inner: GenericSplitN { - iter: self.split(pred), - count: n, - invert: true + iter: self.rsplit(pred), + count: n } } } @@ -504,8 +502,7 @@ impl SliceExt for [T] { SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), - count: n, - invert: false + count: n } } } @@ -516,9 +513,8 @@ impl SliceExt for [T] { { RSplitNMut { inner: GenericSplitN { - iter: self.split_mut(pred), - count: n, - invert: true + iter: self.rsplit_mut(pred), + count: n } } } @@ -1881,7 +1877,6 @@ impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool struct GenericSplitN { iter: I, count: usize, - invert: bool } impl> Iterator for GenericSplitN { @@ -1892,10 +1887,7 @@ impl> Iterator for GenericSplitN { match self.count { 0 => None, 1 => { self.count -= 1; self.iter.finish() } - _ => { - self.count -= 1; - if self.invert {self.iter.next_back()} else {self.iter.next()} - } + _ => { self.count -= 1; self.iter.next() } } } @@ -1937,7 +1929,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitN<'a, T, P> where P: FnMut(& /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN> + inner: GenericSplitN> } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -1980,7 +1972,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitNMut<'a, T, P> where P: FnMu /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN> + inner: GenericSplitN> } #[stable(feature = "core_impl_debug", since = "1.9.0")] From 086627ecd24308d773a9e5a2765d0c1f19f0226e Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 4 Apr 2017 15:39:44 -0400 Subject: [PATCH 516/662] Fix links part of https://github.com/rust-lang/rust/issues/40912 []\n() is not actually a link. --- src/libcollections/linked_list.rs | 4 +- src/libcore/intrinsics.rs | 90 ++++++++++++++++++------------- src/libtest/stats.rs | 6 ++- 3 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 8f0488f69369e..1b3eeb837d909 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -697,8 +697,8 @@ impl LinkedList { /// Returns a place for insertion at the front of the list. /// - /// Using this method with placement syntax is equivalent to [`push_front`] - /// (#method.push_front), but may be more efficient. + /// Using this method with placement syntax is equivalent to + /// [`push_front`](#method.push_front), but may be more efficient. /// /// # Examples /// diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ae8b6bb45113..7339fb56e5b49 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -61,16 +61,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -79,8 +81,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -89,16 +92,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -107,8 +112,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -117,8 +123,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -127,8 +134,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -137,8 +145,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. @@ -146,16 +155,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -164,8 +175,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -174,16 +186,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -192,8 +206,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -202,8 +217,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -212,8 +228,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -222,8 +239,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 077d57a9da389..f04394f716660 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -39,8 +39,10 @@ pub trait Stats { /// /// Note: this method sacrifices performance at the altar of accuracy /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: - /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"] - /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps) + /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric + /// Predicates"][paper] + /// + /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps fn sum(&self) -> f64; /// Minimum value of the samples. From ea2bfae8694221c92857a0b3dd96f63a8a255db2 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 4 Apr 2017 13:50:24 -0600 Subject: [PATCH 517/662] Branch arms need to match the return value even if it's not being assigned to anything --- src/bootstrap/flags.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 3af3b76163c1e..a1466d68a135a 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -137,10 +137,10 @@ To learn more about a subcommand, run `./x.py -h`"); // Some subcommands get extra options match subcommand.as_str() { - "test" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), - "bench" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), - "dist" => opts.optflag("", "install", "run installer as well"), - _ => { } + "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "dist" => { opts.optflag("", "install", "run installer as well"); }, + _ => { }, }; // Done specifying what options are possible, so do the getopts parsing From c7f2dbef90231eab0b0f2032854823d192a964eb Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Tue, 4 Apr 2017 16:23:52 -0400 Subject: [PATCH 518/662] Change docs to follow review requests --- src/libstd/process.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 265228281f853..123138daeeaea 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -233,9 +233,9 @@ impl fmt::Debug for ChildStdout { } } -/// A handle to a child process's stderr. It can be used to -/// read any errors that the child process has output while -/// running. +/// A handle to a child process's stderr. +/// +/// This struct is used in the [`stderr`] field on [`Child`]. /// /// [`Child`]: struct.Child.html /// [`stderr`]: struct.Child.html#structfield.stderr From f07ebd609796226e672737e502525fbbf5e27940 Mon Sep 17 00:00:00 2001 From: arthurprs Date: Wed, 15 Mar 2017 23:26:27 +0100 Subject: [PATCH 519/662] Simplify HashMap Bucket interface * Store capacity_mask instead of capacity * Move bucket index into RawBucket * Bucket index is now always within [0..table_capacity) * Clone RawTable using RawBucket * Simplify iterators by moving logic into RawBuckets * Make retain aware of the number of elements --- src/libstd/collections/hash/map.rs | 32 ++- src/libstd/collections/hash/table.rs | 324 +++++++++++++-------------- 2 files changed, 165 insertions(+), 191 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 5733217008146..a06299eaefe0a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -472,7 +472,7 @@ fn pop_internal(starting_bucket: FullBucketMut) } // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_bucket().into_table()) + (retkey, retval, gap.into_table()) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, mut key: K, mut val: V) -> FullBucketMut<'a, K, V> { - let start_index = bucket.index(); let size = bucket.table().size(); - // Save the *starting point*. - let mut bucket = bucket.stash(); + let raw_capacity = bucket.table().capacity(); // There can be at most `size - dib` buckets to displace, because // in the worst case, there are `size` elements and we already are // `displacement` buckets away from the initial one. - let idx_end = start_index + size - bucket.displacement(); + let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; + // Save the *starting point*. + let mut bucket = bucket.stash(); loop { let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); @@ -568,11 +568,8 @@ impl HashMap // The caller should ensure that invariants by Robin Hood Hashing hold // and that there's space in the underlying table. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); - // note that buckets.index() keeps increasing - // even if the pointer wraps back to the first bucket. - let limit_bucket = buckets.index() + raw_cap; + let start_index = buckets.index(); loop { // We don't need to compare hashes for value swap. @@ -585,7 +582,7 @@ impl HashMap Full(b) => b.into_bucket(), }; buckets.next(); - debug_assert!(buckets.index() < limit_bucket); + debug_assert!(buckets.index() != start_index); } } } @@ -1244,24 +1241,25 @@ impl HashMap pub fn retain(&mut self, mut f: F) where F: FnMut(&K, &mut V) -> bool { - if self.table.capacity() == 0 || self.table.size() == 0 { + if self.table.size() == 0 { return; } + let mut elems_left = self.table.size(); let mut bucket = Bucket::head_bucket(&mut self.table); bucket.prev(); - let tail = bucket.index(); - loop { + let start_index = bucket.index(); + while elems_left != 0 { bucket = match bucket.peek() { Full(mut full) => { + elems_left -= 1; let should_remove = { let (k, v) = full.read_mut(); !f(k, v) }; if should_remove { - let prev_idx = full.index(); let prev_raw = full.raw(); let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, prev_idx, t) + Bucket::new_from(prev_raw, t) } else { full.into_bucket() } @@ -1271,9 +1269,7 @@ impl HashMap } }; bucket.prev(); // reverse iteration - if bucket.index() == tail { - break; - } + debug_assert!(elems_left == 0 || bucket.index() != start_index); } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index da5fb1a47333e..9623706548b32 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -113,7 +113,7 @@ impl TaggedHashUintPtr { /// when the RawTable is created and is accessible with the `tag` and `set_tag` /// functions. pub struct RawTable { - capacity: usize, + capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, @@ -125,10 +125,13 @@ pub struct RawTable { unsafe impl Send for RawTable {} unsafe impl Sync for RawTable {} +// An unsafe view of a RawTable bucket +// Valid indexes are within [0..table_capacity) pub struct RawBucket { - hash: *mut HashUint, + hash_start: *mut HashUint, // We use *const to ensure covariance with respect to K and V - pair: *const (K, V), + pair_start: *const (K, V), + idx: usize, _marker: marker::PhantomData<(K, V)>, } @@ -141,7 +144,6 @@ impl Clone for RawBucket { pub struct Bucket { raw: RawBucket, - idx: usize, table: M, } @@ -154,13 +156,11 @@ impl Clone for Bucket { pub struct EmptyBucket { raw: RawBucket, - idx: usize, table: M, } pub struct FullBucket { raw: RawBucket, - idx: usize, table: M, } @@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() { assert_eq!(size_of::(), size_of::()) } +// RawBucket methods are unsafe as it's possible to +// make a RawBucket point to invalid memory using safe code. impl RawBucket { - unsafe fn offset(self, count: isize) -> RawBucket { - RawBucket { - hash: self.hash.offset(count), - pair: self.pair.offset(count), - _marker: marker::PhantomData, - } + unsafe fn hash(&self) -> *mut HashUint { + self.hash_start.offset(self.idx as isize) + } + unsafe fn pair(&self) -> *mut (K, V) { + self.pair_start.offset(self.idx as isize) as *mut (K, V) + } + unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { + (self.hash(), self.pair()) } } @@ -258,7 +262,7 @@ impl FullBucket { } /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// Get the raw bucket. pub fn raw(&self) -> RawBucket { @@ -280,7 +284,7 @@ impl EmptyBucket { impl Bucket { /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// get the table. pub fn into_table(self) -> M { @@ -331,12 +335,11 @@ impl>> Bucket { Bucket::at_index(table, hash.inspect() as usize) } - pub fn new_from(r: RawBucket, i: usize, t: M) + pub fn new_from(r: RawBucket, t: M) -> Bucket { Bucket { raw: r, - idx: i, table: t, } } @@ -346,18 +349,16 @@ impl>> Bucket { // This is an uncommon case though, so avoid it in release builds. debug_assert!(table.capacity() > 0, "Table should have capacity at this point"); - let ib_index = ib_index & (table.capacity() - 1); + let ib_index = ib_index & table.capacity_mask; Bucket { - raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) }, - idx: ib_index, + raw: table.raw_bucket_at(ib_index), table: table, } } pub fn first(table: M) -> Bucket { Bucket { - raw: table.first_bucket_raw(), - idx: 0, + raw: table.raw_bucket_at(0), table: table, } } @@ -401,48 +402,30 @@ impl>> Bucket { /// the appropriate types to call most of the other functions in /// this module. pub fn peek(self) -> BucketState { - match unsafe { *self.raw.hash } { + match unsafe { *self.raw.hash() } { EMPTY_BUCKET => { Empty(EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } _ => { Full(FullBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } } } - /// Modifies the bucket pointer in place to make it point to the next slot. + /// Modifies the bucket in place to make it point to the next slot. pub fn next(&mut self) { - self.idx += 1; - let range = self.table.capacity(); - // This code is branchless thanks to a conditional move. - let dist = if self.idx & (range - 1) == 0 { - 1 - range as isize - } else { - 1 - }; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; } - /// Modifies the bucket pointer in place to make it point to the previous slot. + /// Modifies the bucket in place to make it point to the previous slot. pub fn prev(&mut self) { - let range = self.table.capacity(); - let new_idx = self.idx.wrapping_sub(1) & (range - 1); - let dist = (new_idx as isize).wrapping_sub(self.idx as isize); - self.idx = new_idx; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; } } @@ -458,7 +441,6 @@ impl>> EmptyBucket { pub fn into_bucket(self) -> Bucket { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -466,7 +448,6 @@ impl>> EmptyBucket { pub fn gap_peek(self) -> Result, Bucket> { let gap = EmptyBucket { raw: self.raw, - idx: self.idx, table: (), }; @@ -494,15 +475,14 @@ impl EmptyBucket /// Use `make_hash` to construct a `SafeHash` to pass to this function. pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { unsafe { - *self.raw.hash = hash.inspect(); - ptr::write(self.raw.pair as *mut (K, V), (key, value)); + *self.raw.hash() = hash.inspect(); + ptr::write(self.raw.pair(), (key, value)); self.table.borrow_table_mut().size += 1; } FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -510,15 +490,14 @@ impl EmptyBucket /// Puts given key, remain value uninitialized. /// It is only used for inplacement insertion. pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket { - *self.raw.hash = hash.inspect(); - let pair_mut = self.raw.pair as *mut (K, V); - ptr::write(&mut (*pair_mut).0, key); + *self.raw.hash() = hash.inspect(); + let pair_ptr = self.raw.pair(); + ptr::write(&mut (*pair_ptr).0, key); self.table.borrow_table_mut().size += 1; FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -536,7 +515,6 @@ impl>> FullBucket { pub fn into_bucket(self) -> Bucket { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -546,7 +524,6 @@ impl>> FullBucket { pub fn stash(self) -> FullBucket { FullBucket { raw: self.raw, - idx: self.idx, table: self, } } @@ -560,17 +537,20 @@ impl>> FullBucket { // Calculates the distance one has to travel when going from // `hash mod capacity` onwards to `idx mod capacity`, wrapping around // if the destination is not reached before the end of the table. - (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1) + (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask } #[inline] pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash } } + unsafe { SafeHash { hash: *self.raw.hash() } } } /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -586,11 +566,10 @@ impl<'t, K, V> FullBucket> { self.table.size -= 1; unsafe { - *self.raw.hash = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair); + *self.raw.hash() = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair()); (EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }, k, @@ -604,9 +583,9 @@ impl<'t, K, V> FullBucket> { pub unsafe fn remove_key(&mut self) { self.table.size -= 1; - *self.raw.hash = EMPTY_BUCKET; - let pair_mut = self.raw.pair as *mut (K, V); - ptr::drop_in_place(&mut (*pair_mut).0); // only drop key + *self.raw.hash() = EMPTY_BUCKET; + let pair_ptr = self.raw.pair(); + ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key } } @@ -617,8 +596,8 @@ impl FullBucket { pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { - let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); + let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); + let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); (old_hash, old_key, old_val) } @@ -630,8 +609,10 @@ impl FullBucket { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -667,22 +653,23 @@ impl GapThenFull &self.full } - pub fn into_bucket(self) -> Bucket { - self.full.into_bucket() + pub fn into_table(self) -> M { + self.full.into_table() } pub fn shift(mut self) -> Result, Bucket> { unsafe { - *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); + let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); + let (full_hash, full_pair) = self.full.raw.hash_pair(); + *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); + ptr::copy_nonoverlapping(full_pair, gap_pair, 1); } - let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; + let FullBucket { raw: prev_raw, .. } = self.full; match self.full.next().peek() { Full(bucket) => { self.gap.raw = prev_raw; - self.gap.idx = prev_idx; self.full = bucket; @@ -761,7 +748,7 @@ impl RawTable { if capacity == 0 { return RawTable { size: 0, - capacity: 0, + capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; @@ -801,25 +788,27 @@ impl RawTable { let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { - capacity: capacity, + capacity_mask: capacity.wrapping_sub(1), size: 0, hashes: TaggedHashUintPtr::new(hashes), marker: marker::PhantomData, } } - fn first_bucket_raw(&self) -> RawBucket { - let hashes_size = self.capacity * size_of::(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + fn raw_bucket_at(&self, index: usize) -> RawBucket { + let hashes_size = self.capacity() * size_of::(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); - let buffer = self.hashes.ptr() as *mut u8; let (pairs_offset, _, oflo) = calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); + + let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { - hash: self.hashes.ptr(), - pair: buffer.offset(pairs_offset as isize) as *const _, + hash_start: buffer as *mut HashUint, + pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + idx: index, _marker: marker::PhantomData, } } @@ -837,7 +826,7 @@ impl RawTable { /// The hashtable's capacity, similar to a vector's. pub fn capacity(&self) -> usize { - self.capacity + self.capacity_mask.wrapping_add(1) } /// The number of elements ever `put` in the hashtable, minus the number @@ -848,8 +837,8 @@ impl RawTable { fn raw_buckets(&self) -> RawBuckets { RawBuckets { - raw: self.first_bucket_raw(), - hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) }, + raw: self.raw_bucket_at(0), + elems_left: self.size, marker: marker::PhantomData, } } @@ -857,25 +846,23 @@ impl RawTable { pub fn iter(&self) -> Iter { Iter { iter: self.raw_buckets(), - elems_left: self.size(), } } pub fn iter_mut(&mut self) -> IterMut { IterMut { iter: self.raw_buckets(), - elems_left: self.size(), _marker: marker::PhantomData, } } pub fn into_iter(self) -> IntoIter { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. IntoIter { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: self, @@ -883,12 +870,12 @@ impl RawTable { } pub fn drain(&mut self) -> Drain { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. Drain { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: unsafe { Shared::new(self) }, @@ -900,18 +887,16 @@ impl RawTable { /// state and should only be used for dropping the table's remaining /// entries. It's used in the implementation of Drop. unsafe fn rev_drop_buckets(&mut self) { - let first_raw = self.first_bucket_raw(); - let mut raw = first_raw.offset(self.capacity as isize); + // initialize the raw bucket past the end of the table + let mut raw = self.raw_bucket_at(self.capacity()); let mut elems_left = self.size; while elems_left != 0 { - debug_assert!(raw.hash != first_raw.hash); + raw.idx -= 1; - raw = raw.offset(-1); - - if *raw.hash != EMPTY_BUCKET { + if *raw.hash() != EMPTY_BUCKET { elems_left -= 1; - ptr::drop_in_place(raw.pair as *mut (K, V)); + ptr::drop_in_place(raw.pair()); } } } @@ -931,7 +916,7 @@ impl RawTable { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket, - hashes_end: *mut HashUint, + elems_left: usize, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> { fn clone(&self) -> RawBuckets<'a, K, V> { RawBuckets { raw: self.raw, - hashes_end: self.hashes_end, + elems_left: self.elems_left, marker: marker::PhantomData, } } @@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { type Item = RawBucket; fn next(&mut self) -> Option> { - while self.raw.hash != self.hashes_end { + if self.elems_left == 0 { + return None; + } + + loop { unsafe { - // We are swapping out the pointer to a bucket and replacing - // it with the pointer to the next one. - let prev = ptr::replace(&mut self.raw, self.raw.offset(1)); - if *prev.hash != EMPTY_BUCKET { - return Some(prev); + let item = self.raw; + self.raw.idx += 1; + if *item.hash() != EMPTY_BUCKET { + self.elems_left -= 1; + return Some(item); } } } + } + + fn size_hint(&self) -> (usize, Option) { + (self.elems_left, Some(self.elems_left)) + } +} - None +impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> { + fn len(&self) -> usize { + self.elems_left } } /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, } unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} @@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } - /// Iterator over mutable references to entries in a table. pub struct IterMut<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, // To ensure invariance with respect to V _marker: marker::PhantomData<&'a mut V>, } @@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { pub fn iter(&self) -> Iter { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } @@ -1027,7 +1019,6 @@ impl IntoIter { pub fn iter(&self) -> Iter { Iter { iter: self.iter.clone(), - elems_left: self.table.size, } } } @@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} impl<'a, K, V> Drain<'a, K, V> { pub fn iter(&self) -> Iter { - unsafe { - Iter { - iter: self.iter.clone(), - elems_left: (**self.table).size, - } + Iter { + iter: self.iter.clone(), } } } @@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - let pair_mut = bucket.pair as *mut (K, V); - unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &mut (*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1098,23 +1087,23 @@ impl Iterator for IntoIter { type Item = (SafeHash, K, V); fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { + self.iter.next().map(|raw| { self.table.size -= 1; unsafe { - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: *bucket.hash }, k, v) + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: *raw.hash() }, k, v) } }) } fn size_hint(&self) -> (usize, Option) { - let size = self.table.size(); - (size, Some(size)) + self.iter.size_hint() } } + impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { - self.table.size() + self.iter().len() } } @@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { - unsafe { - (*self.table.as_mut_ptr()).size -= 1; - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) - } + self.iter.next().map(|raw| unsafe { + (*self.table.as_mut_ptr()).size -= 1; + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) }) } fn size_hint(&self) -> (usize, Option) { - let size = unsafe { (**self.table).size() }; - (size, Some(size)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - unsafe { (**self.table).size() } + self.iter.len() } } @@ -1152,30 +1139,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { impl Clone for RawTable { fn clone(&self) -> RawTable { unsafe { - let mut new_ht = RawTable::new_uninitialized(self.capacity()); - - { - let cap = self.capacity(); - let mut new_buckets = Bucket::first(&mut new_ht); - let mut buckets = Bucket::first(self); - while buckets.index() != cap { - match buckets.peek() { - Full(full) => { - let (h, k, v) = { - let (k, v) = full.read(); - (full.hash(), k.clone(), v.clone()) - }; - *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); - } - Empty(..) => { - *new_buckets.raw.hash = EMPTY_BUCKET; - } - } - new_buckets.next(); - buckets.next(); + let cap = self.capacity(); + let mut new_ht = RawTable::new_uninitialized(cap); + + let mut new_buckets = new_ht.raw_bucket_at(0); + let mut buckets = self.raw_bucket_at(0); + while buckets.idx < cap { + *new_buckets.hash() = *buckets.hash(); + if *new_buckets.hash() != EMPTY_BUCKET { + let pair_ptr = buckets.pair(); + let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); + ptr::write(new_buckets.pair(), kv); } - }; + buckets.idx += 1; + new_buckets.idx += 1; + } new_ht.size = self.size(); @@ -1186,7 +1164,7 @@ impl Clone for RawTable { unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { fn drop(&mut self) { - if self.capacity == 0 { + if self.capacity() == 0 { return; } @@ -1202,8 +1180,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { } } - let hashes_size = self.capacity * size_of::(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + let hashes_size = self.capacity() * size_of::(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); let (align, _, size, oflo) = calculate_allocation(hashes_size, align_of::(), pairs_size, From b970bc2a79719b5c1573fb87c96773ce131dbb8d Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Tue, 4 Apr 2017 22:51:16 +0100 Subject: [PATCH 520/662] Enable appveyor cache, add more paranoia --- appveyor.yml | 7 +++++-- src/ci/init_repo.sh | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 68b2a239aff1b..b0adda4bdb904 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,15 +141,18 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' + - if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc + - sh src/ci/init_repo.sh . /c/cache/rustsrc - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh on_failure: - - cat %CD%/sccache.log + - cat %CD%\sccache.log + - cat C:\Users\appveyor\AppData\Local\Temp\1\build-cache-logs\*.log cache: + - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 4e22907d9794c..c235681cddd0c 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -38,9 +38,20 @@ fi # Wipe the cache if it's not valid, or mark it as invalid while we update it if [ ! -f "$cache_valid_file" ]; then - rm -rf "$CACHE_DIR" && mkdir "$CACHE_DIR" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" else - rm "$cache_valid_file" + stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1 && echo $?) + if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then + # Something is badly wrong - the cache valid file is here, but something + # about the git repo is fishy. Nuke it all, just in case + echo "WARNING: $cache_valid_file exists but bad repo: l:$stat_lines, ec:$stat_ec" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" + else + rm "$cache_valid_file" + fi fi # Update the cache (a pristine copy of the rust source master) From e60ea55f660bfd0d34fc18efa60b2d9764840601 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Apr 2017 15:55:23 -0700 Subject: [PATCH 521/662] travis: Update sccache binaries I've tracked down what I believe is the last spurious sccache failure on #40240 to behavior in mio (carllerche/mio#583), and this commit updates the binaries to a version which has that fix incorporated. --- .travis.yml | 2 +- appveyor.yml | 4 ++-- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/cross/Dockerfile | 2 +- src/ci/docker/dist-aarch64-linux/Dockerfile | 2 +- src/ci/docker/dist-android/Dockerfile | 2 +- src/ci/docker/dist-arm-linux/Dockerfile | 2 +- src/ci/docker/dist-armhf-linux/Dockerfile | 2 +- src/ci/docker/dist-armv7-linux/Dockerfile | 2 +- src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 2 +- src/ci/docker/dist-i686-freebsd/Dockerfile | 2 +- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-mips-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64el-linux/Dockerfile | 2 +- src/ci/docker/dist-mipsel-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64le-linux/Dockerfile | 2 +- src/ci/docker/dist-s390x-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-freebsd/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-musl/Dockerfile | 2 +- src/ci/docker/dist-x86_64-netbsd/Dockerfile | 2 +- src/ci/docker/emscripten/Dockerfile | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 2 +- src/ci/docker/i686-gnu/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-debug/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-distcheck/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-incremental/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-nopt/Dockerfile | 2 +- src/ci/docker/x86_64-gnu/Dockerfile | 2 +- 36 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5b57a389ecbe..0ffba70d2ef44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,7 +63,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp diff --git a/appveyor.yml b/appveyor.yml index 68b2a239aff1b..83cfea0dd834e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-pc-windows-msvc - - mv 2017-03-24-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-pc-windows-msvc + - mv 2017-04-04-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 933562c79e582..d42b35d488c3d 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 8dc02ab522c21..7c1984410078f 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile index c468a689a0565..d9a5429d2b8e8 100644 --- a/src/ci/docker/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 44d6863bf0bbd..31f4b8b777be5 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 1e448dd43fd5f..7162aa0efc0cf 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile index cad96b4bde480..8fa1cbe492fac 100644 --- a/src/ci/docker/dist-armhf-linux/Dockerfile +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile index d5be52eba5c2e..9fcd827fc9962 100644 --- a/src/ci/docker/dist-armv7-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index ed37a9e842e22..bfffd9637fcee 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index d88ec7aab3464..d2727cbdb3508 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-i686-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile index beda2512741e9..3b81216c6431e 100644 --- a/src/ci/docker/dist-i686-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -25,7 +25,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 8a01934deda30..b322f56f0d048 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -82,7 +82,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index e3df1cc7192d8..33cca061103a3 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index e4b3bc378c89a..157de83abb783 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile index 06f42397a3ea5..739d5ff6ac4aa 100644 --- a/src/ci/docker/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile index 17f9913b5aec2..9339063bc19eb 100644 --- a/src/ci/docker/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index c1e5e863ae06c..92342caed2a95 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 7c143b414d464..182dfd93cc76f 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc64-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile index 19b0d625d3616..6b9f964d5a383 100644 --- a/src/ci/docker/dist-powerpc64le-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -63,7 +63,7 @@ COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-s390x-linux/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile index 0d218771cf1c6..7c94f713e1875 100644 --- a/src/ci/docker/dist-s390x-linux/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-s390x-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile index 14444d69d2a8c..a2939c8c48591 100644 --- a/src/ci/docker/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -25,7 +25,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index bd36c75f9f06a..cbe5f5936a506 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -82,7 +82,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=x86_64-unknown-linux-gnu diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 085aa35165990..a41c0cca3b5f0 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile index 053300b9c1688..a1dd9a3724a88 100644 --- a/src/ci/docker/dist-x86_64-netbsd/Dockerfile +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-netbsd-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 77cf54a19a7fd..ffdb1d18a94ef 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index c84cf56e4e858..34d0567a440f9 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index f4bb9083b8582..960a0fa7a385f 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 68184c65cf17f..9871df90e00d5 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 6320a806fc301..197b0ec9b9bb6 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 180f53ec33f31..60af302791a74 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 4500fc0f642de..4ec0b5c152575 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index ad1227fa581f9..6448f88950f0d 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index f124020180571..c00667fe1dd00 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index fa9707d1a7352..7284d231b844b 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index e5d89034dbe42..1dce84bc5fd73 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ From 56902fbe71b9b0a9b327972412fca085a8770e61 Mon Sep 17 00:00:00 2001 From: GitLab Date: Mon, 13 Mar 2017 14:44:54 -0300 Subject: [PATCH 522/662] Fixes other targets rustlibs installation When the user select more than one target to generate rustlibs for, rustbuild will only install the host one. This patch fixes it, more info in https://github.com/rust-lang/rust/issues/39235#issuecomment-285878858 --- src/bootstrap/install.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 249f241a151bb..25082e3a9d095 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -49,12 +49,17 @@ pub fn install(build: &Build, stage: u32, host: &str) { install_sh(&build, "docs", "rust-docs", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } + + for target in build.config.target.iter() { + install_sh(&build, "std", "rust-std", stage, target, &prefix, + &docdir, &libdir, &mandir, &empty_dir); + } + if build.config.rust_save_analysis { install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - install_sh(&build, "std", "rust-std", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); From 1f70247446914a8b58bd088f32bcca792d30d75f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 5 Apr 2017 07:45:44 +0100 Subject: [PATCH 523/662] Add tracking issue for offset_to --- src/doc/unstable-book/src/offset-to.md | 4 ++-- src/libcore/ptr.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md index 376f3ff5d2199..03d990eb4ae97 100644 --- a/src/doc/unstable-book/src/offset-to.md +++ b/src/doc/unstable-book/src/offset-to.md @@ -1,7 +1,7 @@ # `offset_to` -The tracking issue for this feature is: [#0] +The tracking issue for this feature is: [#41079] -[#0]: https://github.com/rust-lang/rust/issues/0 +[#41079]: https://github.com/rust-lang/rust/issues/41079 ------------------------ diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6bcce76af04e3..04480fc5d31da 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -527,7 +527,7 @@ impl *const T { /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); /// } /// ``` - #[unstable(feature = "offset_to", issue = "0")] + #[unstable(feature = "offset_to", issue = "41079")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); @@ -718,7 +718,7 @@ impl *mut T { /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); /// } /// ``` - #[unstable(feature = "offset_to", issue = "0")] + #[unstable(feature = "offset_to", issue = "41079")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); From 608e8fe16c3859b61f3a43ee233cbf0119ecd35f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 5 Apr 2017 00:41:08 -0700 Subject: [PATCH 524/662] dist-powerpc-linux: use a pure 32-bit CPU profile With `-mcpu=power4`, code might use instructions like `fcfid`, excluding older CPUs like the PowerPC G4, which apparently some users would like to use. The generic `-mcpu=powerpc` should stick to pure 32-bit PowerPC instructions. Fixes rust-lang/cargo#3852. --- src/ci/docker/README.md | 7 +------ src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config | 8 ++++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 52f74ba90de6e..6f3a7e091e1ed 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -152,18 +152,13 @@ For targets: `powerpc-unknown-linux-gnu` - Path and misc options > Patches origin = Bundled, then local - Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = powerpc -- Target options > Emit assembly for CPU = power4 -- (+) -- Target options > Tune for CPU = power6 -- (+) +- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc - C compiler > gcc version = 4.9.3 -- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) -- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) - C compiler > C++ = ENABLE -- to cross compile LLVM -(+) These CPU options match the configuration of the toolchains in RHEL6. - ## `powerpc64-linux-gnu.config` For targets: `powerpc64-unknown-linux-gnu` diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config index 26e2de863a0f9..984a0a0304e47 100644 --- a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -101,8 +101,8 @@ CT_ARCH_SUPPORTS_WITH_FLOAT=y CT_ARCH_DEFAULT_BE=y CT_ARCH_DEFAULT_32=y CT_ARCH_ABI="" -CT_ARCH_CPU="power4" -CT_ARCH_TUNE="power6" +CT_ARCH_CPU="powerpc" +CT_ARCH_TUNE="" CT_ARCH_BE=y # CT_ARCH_LE is not set CT_ARCH_32=y @@ -391,8 +391,8 @@ CT_CC_GCC_HAS_LIBSANITIZER=y CT_CC_GCC_VERSION="4.9.3" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" -CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" -CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_ENV_ARRAY="" CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set From 36bc448c00a9fb5397d84b94485dd0279eb2af45 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 5 Apr 2017 10:02:37 -0500 Subject: [PATCH 525/662] style: space between struct name and opening brace --- src/librustdoc/html/format.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9e45ccaff32ba..7c1139d7135c1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -183,7 +183,7 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause{ gens, indent, end_newline } = self; + let &WhereClause { gens, indent, end_newline } = self; if gens.where_predicates.is_empty() { return Ok(()); } @@ -882,7 +882,7 @@ fn fmt_impl(i: &clean::Impl, fmt_type(&i.for_, f, use_absolute, true)?; - fmt::Display::fmt(&WhereClause{ gens: &i.generics, indent: 0, end_newline: true }, f)?; + fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?; Ok(()) } From b5cedb7c4ea74234fbf6da6bdc2ab6efc447baad Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Wed, 5 Apr 2017 11:58:53 -0400 Subject: [PATCH 526/662] tidy clean and small text fix --- src/libcore/intrinsics.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7339fb56e5b49..0806548b5aa05 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -155,18 +155,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -175,9 +175,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -186,18 +186,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -206,9 +206,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -217,9 +217,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -228,9 +228,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -239,9 +239,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. From 201b1a9032df63b40c1024cc9defd4a4b66cd73a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 5 Apr 2017 18:59:16 +0300 Subject: [PATCH 527/662] Properly adjust filenames when multiple emissions Fixes #40993 --- src/librustc_driver/driver.rs | 7 +++---- src/test/run-make/multiple-emits/Makefile | 7 +++++++ src/test/run-make/multiple-emits/foo.rs | 11 +++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 src/test/run-make/multiple-emits/Makefile create mode 100644 src/test/run-make/multiple-emits/foo.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 977382b33adf7..96eb5dd602f51 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1358,10 +1358,9 @@ pub fn build_output_filenames(input: &Input, .values() .filter(|a| a.is_none()) .count(); - let ofile = if unnamed_output_types > 1 && - sess.opts.output_types.contains_key(&OutputType::Exe) { - sess.warn("ignoring specified output filename for 'link' output because multiple \ - outputs were requested"); + let ofile = if unnamed_output_types > 1 { + sess.warn("due to multiple output types requested, the explicitly specified \ + output file name will be adapted for each output type"); None } else { Some(out_file.clone()) diff --git a/src/test/run-make/multiple-emits/Makefile b/src/test/run-make/multiple-emits/Makefile new file mode 100644 index 0000000000000..e126422835cae --- /dev/null +++ b/src/test/run-make/multiple-emits/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out 2>&1 + rm $(TMPDIR)/out.ll $(TMPDIR)/out.s + $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out2.ext 2>&1 + rm $(TMPDIR)/out2.ll $(TMPDIR)/out2.s diff --git a/src/test/run-make/multiple-emits/foo.rs b/src/test/run-make/multiple-emits/foo.rs new file mode 100644 index 0000000000000..8ae3d072362ed --- /dev/null +++ b/src/test/run-make/multiple-emits/foo.rs @@ -0,0 +1,11 @@ +// 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. + +fn main() {} From 44bcd261a7fa2a4ad873a77b67ac88b0cf09f111 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Wed, 22 Mar 2017 03:27:06 +0900 Subject: [PATCH 528/662] Reduce a table used for `Debug` impl of `str`. This commit shrinks the size of the aforementioned table from 2,102 bytes to 1,197 bytes. This is achieved by an observation that most u16 entries are common in its upper byte. Specifically: - SINGLETONS now uses two tables, one for (upper byte, lower count) and another for a series of lower bytes. For each upper byte given number of lower bytes are read and compared. - NORMAL now uses a variable length format for the count of "true" codepoints and "false" codepoints (one byte with MSB unset, or two big-endian bytes with the first MSB set). The code size and relative performance roughly remains same as this commit tries to optimize for both. The new table and algorithm has been verified for the equivalence to older ones. --- src/etc/char_private.py | 132 +++- src/libcore/char_private.rs | 1238 +++++++++++++---------------------- 2 files changed, 565 insertions(+), 805 deletions(-) diff --git a/src/etc/char_private.py b/src/etc/char_private.py index 9d15f98e06709..75ab3f1a17be4 100644 --- a/src/etc/char_private.py +++ b/src/etc/char_private.py @@ -76,6 +76,66 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) +def compress_singletons(singletons): + uppers = [] # (upper, # items in lowers) + lowers = [] + + for i in singletons: + upper = i >> 8 + lower = i & 0xff + if len(uppers) == 0 or uppers[-1][0] != upper: + uppers.append((upper, 1)) + else: + upper, count = uppers[-1] + uppers[-1] = upper, count + 1 + lowers.append(lower) + + return uppers, lowers + +def compress_normal(normal): + # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f + # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + + prev_start = 0 + for start, count in normal: + truelen = start - prev_start + falselen = count + prev_start = start + count + + assert truelen < 0x8000 and falselen < 0x8000 + entry = [] + if truelen > 0x7f: + entry.append(0x80 | (truelen >> 8)) + entry.append(truelen & 0xff) + else: + entry.append(truelen & 0x7f) + if falselen > 0x7f: + entry.append(0x80 | (falselen >> 8)) + entry.append(falselen & 0xff) + else: + entry.append(falselen & 0x7f) + + compressed.append(entry) + + return compressed + +def print_singletons(uppers, lowers, uppersname, lowersname): + print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) + for u, c in uppers: + print(" ({:#04x}, {}),".format(u, c)) + print("];") + print("const {}: &'static [u8] = &[".format(lowersname)) + for i in range(0, len(lowers), 8): + print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print("];") + +def print_normal(normal, normalname): + print("const {}: &'static [u8] = &[".format(normalname)) + for v in normal: + print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) + print("];") + def main(): file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") @@ -111,6 +171,11 @@ def main(): else: normal0.append((a, b - a)) + singletons0u, singletons0l = compress_singletons(singletons0) + singletons1u, singletons1l = compress_singletons(singletons1) + normal0 = compress_normal(normal0) + normal1 = compress_normal(normal1) + print("""\ // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -125,38 +190,49 @@ def main(): // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { break; } + lowerstart = lowerend; } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; - } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 } else { + v as i32 + }; + x -= len; + if x < 0 { break; } + current = !current; } - true + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else {\ """) for a, b in extra: @@ -169,22 +245,10 @@ def main(): }\ """) print() - print("const SINGLETONS0: &'static [u16] = &[") - for s in singletons0: - print(" 0x{:x},".format(s)) - print("];") - print("const SINGLETONS1: &'static [u16] = &[") - for s in singletons1: - print(" 0x{:x},".format(s)) - print("];") - print("const NORMAL0: &'static [u16] = &[") - for a, b in normal0: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") - print("const NORMAL1: &'static [u16] = &[") - for a, b in normal1: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") + print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') + print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') + print_normal(normal0, 'NORMAL0') + print_normal(normal1, 'NORMAL1') if __name__ == '__main__': main() diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs index ddc473592a260..2c0f449b27601 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -11,38 +11,49 @@ // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { break; } + lowerstart = lowerend; } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; - } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 } else { + v as i32 + }; + x -= len; + if x < 0 { break; } + current = !current; } - true + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else { if 0x2a6d7 <= x && x < 0x2a700 { return false; @@ -66,761 +77,446 @@ pub fn is_printable(x: char) -> bool { } } -const SINGLETONS0: &'static [u16] = &[ - 0xad, - 0x378, - 0x379, - 0x38b, - 0x38d, - 0x3a2, - 0x530, - 0x557, - 0x558, - 0x560, - 0x588, - 0x58b, - 0x58c, - 0x590, - 0x61c, - 0x61d, - 0x6dd, - 0x70e, - 0x70f, - 0x74b, - 0x74c, - 0x82e, - 0x82f, - 0x83f, - 0x85c, - 0x85d, - 0x8b5, - 0x8e2, - 0x984, - 0x98d, - 0x98e, - 0x991, - 0x992, - 0x9a9, - 0x9b1, - 0x9ba, - 0x9bb, - 0x9c5, - 0x9c6, - 0x9c9, - 0x9ca, - 0x9de, - 0x9e4, - 0x9e5, - 0xa04, - 0xa11, - 0xa12, - 0xa29, - 0xa31, - 0xa34, - 0xa37, - 0xa3a, - 0xa3b, - 0xa3d, - 0xa49, - 0xa4a, - 0xa5d, - 0xa84, - 0xa8e, - 0xa92, - 0xaa9, - 0xab1, - 0xab4, - 0xaba, - 0xabb, - 0xac6, - 0xaca, - 0xace, - 0xacf, - 0xae4, - 0xae5, - 0xb04, - 0xb0d, - 0xb0e, - 0xb11, - 0xb12, - 0xb29, - 0xb31, - 0xb34, - 0xb3a, - 0xb3b, - 0xb45, - 0xb46, - 0xb49, - 0xb4a, - 0xb5e, - 0xb64, - 0xb65, - 0xb84, - 0xb91, - 0xb9b, - 0xb9d, - 0xbc9, - 0xbce, - 0xbcf, - 0xc04, - 0xc0d, - 0xc11, - 0xc29, - 0xc45, - 0xc49, - 0xc57, - 0xc64, - 0xc65, - 0xc84, - 0xc8d, - 0xc91, - 0xca9, - 0xcb4, - 0xcba, - 0xcbb, - 0xcc5, - 0xcc9, - 0xcdf, - 0xce4, - 0xce5, - 0xcf0, - 0xd04, - 0xd0d, - 0xd11, - 0xd3b, - 0xd3c, - 0xd45, - 0xd49, - 0xd64, - 0xd65, - 0xd80, - 0xd81, - 0xd84, - 0xdb2, - 0xdbc, - 0xdbe, - 0xdbf, - 0xdd5, - 0xdd7, - 0xdf0, - 0xdf1, - 0xe83, - 0xe85, - 0xe86, - 0xe89, - 0xe8b, - 0xe8c, - 0xe98, - 0xea0, - 0xea4, - 0xea6, - 0xea8, - 0xea9, - 0xeac, - 0xeba, - 0xebe, - 0xebf, - 0xec5, - 0xec7, - 0xece, - 0xecf, - 0xeda, - 0xedb, - 0xf48, - 0xf98, - 0xfbd, - 0xfcd, - 0x10c6, - 0x10ce, - 0x10cf, - 0x1249, - 0x124e, - 0x124f, - 0x1257, - 0x1259, - 0x125e, - 0x125f, - 0x1289, - 0x128e, - 0x128f, - 0x12b1, - 0x12b6, - 0x12b7, - 0x12bf, - 0x12c1, - 0x12c6, - 0x12c7, - 0x12d7, - 0x1311, - 0x1316, - 0x1317, - 0x135b, - 0x135c, - 0x13f6, - 0x13f7, - 0x13fe, - 0x13ff, - 0x1680, - 0x170d, - 0x176d, - 0x1771, - 0x17de, - 0x17df, - 0x180e, - 0x180f, - 0x191f, - 0x196e, - 0x196f, - 0x1a1c, - 0x1a1d, - 0x1a5f, - 0x1a7d, - 0x1a7e, - 0x1aae, - 0x1aaf, - 0x1cf7, - 0x1f16, - 0x1f17, - 0x1f1e, - 0x1f1f, - 0x1f46, - 0x1f47, - 0x1f4e, - 0x1f4f, - 0x1f58, - 0x1f5a, - 0x1f5c, - 0x1f5e, - 0x1f7e, - 0x1f7f, - 0x1fb5, - 0x1fc5, - 0x1fd4, - 0x1fd5, - 0x1fdc, - 0x1ff0, - 0x1ff1, - 0x1ff5, - 0x2072, - 0x2073, - 0x208f, - 0x23ff, - 0x2b74, - 0x2b75, - 0x2b96, - 0x2b97, - 0x2bc9, - 0x2c2f, - 0x2c5f, - 0x2d26, - 0x2d2e, - 0x2d2f, - 0x2da7, - 0x2daf, - 0x2db7, - 0x2dbf, - 0x2dc7, - 0x2dcf, - 0x2dd7, - 0x2ddf, - 0x2e9a, - 0x3040, - 0x3097, - 0x3098, - 0x318f, - 0x321f, - 0x32ff, - 0xa7af, - 0xa8fe, - 0xa8ff, - 0xa9ce, - 0xa9ff, - 0xaa4e, - 0xaa4f, - 0xaa5a, - 0xaa5b, - 0xab07, - 0xab08, - 0xab0f, - 0xab10, - 0xab27, - 0xab2f, - 0xabee, - 0xabef, - 0xfa6e, - 0xfa6f, - 0xfb37, - 0xfb3d, - 0xfb3f, - 0xfb42, - 0xfb45, - 0xfd90, - 0xfd91, - 0xfdfe, - 0xfdff, - 0xfe53, - 0xfe67, - 0xfe75, - 0xffc8, - 0xffc9, - 0xffd0, - 0xffd1, - 0xffd8, - 0xffd9, - 0xffe7, - 0xfffe, - 0xffff, +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 7), + (0x09, 16), + (0x0a, 27), + (0x0b, 24), + (0x0c, 22), + (0x0d, 20), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1c, 1), + (0x1f, 22), + (0x20, 3), + (0x23, 1), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 1), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), ]; -const SINGLETONS1: &'static [u16] = &[ - 0xc, - 0x27, - 0x3b, - 0x3e, - 0x4e, - 0x4f, - 0x18f, - 0x39e, - 0x49e, - 0x49f, - 0x806, - 0x807, - 0x809, - 0x836, - 0x83d, - 0x83e, - 0x856, - 0x8f3, - 0x9d0, - 0x9d1, - 0xa04, - 0xa14, - 0xa18, - 0xb56, - 0xb57, - 0x10bd, - 0x1135, - 0x11ce, - 0x11cf, - 0x11e0, - 0x1212, - 0x1287, - 0x1289, - 0x128e, - 0x129e, - 0x1304, - 0x130d, - 0x130e, - 0x1311, - 0x1312, - 0x1329, - 0x1331, - 0x1334, - 0x133a, - 0x133b, - 0x1345, - 0x1346, - 0x1349, - 0x134a, - 0x134e, - 0x134f, - 0x1364, - 0x1365, - 0x145a, - 0x145c, - 0x15b6, - 0x15b7, - 0x1c09, - 0x1c37, - 0x1c90, - 0x1c91, - 0x1ca8, - 0x246f, - 0x6a5f, - 0x6aee, - 0x6aef, - 0x6b5a, - 0x6b62, - 0xbc9a, - 0xbc9b, - 0xd127, - 0xd128, - 0xd455, - 0xd49d, - 0xd4a0, - 0xd4a1, - 0xd4a3, - 0xd4a4, - 0xd4a7, - 0xd4a8, - 0xd4ad, - 0xd4ba, - 0xd4bc, - 0xd4c4, - 0xd506, - 0xd50b, - 0xd50c, - 0xd515, - 0xd51d, - 0xd53a, - 0xd53f, - 0xd545, - 0xd551, - 0xd6a6, - 0xd6a7, - 0xd7cc, - 0xd7cd, - 0xdaa0, - 0xe007, - 0xe019, - 0xe01a, - 0xe022, - 0xe025, - 0xe8c5, - 0xe8c6, - 0xee04, - 0xee20, - 0xee23, - 0xee25, - 0xee26, - 0xee28, - 0xee33, - 0xee38, - 0xee3a, - 0xee48, - 0xee4a, - 0xee4c, - 0xee50, - 0xee53, - 0xee55, - 0xee56, - 0xee58, - 0xee5a, - 0xee5c, - 0xee5e, - 0xee60, - 0xee63, - 0xee65, - 0xee66, - 0xee6b, - 0xee73, - 0xee78, - 0xee7d, - 0xee7f, - 0xee8a, - 0xeea4, - 0xeeaa, - 0xf0af, - 0xf0b0, - 0xf0c0, - 0xf0d0, - 0xf12f, - 0xf91f, - 0xf931, - 0xf932, - 0xf93f, +const SINGLETONS0L: &'static [u8] = &[ + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, + 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, + 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, + 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9, + 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, 0x29, + 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, + 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, + 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, 0x04, + 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, + 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x04, + 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, + 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, + 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, + 0x3b, 0x3c, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, + 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, + 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, + 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, + 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, + 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, + 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, + 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, + 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, + 0x7e, 0xae, 0xaf, 0xf7, 0x16, 0x17, 0x1e, 0x1f, + 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, + 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0xff, 0x74, 0x75, + 0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, + 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, + 0x9a, 0x40, 0x97, 0x98, 0x8f, 0x1f, 0xff, 0xaf, + 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, + 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, + 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, + 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, + 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; -const NORMAL0: &'static [u16] = &[ - 0x0, 0x20, - 0x7f, 0x22, - 0x380, 0x4, - 0x5c8, 0x8, - 0x5eb, 0x5, - 0x5f5, 0x11, - 0x7b2, 0xe, - 0x7fb, 0x5, - 0x85f, 0x41, - 0x8be, 0x16, - 0x9b3, 0x3, - 0x9cf, 0x8, - 0x9d8, 0x4, - 0x9fc, 0x5, - 0xa0b, 0x4, - 0xa43, 0x4, - 0xa4e, 0x3, - 0xa52, 0x7, - 0xa5f, 0x7, - 0xa76, 0xb, - 0xad1, 0xf, - 0xaf2, 0x7, - 0xafa, 0x7, - 0xb4e, 0x8, - 0xb58, 0x4, - 0xb78, 0xa, - 0xb8b, 0x3, - 0xb96, 0x3, - 0xba0, 0x3, - 0xba5, 0x3, - 0xbab, 0x3, - 0xbba, 0x4, - 0xbc3, 0x3, - 0xbd1, 0x6, - 0xbd8, 0xe, - 0xbfb, 0x5, - 0xc3a, 0x3, - 0xc4e, 0x7, - 0xc5b, 0x5, - 0xc70, 0x8, - 0xcce, 0x7, - 0xcd7, 0x7, - 0xcf3, 0xe, - 0xd50, 0x4, - 0xd97, 0x3, - 0xdc7, 0x3, - 0xdcb, 0x4, - 0xde0, 0x6, - 0xdf5, 0xc, - 0xe3b, 0x4, - 0xe5c, 0x25, - 0xe8e, 0x6, - 0xee0, 0x20, - 0xf6d, 0x4, - 0xfdb, 0x25, - 0x10c8, 0x5, - 0x137d, 0x3, - 0x139a, 0x6, - 0x169d, 0x3, - 0x16f9, 0x7, - 0x1715, 0xb, - 0x1737, 0x9, - 0x1754, 0xc, - 0x1774, 0xc, - 0x17ea, 0x6, - 0x17fa, 0x6, - 0x181a, 0x6, - 0x1878, 0x8, - 0x18ab, 0x5, - 0x18f6, 0xa, - 0x192c, 0x4, - 0x193c, 0x4, - 0x1941, 0x3, - 0x1975, 0xb, - 0x19ac, 0x4, - 0x19ca, 0x6, - 0x19db, 0x3, - 0x1a8a, 0x6, - 0x1a9a, 0x6, - 0x1abf, 0x41, - 0x1b4c, 0x4, - 0x1b7d, 0x3, - 0x1bf4, 0x8, - 0x1c38, 0x3, - 0x1c4a, 0x3, - 0x1c89, 0x37, - 0x1cc8, 0x8, - 0x1cfa, 0x6, - 0x1df6, 0x5, - 0x1fff, 0x11, - 0x2028, 0x8, - 0x205f, 0x11, - 0x209d, 0x3, - 0x20bf, 0x11, - 0x20f1, 0xf, - 0x218c, 0x4, - 0x2427, 0x19, - 0x244b, 0x15, - 0x2bba, 0x3, - 0x2bd2, 0x1a, - 0x2bf0, 0x10, - 0x2cf4, 0x5, - 0x2d28, 0x5, - 0x2d68, 0x7, - 0x2d71, 0xe, - 0x2d97, 0x9, - 0x2e45, 0x3b, - 0x2ef4, 0xc, - 0x2fd6, 0x1a, - 0x2ffc, 0x5, - 0x3100, 0x5, - 0x312e, 0x3, - 0x31bb, 0x5, - 0x31e4, 0xc, - 0x4db6, 0xa, - 0x9fd6, 0x2a, - 0xa48d, 0x3, - 0xa4c7, 0x9, - 0xa62c, 0x14, - 0xa6f8, 0x8, - 0xa7b8, 0x3f, - 0xa82c, 0x4, - 0xa83a, 0x6, - 0xa878, 0x8, - 0xa8c6, 0x8, - 0xa8da, 0x6, - 0xa954, 0xb, - 0xa97d, 0x3, - 0xa9da, 0x4, - 0xaa37, 0x9, - 0xaac3, 0x18, - 0xaaf7, 0xa, - 0xab17, 0x9, - 0xab66, 0xa, - 0xabfa, 0x6, - 0xd7a4, 0xc, - 0xd7c7, 0x4, - 0xd7fc, 0x2104, - 0xfada, 0x26, - 0xfb07, 0xc, - 0xfb18, 0x5, - 0xfbc2, 0x11, - 0xfd40, 0x10, - 0xfdc8, 0x28, - 0xfe1a, 0x6, - 0xfe6c, 0x4, - 0xfefd, 0x4, - 0xffbf, 0x3, - 0xffdd, 0x3, - 0xffef, 0xd, +const SINGLETONS1U: &'static [(u8, u8)] = &[ + (0x00, 6), + (0x01, 1), + (0x03, 1), + (0x04, 2), + (0x08, 8), + (0x09, 2), + (0x0a, 3), + (0x0b, 2), + (0x10, 1), + (0x11, 4), + (0x12, 5), + (0x13, 18), + (0x14, 2), + (0x15, 2), + (0x1c, 5), + (0x24, 1), + (0x6a, 3), + (0x6b, 2), + (0xbc, 2), + (0xd1, 2), + (0xd4, 12), + (0xd5, 9), + (0xd6, 2), + (0xd7, 2), + (0xda, 1), + (0xe0, 5), + (0xe8, 2), + (0xee, 32), + (0xf0, 4), + (0xf1, 1), + (0xf9, 4), ]; -const NORMAL1: &'static [u16] = &[ +const SINGLETONS1L: &'static [u8] = &[ + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, + 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, + 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, + 0xb7, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x6f, 0x5f, + 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, + 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, + 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, + 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, + 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, + 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, + 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, + 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, + 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, + 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x1f, 0x31, + 0x32, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x5f, 0x41, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x20, 0x05, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x01, 0x07, + 0x4d, 0x08, + 0x02, 0x04, + 0x1c, 0x0a, + 0x09, 0x03, + 0x08, 0x03, + 0x07, 0x03, + 0x02, 0x03, + 0x03, 0x03, + 0x0c, 0x04, + 0x05, 0x03, + 0x0b, 0x06, + 0x01, 0x0e, + 0x15, 0x05, + 0x3a, 0x03, + 0x11, 0x07, + 0x06, 0x05, + 0x10, 0x08, + 0x56, 0x07, + 0x02, 0x07, + 0x15, 0x0e, + 0x4f, 0x04, + 0x43, 0x03, + 0x2d, 0x03, + 0x01, 0x04, + 0x11, 0x06, + 0x0f, 0x0c, + 0x3a, 0x04, + 0x1d, 0x25, + 0x0d, 0x06, + 0x4c, 0x20, + 0x6d, 0x04, + 0x6a, 0x25, + 0x80, 0xc8, 0x05, + 0x82, 0xb0, 0x03, + 0x1a, 0x06, + 0x82, 0xfd, 0x03, + 0x59, 0x07, + 0x15, 0x0b, + 0x17, 0x09, + 0x14, 0x0c, + 0x14, 0x0c, + 0x6a, 0x06, + 0x0a, 0x06, + 0x1a, 0x06, + 0x58, 0x08, + 0x2b, 0x05, + 0x46, 0x0a, + 0x2c, 0x04, + 0x0c, 0x04, + 0x01, 0x03, + 0x31, 0x0b, + 0x2c, 0x04, + 0x1a, 0x06, + 0x0b, 0x03, + 0x80, 0xac, 0x06, + 0x0a, 0x06, + 0x1f, 0x41, + 0x4c, 0x04, + 0x2d, 0x03, + 0x74, 0x08, + 0x3c, 0x03, + 0x0f, 0x03, + 0x3c, 0x37, + 0x08, 0x08, + 0x2a, 0x06, + 0x80, 0xf6, 0x05, + 0x82, 0x04, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x1f, 0x11, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x15, 0x1a, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xa5, 0x3b, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x29, 0x03, + 0x80, 0x8a, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x16, 0x2a, + 0x84, 0x8d, 0x03, + 0x37, 0x09, + 0x81, 0x5c, 0x14, + 0x80, 0xb8, 0x08, + 0x80, 0xb8, 0x3f, + 0x35, 0x04, + 0x0a, 0x06, + 0x38, 0x08, + 0x46, 0x08, + 0x0c, 0x06, + 0x74, 0x0b, + 0x1e, 0x03, + 0x5a, 0x04, + 0x59, 0x09, + 0x80, 0x83, 0x18, + 0x1c, 0x0a, + 0x16, 0x09, + 0x46, 0x0a, + 0x80, 0x8a, 0x06, + 0xab, 0xa4, 0x0c, + 0x17, 0x04, + 0x31, 0xa1, 0x04, + 0x81, 0xda, 0x26, + 0x07, 0x0c, + 0x05, 0x05, + 0x80, 0xa5, 0x11, + 0x81, 0x6d, 0x10, + 0x78, 0x28, + 0x2a, 0x06, + 0x4c, 0x04, + 0x80, 0x8d, 0x04, + 0x80, 0xbe, 0x03, + 0x1b, 0x03, + 0x0f, 0x0d, +]; +const NORMAL1: &'static [u8] = &[ + 0x5e, 0x22, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x0c, + 0x1b, 0x05, + 0x2b, 0x05, + 0x44, 0x04, + 0x0e, 0x2a, + 0x80, 0xaa, 0x06, + 0x24, 0x04, + 0x24, 0x04, + 0x28, 0x08, + 0x34, 0x0b, + 0x01, 0x80, 0x90, + 0x81, 0x37, 0x09, + 0x16, 0x0a, + 0x08, 0x80, 0x98, + 0x39, 0x03, + 0x63, 0x08, + 0x09, 0x30, + 0x16, 0x05, + 0x21, 0x03, + 0x1b, 0x05, + 0x01, 0x40, + 0x38, 0x04, + 0x4b, 0x05, + 0x28, 0x04, + 0x03, 0x04, + 0x09, 0x08, + 0x09, 0x07, + 0x40, 0x20, + 0x27, 0x04, + 0x0c, 0x09, + 0x36, 0x03, + 0x3a, 0x05, + 0x1a, 0x07, + 0x04, 0x0c, + 0x07, 0x50, + 0x49, 0x37, + 0x33, 0x0d, + 0x33, 0x07, + 0x06, 0x81, 0x60, + 0x1f, 0x81, 0x81, + 0x4e, 0x04, + 0x1e, 0x0f, + 0x43, 0x0e, + 0x19, 0x07, + 0x0a, 0x06, + 0x44, 0x0c, + 0x27, 0x09, + 0x75, 0x0b, + 0x3f, 0x41, + 0x2a, 0x06, + 0x3b, 0x05, + 0x0a, 0x06, + 0x51, 0x06, + 0x01, 0x05, + 0x10, 0x03, + 0x05, 0x80, 0x8b, + 0x5e, 0x22, + 0x48, 0x08, + 0x0a, 0x80, 0xa6, 0x5e, 0x22, - 0xfb, 0x5, - 0x103, 0x4, - 0x134, 0x3, - 0x19c, 0x4, - 0x1a1, 0x2f, - 0x1fe, 0x82, - 0x29d, 0x3, - 0x2d1, 0xf, - 0x2fc, 0x4, - 0x324, 0xc, - 0x34b, 0x5, - 0x37b, 0x5, - 0x3c4, 0x4, - 0x3d6, 0x2a, - 0x4aa, 0x6, - 0x4d4, 0x4, - 0x4fc, 0x4, - 0x528, 0x8, - 0x564, 0xb, - 0x570, 0x90, - 0x737, 0x9, - 0x756, 0xa, - 0x768, 0x98, - 0x839, 0x3, - 0x89f, 0x8, - 0x8b0, 0x30, - 0x8f6, 0x5, - 0x91c, 0x3, - 0x93a, 0x5, - 0x940, 0x40, - 0x9b8, 0x4, - 0xa07, 0x5, - 0xa34, 0x4, - 0xa3b, 0x4, - 0xa48, 0x8, - 0xa59, 0x7, - 0xaa0, 0x20, - 0xae7, 0x4, - 0xaf7, 0x9, - 0xb36, 0x3, - 0xb73, 0x5, - 0xb92, 0x7, - 0xb9d, 0xc, - 0xbb0, 0x50, - 0xc49, 0x37, - 0xcb3, 0xd, - 0xcf3, 0x7, - 0xd00, 0x160, - 0xe7f, 0x181, - 0x104e, 0x4, - 0x1070, 0xf, - 0x10c2, 0xe, - 0x10e9, 0x7, - 0x10fa, 0x6, - 0x1144, 0xc, - 0x1177, 0x9, - 0x11f5, 0xb, - 0x123f, 0x41, - 0x12aa, 0x6, - 0x12eb, 0x5, - 0x12fa, 0x6, - 0x1351, 0x6, - 0x1358, 0x5, - 0x136d, 0x3, - 0x1375, 0x8b, - 0x145e, 0x22, - 0x14c8, 0x8, - 0x14da, 0xa6, - 0x15de, 0x22, - 0x1645, 0xb, - 0x165a, 0x6, - 0x166d, 0x13, - 0x16b8, 0x8, - 0x16ca, 0x36, - 0x171a, 0x3, - 0x172c, 0x4, - 0x1740, 0x160, - 0x18f3, 0xc, - 0x1900, 0x1c0, - 0x1af9, 0x107, - 0x1c46, 0xa, - 0x1c6d, 0x3, - 0x1cb7, 0x349, - 0x239a, 0x66, - 0x2475, 0xb, - 0x2544, 0xabc, - 0x342f, 0xfd1, - 0x4647, 0x21b9, - 0x6a39, 0x7, - 0x6a6a, 0x4, - 0x6a70, 0x60, - 0x6af6, 0xa, - 0x6b46, 0xa, - 0x6b78, 0x5, - 0x6b90, 0x370, - 0x6f45, 0xb, - 0x6f7f, 0x10, - 0x6fa0, 0x40, - 0x6fe1, 0x1f, - 0x87ed, 0x13, - 0x8af3, 0x250d, - 0xb002, 0xbfe, - 0xbc6b, 0x5, - 0xbc7d, 0x3, - 0xbc89, 0x7, - 0xbca0, 0x1360, - 0xd0f6, 0xa, - 0xd173, 0x8, - 0xd1e9, 0x17, - 0xd246, 0xba, - 0xd357, 0x9, - 0xd372, 0x8e, - 0xd547, 0x3, - 0xda8c, 0xf, - 0xdab0, 0x550, - 0xe02b, 0x7d5, - 0xe8d7, 0x29, - 0xe94b, 0x5, - 0xe95a, 0x4, - 0xe960, 0x4a0, - 0xee3c, 0x6, - 0xee43, 0x4, - 0xee9c, 0x5, - 0xeebc, 0x34, - 0xeef2, 0x10e, - 0xf02c, 0x4, - 0xf094, 0xc, - 0xf0f6, 0xa, - 0xf10d, 0x3, - 0xf16c, 0x4, - 0xf1ad, 0x39, - 0xf203, 0xd, - 0xf23c, 0x4, - 0xf249, 0x7, - 0xf252, 0xae, - 0xf6d3, 0xd, - 0xf6ed, 0x3, - 0xf6f7, 0x9, - 0xf774, 0xc, - 0xf7d5, 0x2b, - 0xf80c, 0x4, - 0xf848, 0x8, - 0xf85a, 0x6, - 0xf888, 0x8, - 0xf8ae, 0x62, - 0xf928, 0x8, - 0xf94c, 0x4, - 0xf95f, 0x21, - 0xf992, 0x2e, - 0xf9c1, 0x63f, + 0x45, 0x0b, + 0x0a, 0x06, + 0x0d, 0x13, + 0x38, 0x08, + 0x0a, 0x36, + 0x1a, 0x03, + 0x0f, 0x04, + 0x10, 0x81, 0x60, + 0x53, 0x0c, + 0x01, 0x81, 0xc0, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x83, 0x49, + 0x83, 0x9a, 0x66, + 0x75, 0x0b, + 0x80, 0xc4, 0x8a, 0xbc, + 0x84, 0x2f, 0x8f, 0xd1, + 0x82, 0x47, 0xa1, 0xb9, + 0x82, 0x39, 0x07, + 0x2a, 0x04, + 0x02, 0x60, + 0x26, 0x0a, + 0x46, 0x0a, + 0x28, 0x05, + 0x13, 0x83, 0x70, + 0x45, 0x0b, + 0x2f, 0x10, + 0x11, 0x40, + 0x01, 0x1f, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x02, 0x8b, 0xfe, + 0x6b, 0x05, + 0x0d, 0x03, + 0x09, 0x07, + 0x10, 0x93, 0x60, + 0x80, 0xf6, 0x0a, + 0x73, 0x08, + 0x6e, 0x17, + 0x46, 0x80, 0xba, + 0x57, 0x09, + 0x12, 0x80, 0x8e, + 0x81, 0x47, 0x03, + 0x85, 0x42, 0x0f, + 0x15, 0x85, 0x50, + 0x2b, 0x87, 0xd5, + 0x80, 0xd7, 0x29, + 0x4b, 0x05, + 0x0a, 0x04, + 0x02, 0x84, 0xa0, + 0x3c, 0x06, + 0x01, 0x04, + 0x55, 0x05, + 0x1b, 0x34, + 0x02, 0x81, 0x0e, + 0x2c, 0x04, + 0x64, 0x0c, + 0x56, 0x0a, + 0x0d, 0x03, + 0x5c, 0x04, + 0x3d, 0x39, + 0x1d, 0x0d, + 0x2c, 0x04, + 0x09, 0x07, + 0x02, 0x80, 0xae, + 0x83, 0xd3, 0x0d, + 0x0d, 0x03, + 0x07, 0x09, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x62, + 0x18, 0x08, + 0x1c, 0x04, + 0x0f, 0x21, + 0x12, 0x2e, + 0x01, 0x86, 0x3f, ]; From 44e414c4770ff0800c375ddbb8e0f46ee00bcab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Apr 2017 09:50:04 -0700 Subject: [PATCH 529/662] Use proper span for tuple index parsed as float Fix diagnostic suggestion from: ```rust help: try parenthesizing the first index | (1, (2, 3)).((1, (2, 3)).1).1; ``` to the correct: ```rust help: try parenthesizing the first index | ((1, (2, 3)).1).1; ``` --- src/libsyntax/parse/parser.rs | 6 +++--- .../suggestions}/tuple-float-index.rs | 4 +--- src/test/ui/suggestions/tuple-float-index.stderr | 11 +++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) rename src/test/{parse-fail => ui/suggestions}/tuple-float-index.rs (75%) create mode 100644 src/test/ui/suggestions/tuple-float-index.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855af..0d2c9b92ed759 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2498,10 +2498,10 @@ impl<'a> Parser<'a> { } token::Literal(token::Float(n), _suf) => { self.bump(); - let prev_span = self.prev_span; let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(prev_span, + let mut err = self.diagnostic().struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); + err.span_label(self.prev_span, &"unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { Some(f) => f, @@ -2519,7 +2519,7 @@ impl<'a> Parser<'a> { word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) }); err.span_suggestion( - prev_span, + lo.to(self.prev_span), "try parenthesizing the first index", sugg); } diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/ui/suggestions/tuple-float-index.rs similarity index 75% rename from src/test/parse-fail/tuple-float-index.rs rename to src/test/ui/suggestions/tuple-float-index.rs index 57ad89ad37404..8bfbd0e74db22 100644 --- a/src/test/parse-fail/tuple-float-index.rs +++ b/src/test/ui/suggestions/tuple-float-index.rs @@ -11,7 +11,5 @@ // compile-flags: -Z parse-only fn main () { - (1, (2, 3)).1.1; //~ ERROR unexpected token - //~^ HELP try parenthesizing the first index - //~| SUGGESTION ((1, (2, 3)).1).1 + (1, (2, 3)).1.1; } diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr new file mode 100644 index 0000000000000..abe04dc1aa210 --- /dev/null +++ b/src/test/ui/suggestions/tuple-float-index.stderr @@ -0,0 +1,11 @@ +error: unexpected token: `1.1` + --> $DIR/tuple-float-index.rs:14:17 + | +14 | (1, (2, 3)).1.1; + | ^^^ unexpected token + | +help: try parenthesizing the first index + | ((1, (2, 3)).1).1; + +error: aborting due to previous error + From 631f761f18d6e4e8d1d4eccaa622ee7defbb8ca4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Apr 2017 10:39:02 -0700 Subject: [PATCH 530/662] travis: Update musl for i686/x86_64 This is a random stab towards #38618, no idea if it'll work. But hey more up-to-date software is better, right? --- src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh | 9 ++++++--- src/ci/docker/dist-x86_64-musl/build-musl.sh | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh index a50a25c791348..ad285a57a84a3 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh @@ -15,11 +15,14 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL -CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686 -make -j10 +CC=gcc \ + CFLAGS="$CFLAGS -m32" \ + ./configure --prefix=/musl-i686 --disable-shared \ + --target=i686 +make AR=ar RANLIB=ranlib -j10 make install cd .. diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh index 86bb259c8549a..776da0093974c 100644 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh @@ -15,7 +15,7 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL ./configure --prefix=/musl-x86_64 --disable-shared From 4c7e27734031d8b57cb51ad498d7f5111032468d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 20 Feb 2017 14:42:47 -0500 Subject: [PATCH 531/662] add an #[used] attribute similar to GCC's __attribute((used))__. This attribute prevents LLVM from optimizing away a non-exported symbol, within a compilation unit (object file), when there are no references to it. This is better explained with an example: ``` #[used] static LIVE: i32 = 0; static REFERENCED: i32 = 0; static DEAD: i32 = 0; fn internal() {} pub fn exported() -> &'static i32 { &REFERENCED } ``` Without optimizations, LLVM pretty much preserves all the static variables and functions within the compilation unit. ``` $ rustc --crate-type=lib --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 t drop::h1be0f8f27a2ba94a 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::DEAD::hc2ea8f9bd06f380b 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 0000000000000000 t symbols::internal::h0ac1aadbc1e3a494 ``` With optimizations, LLVM will drop dead code. Here `internal` is dropped because it's not a exported function/symbol (i.e. not `pub`lic). `DEAD` is dropped for the same reason. `REFERENCED` is preserved, even though it's not exported, because it's referenced by the `exported` function. Finally, `LIVE` survives because of the `#[used]` attribute even though it's not exported or referenced. ``` $ rustc --crate-type=lib -C opt-level=3 --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 ``` Note that the linker knows nothing about `#[used]` and will drop `LIVE` because no other object references to it. ``` $ echo 'fn main() {}' >> symbols.rs $ rustc symbols.rs && nm -C symbols | grep LIVE ``` At this time, `#[used]` only works on `static` variables. --- src/librustc_trans/base.rs | 20 +++++++++++++++++++- src/librustc_trans/consts.rs | 4 ++++ src/librustc_trans/context.rs | 7 +++++++ src/libsyntax/feature_gate.rs | 8 ++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ec45c5593632e..63258b7453317 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -50,7 +50,7 @@ use builder::Builder; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; -use common::{C_struct_in_context, C_u64, C_undef}; +use common::{C_struct_in_context, C_u64, C_undef, C_array}; use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; @@ -1187,6 +1187,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Create llvm.used variable + if !ccx.used_statics().borrow().is_empty() { + debug!("llvm.used"); + + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(ccx.llmod(), + val_ty(array).to_ref(), + name.as_ptr()); + llvm::LLVMSetInitializer(g, array); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::LLVMSetSection(g, section.as_ptr()); + } + } + // Finalize debuginfo if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0c3d211912add..9974155f7c07d 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -276,6 +276,10 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); + if attr::contains_name(attrs, "used") { + ccx.used_statics().borrow_mut().push(g); + } + Ok(g) } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 73602dc420b3f..2eca0a18e2b38 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell>, + used_statics: RefCell>, + lltypes: RefCell, Type>>, llsizingtypes: RefCell, Type>>, type_hashcodes: RefCell, String>>, @@ -587,6 +589,7 @@ impl<'tcx> LocalCrateContext<'tcx> { impl_method_cache: RefCell::new(FxHashMap()), closure_bare_wrapper_cache: RefCell::new(FxHashMap()), statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), lltypes: RefCell::new(FxHashMap()), llsizingtypes: RefCell::new(FxHashMap()), type_hashcodes: RefCell::new(FxHashMap()), @@ -754,6 +757,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().statics_to_rauw } + pub fn used_statics<'a>(&'a self) -> &'a RefCell> { + &self.local().used_statics + } + pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { &self.local().lltypes } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12d25ca4274fe..66a813025c437 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -337,11 +337,15 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Used to preserve symbols + (active, used, "1.18.0", None), ); declare_features! ( @@ -748,6 +752,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), + ("used", Whitelisted, Gated( + Stability::Unstable, "used", + "the `#[used]` attribute is an experimental feature", + cfg_fn!(used))), // used in resolve ("prelude_import", Whitelisted, Gated(Stability::Unstable, From 4e1147f3406bcd368c50c89242bbba6a6fec5127 Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 5 Apr 2017 20:41:43 +0200 Subject: [PATCH 532/662] Add example to std::process::abort This is a second (2/3?) step in order to complete this issue: https://github.com/rust-lang/rust/issues/29370 I submitted this PR with the help of @steveklabnik again. Thanks to him! More info here: https://github.com/rust-lang/rust/issues/29370#issuecomment-290653877 --- src/libstd/process.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7f1a00c707c20..95e625888ccee 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1070,6 +1070,28 @@ pub fn exit(code: i32) -> ! { /// // execution never gets here /// } /// ``` +/// +/// The abort function terminates the process, so the destructor will not get +/// run on the example below: +/// +/// ```no_run +/// use std::process; +/// +/// struct HasDrop; +/// +/// impl Drop for HasDrop { +/// fn drop(&mut self) { +/// println!("This will never be printed!"); +/// } +/// } +/// +/// fn main() { +/// let _x = HasDrop; +/// process::abort(); +/// // the destructor implemented for HasDrop will never get run +/// } +/// ``` +/// #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; From bc1bd8a609823814079996ca3ca0b05774e07a74 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 5 Mar 2017 23:03:42 -0500 Subject: [PATCH 533/662] add tracking issue and feature-gate and run-make tests --- src/test/compile-fail/feature-gate-used.rs | 15 +++++++++++++++ src/test/run-make/used/Makefile | 12 ++++++++++++ src/test/run-make/used/used.rs | 17 +++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-used.rs create mode 100644 src/test/run-make/used/Makefile create mode 100644 src/test/run-make/used/used.rs diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs new file mode 100644 index 0000000000000..68679d7dac896 --- /dev/null +++ b/src/test/compile-fail/feature-gate-used.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile new file mode 100644 index 0000000000000..70ac2e3802b81 --- /dev/null +++ b/src/test/run-make/used/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +# Do nothing on MSVC. +all: + exit 0 +else +all: + $(RUSTC) -C opt-level=3 --emit=obj used.rs + nm -C used.o | grep FOO + nm -C used.o | grep -v BAR +endif diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs new file mode 100644 index 0000000000000..186cd0fdf5e35 --- /dev/null +++ b/src/test/run-make/used/used.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +#![crate_type = "lib"] +#![feature(used)] + +#[used] +static FOO: u32 = 0; + +static BAR: u32 = 0; From c759eea7a60941f28e7e7a370ba95eeae06ea013 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 11:18:56 -0500 Subject: [PATCH 534/662] fix location of the emitted object file --- src/test/run-make/used/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 70ac2e3802b81..650464e4d8454 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -7,6 +7,6 @@ all: else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm -C used.o | grep FOO - nm -C used.o | grep -v BAR + nm -C $(TMPDIR)/used.o | grep FOO + nm -C $(TMPDIR)/used.o | grep -v BAR endif From 2598e4574e9136690add3cef55fbb8ac7356f3d2 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 5 Apr 2017 15:33:24 -0400 Subject: [PATCH 535/662] Add safe wrapper for atomic_singlethreadfence_* --- src/libcore/sync/atomic.rs | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index ae47e6fdfa928..948edda832b46 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1572,6 +1572,47 @@ pub fn fence(order: Ordering) { } +/// A compiler memory barrier. +/// +/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering +/// memory operations across this point. Which reorderings are disallowed is dictated by the given +/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory +/// synchronization; for that, a [`fence`] is needed. +/// +/// The re-ordering prevented by the different ordering semantics are: +/// +/// - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed. +/// - with [`Release`], preceding reads and writes cannot be moved past subsequent writes. +/// - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads. +/// - with [`AcqRel`], both of the above rules are enforced. +/// +/// # Panics +/// +/// Panics if `order` is [`Relaxed`]. +/// +/// [`fence`]: fn.fence.html +/// [`Ordering`]: enum.Ordering.html +/// [`Acquire`]: enum.Ordering.html#variant.Acquire +/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst +/// [`Release`]: enum.Ordering.html#variant.Release +/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel +/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed +#[inline] +#[unstable(feature = "std_compiler_fences", issue = "41091")] +pub fn compiler_barrier(order: Ordering) { + unsafe { + match order { + Acquire => intrinsics::atomic_singlethreadfence_acq(), + Release => intrinsics::atomic_singlethreadfence_rel(), + AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), + SeqCst => intrinsics::atomic_singlethreadfence(), + Relaxed => panic!("there is no such thing as a relaxed barrier"), + __Nonexhaustive => panic!("invalid memory ordering"), + } + } +} + + #[cfg(target_has_atomic = "8")] #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { From c1635d7e61533550d6c58d4f92a01d1e6acd28e6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Apr 2017 21:02:52 -0500 Subject: [PATCH 536/662] cast the #[used] static to *i8 to match the type signature of the llvm.used variable --- src/librustc_trans/base.rs | 2 -- src/librustc_trans/consts.rs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 63258b7453317..378e1d7fc63f0 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1189,8 +1189,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Create llvm.used variable if !ccx.used_statics().borrow().is_empty() { - debug!("llvm.used"); - let name = CString::new("llvm.used").unwrap(); let section = CString::new("llvm.metadata").unwrap(); let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 9974155f7c07d..ae8c2433fed75 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -277,7 +277,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); if attr::contains_name(attrs, "used") { - ccx.used_statics().borrow_mut().push(g); + let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref()); + ccx.used_statics().borrow_mut().push(cast); } Ok(g) From ecddad6920b7640ff0398a52a808703db3d4e62a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Apr 2017 21:06:53 -0500 Subject: [PATCH 537/662] don't test for the absence of BAR in the rmake test it's not related to this feature --- src/test/run-make/used/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 650464e4d8454..5fe09e95a828d 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -8,5 +8,4 @@ else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs nm -C $(TMPDIR)/used.o | grep FOO - nm -C $(TMPDIR)/used.o | grep -v BAR endif From bbe54115873eca9d9a889be3d9eff0c01d2ba8be Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Apr 2017 21:11:22 -0500 Subject: [PATCH 538/662] document the implementation a bit more --- src/librustc_trans/base.rs | 3 ++- src/librustc_trans/consts.rs | 1 + src/librustc_trans/context.rs | 2 ++ src/libsyntax/feature_gate.rs | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 378e1d7fc63f0..d204703b77598 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1187,7 +1187,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - // Create llvm.used variable + // Create the llvm.used variable + // This variable has type [N x i8*] and is stored in the llvm.metadata section if !ccx.used_statics().borrow().is_empty() { let name = CString::new("llvm.used").unwrap(); let section = CString::new("llvm.metadata").unwrap(); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index ae8c2433fed75..daf1a1ba95f9a 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -277,6 +277,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); if attr::contains_name(attrs, "used") { + // This static will be stored in the llvm.used variable which is an array of i8* let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref()); ccx.used_statics().borrow_mut().push(cast); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 2eca0a18e2b38..afb94f546abe8 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell>, + /// Statics that will be placed in the llvm.used variable + /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details used_statics: RefCell>, lltypes: RefCell, Type>>, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 66a813025c437..5f71900120386 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -344,8 +344,8 @@ declare_features! ( // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), - // Used to preserve symbols - (active, used, "1.18.0", None), + // Used to preserve symbols (see llvm.used) + (active, used, "1.18.0", Some(40289)), ); declare_features! ( From 763beff5d1bcfb74d2930decd731a43a7d3ad080 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 00:04:33 -0500 Subject: [PATCH 539/662] add documentation to the unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/used.md | 152 +++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/doc/unstable-book/src/used.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec816a..0459c6a251995 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -203,6 +203,7 @@ - [unwind_attributes](unwind-attributes.md) - [update_panic_count](update-panic-count.md) - [use_extern_macros](use-extern-macros.md) +- [used](used.md) - [utf8_error_error_len](utf8-error-error-len.md) - [vec_remove_item](vec-remove-item.md) - [windows_c](windows-c.md) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md new file mode 100644 index 0000000000000..749c9a8ec288c --- /dev/null +++ b/src/doc/unstable-book/src/used.md @@ -0,0 +1,152 @@ +# `used` + +The tracking issue for this feature is: 40289. + +------------------------ + +The `#[used]` attribute can be applied to `static` variables to prevent the Rust +compiler from optimizing them away even if they appear to be unused by the crate +(appear to be "dead code"). + +``` rust +#![feature(used)] + +#[used] +static FOO: i32 = 1; + +static BAR: i32 = 2; + +fn main() {} +``` + +If you compile this program into an object file, you'll see that `FOO` makes it +to the object file but `BAR` doesn't. Neither static variable is used by the +program. + +``` text +$ rustc -C opt-level=3 --emit=obj used.rs + +$ nm -C used.o +0000000000000000 T main + U std::rt::lang_start +0000000000000000 r used::FOO +0000000000000000 t used::main +``` + +Note that the *linker* knows nothing about the `#[used]` attribute and will +remove `#[used]` symbols if they are not referenced by other parts of the +program: + +``` text +$ rustc -C opt-level=3 used.rs + +$ nm -C used | grep FOO +``` + +"This doesn't sound too useful then!" you may think but keep reading. + +To preserve the symbols all the way to the final binary, you'll need the +cooperation of the linker. Here's one example: + +The ELF standard defines two special sections, `.init_array` and +`.pre_init_array`, that may contain function pointers which will be executed +*before* the `main` function is invoked. The linker will preserve symbols placed +in these sections (at least when linking programs that target the `*-*-linux-*` +targets). + +``` rust +#![feature(used)] + +extern "C" fn before_main() { + println!("Hello, world!"); +} + +#[link_section = ".init_array"] +#[used] +static INIT_ARRAY: [extern "C" fn(); 1] = [before_main]; + +fn main() {} +``` + +So, `#[used]` and `#[link_section]` can be combined to obtain "life before +main". + +``` text +$ rustc -C opt-level=3 before-main.rs + +$ ./before-main +Hello, world! +``` + +Another example: ARM Cortex-M microcontrollers need their reset handler, a +pointer to the function that will executed right after the microcontroller is +turned on, to be placed near the start of their FLASH memory to boot properly. + +This condition can be met using `#[used]` and `#[link_section]` plus a linker +script. + +``` rust +#![feature(lang_items)] +#![feature(used)] +#![no_main] +#![no_std] + +extern "C" fn reset_handler() -> ! { + loop {} +} + +#[link_section = ".reset_handler"] +#[used] +static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; + +#[lang = "panic_fmt"] +fn panic_fmt() {} +``` + +``` text +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} + +SECTIONS +{ + .text ORIGIN(FLASH) : + { + /* Vector table */ + LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */ + KEEP(*(.reset_handler)); + + /* Omitted: The rest of the vector table */ + + *(.text.*); + } > FLASH + + /DISCARD/ : + { + /* Unused unwinding stuff */ + *(.ARM.exidx.*) + } +} +``` + +``` text +$ xargo rustc --target thumbv7m-none-eabi --release -- \ + -C link-arg=-Tlink.x -C link-arg=-nostartfiles + +$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app +./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm + + +Disassembly of section .text: + +08000000 : + 8000000: 20005000 .word 0x20005000 + +08000004 : + 8000004: 08000009 .... + +08000008 : + 8000008: e7fe b.n 8000008 +``` From f6d262a326b3a44954773fed6983215b62fe4862 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 5 Apr 2017 21:39:43 -0400 Subject: [PATCH 540/662] Add unstable book entry --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../unstable-book/src/compiler-barriers.md | 98 +++++++++++++++++++ src/libcore/sync/atomic.rs | 2 +- 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/doc/unstable-book/src/compiler-barriers.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec816a..68f31ca75e08e 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -37,6 +37,7 @@ - [collections](collections.md) - [collections_range](collections-range.md) - [command_envs](command-envs.md) +- [compiler_barriers](compiler-barriers.md) - [compiler_builtins](compiler-builtins.md) - [compiler_builtins_lib](compiler-builtins-lib.md) - [concat_idents](concat-idents.md) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md new file mode 100644 index 0000000000000..84190dab32737 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -0,0 +1,98 @@ +# `compiler_barriers` + +The tracking issue for this feature is: [#41092] + +[#41092]: https://github.com/rust-lang/rust/issues/41092 + +------------------------ + +The `compiler_barriers` feature exposes the `compiler_barrier` function +in `std::sync::atomic`. This function is conceptually similar to C++'s +`atomic_signal_fence`, which can currently only be accessed in nightly +Rust using the `atomic_singlethreadfence_*` instrinsic functions in +`core`, or through the mostly equivalent literal assembly: + +```rust +#![feature(asm)] +unsafe { asm!("" ::: "memory" : "volatile") }; +``` + +A `compiler_barrier` restricts the kinds of memory re-ordering the +compiler is allowed to do. Specifically, depending on the given ordering +semantics, the compiler may be disallowed from moving reads or writes +from before or after the call to the other side of the call to +`compiler_barrier`. + +## Examples + +The need to prevent re-ordering of reads and writes often arises when +working with low-level devices. Consider a piece of code that interacts +with an ethernet card with a set of internal registers that are accessed +through an address port register (`a: &mut usize`) and a data port +register (`d: &usize`). To read internal register 5, the following code +might then be used: + +```rust +fn read_fifth(a: &mut usize, d: &usize) -> usize { + *a = 5; + *d +} +``` + +In this case, the compiler is free to re-order these two statements if +it thinks doing so might result in better performance, register use, or +anything else compilers care about. However, in doing so, it would break +the code, as `x` would be set to the value of some other device +register! + +By inserting a compiler barrier, we can force the compiler to not +re-arrange these two statements, making the code function correctly +again: + +```rust +#![feature(compiler_barriers)] +use std::sync::atomic; + +fn read_fifth(a: &mut usize, d: &usize) -> usize { + *a = 5; + atomic::compiler_barrier(atomic::Ordering::SeqCst); + *d +} +``` + +Compiler barriers are also useful in code that implements low-level +synchronization primitives. Consider a structure with two different +atomic variables, with a dependency chain between them: + +```rust +use std::sync::atomic; + +fn thread1(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { + x.store(1, atomic::Ordering::Release); + let v1 = y.load(atomic::Ordering::Acquire); +} +fn thread2(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { + y.store(1, atomic::Ordering::Release); + let v2 = x.load(atomic::Ordering::Acquire); +} +``` + +This code will guarantee that `thread1` sees any writes to `y` made by +`thread2`, and that `thread2` sees any writes to `x`. Intuitively, one +might also expect that if `thread2` sees `v2 == 0`, `thread1` must see +`v1 == 1` (since `thread2`'s store happened before its `load`, and its +load did not see `thread1`'s store). However, the code as written does +*not* guarantee this, because the compiler is allowed to re-order the +store and load within each thread. To enforce this particular behavior, +a call to `compiler_barrier(Ordering::SeqCst)` would need to be inserted +between the `store` and `load` in both functions. + +Compiler barriers with weaker re-ordering semantics (such as +`Ordering::Acquire`) can also be useful, but are beyond the scope of +this text. Curious readers are encouraged to read the Linux kernel's +discussion of [memory barriers][1], as well as C++ references on +[`std::memory_order`][2] and [`atomic_signal_fence`][3]. + +[1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt +[2]: http://en.cppreference.com/w/cpp/atomic/memory_order +[3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/ diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 948edda832b46..8cf1d1d54a5e9 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1598,7 +1598,7 @@ pub fn fence(order: Ordering) { /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] -#[unstable(feature = "std_compiler_fences", issue = "41091")] +#[unstable(feature = "compiler_barriers", issue = "41091")] pub fn compiler_barrier(order: Ordering) { unsafe { match order { From 5c6f7fafbdcfe412f0ee836562c3682818604132 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 6 Apr 2017 03:45:08 -0400 Subject: [PATCH 541/662] Point to tracking issue, not PR --- src/doc/unstable-book/src/compiler-barriers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 84190dab32737..5a5c539609c72 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -1,8 +1,8 @@ # `compiler_barriers` -The tracking issue for this feature is: [#41092] +The tracking issue for this feature is: [#41091] -[#41092]: https://github.com/rust-lang/rust/issues/41092 +[#41091]: https://github.com/rust-lang/rust/issues/41091 ------------------------ From 16c77d7da1d1707a90d94d9eb77e0752f974a0db Mon Sep 17 00:00:00 2001 From: raph Date: Thu, 6 Apr 2017 10:17:32 +0200 Subject: [PATCH 542/662] Update process.rs --- src/libstd/process.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 95e625888ccee..8cfd8fcd8c680 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1071,8 +1071,8 @@ pub fn exit(code: i32) -> ! { /// } /// ``` /// -/// The abort function terminates the process, so the destructor will not get -/// run on the example below: +/// The [`abort`] function terminates the process, so the destructor will not +/// get run on the example below: /// /// ```no_run /// use std::process; @@ -1091,7 +1091,6 @@ pub fn exit(code: i32) -> ! { /// // the destructor implemented for HasDrop will never get run /// } /// ``` -/// #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; From 95bd41e339ad07a2d7fb347de0a71fcdf155f2d5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Apr 2017 13:20:24 +0300 Subject: [PATCH 543/662] don't try to blame tuple fields for immutability Tuple fields don't have an `&T` in their declaration that can be changed to `&mut T` - skip them.. Fixes #41104. --- src/librustc/middle/mem_categorization.rs | 18 +++++++++++------- src/test/ui/did_you_mean/issue-39544.rs | 6 ++++++ src/test/ui/did_you_mean/issue-39544.stderr | 8 +++++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b52e85e08e32..7d3c17a048917 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> { } impl<'tcx> cmt_<'tcx> { - fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> { - let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { - bug!("interior cmt {:?} is not an ADT", self) - }); + let adt_def = match self.ty.sty { + ty::TyAdt(def, _) => def, + ty::TyTuple(..) => return None, + // closures get `Categorization::Upvar` rather than `Categorization::Interior` + _ => bug!("interior cmt {:?} is not an ADT", self) + }; let variant_def = match self.cat { Categorization::Downcast(_, variant_did) => { adt_def.variant_with_id(variant_did) @@ -220,7 +223,7 @@ impl<'tcx> cmt_<'tcx> { NamedField(name) => variant_def.field_named(name), PositionalField(idx) => &variant_def.fields[idx] }; - (adt_def, field_def) + Some((adt_def, field_def)) } pub fn immutability_blame(&self) -> Option> { @@ -232,8 +235,9 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(node_id) => Some(ImmutabilityBlame::LocalDeref(node_id)), Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { - let (adt_def, field_def) = base_cmt.resolve_field(field_name); - Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) + }) } Categorization::Upvar(Upvar { id, .. }) => { if let NoteClosureEnv(..) = self.note { diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index 6331fc5771fcb..d7c8935560623 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; } + +pub fn with_tuple() { + let mut y = 0; + let x = (&y,); + *x.0 = 1; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index e1e229a8b0572..2e98bc65e9e9f 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable 52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 11 previous errors +error: cannot assign to immutable borrowed content `*x.0` + --> $DIR/issue-39544.rs:58:5 + | +58 | *x.0 = 1; + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 12 previous errors From b4be4758361bf1b03410a523e8672b1c1fa7d385 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 6 Apr 2017 12:57:40 +0100 Subject: [PATCH 544/662] Fix Markdown issues in the docs * Since the switch to pulldown-cmark reference links need a blank line before the URLs. * Reference link references are not case sensitive. * Doc comments need to be indented uniformly otherwise rustdoc gets confused. --- src/libcollections/vec.rs | 2 +- src/libcore/sync/atomic.rs | 5 +++-- src/libstd/fs.rs | 14 ++++++++++++++ src/libstd/io/buffered.rs | 17 +++++++++-------- src/libstd/io/mod.rs | 9 +++++---- src/libstd/net/tcp.rs | 4 ++-- src/libstd/prelude/mod.rs | 12 ++++++------ src/libstd/sys/windows/ext/fs.rs | 2 +- src/libstd/sys/windows/ext/process.rs | 1 + src/libstd/thread/mod.rs | 4 ++-- 10 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c258ac2bdea9b..35ecf411db4e0 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1346,7 +1346,7 @@ impl Vec { /// # Examples /// /// ``` - ///# #![feature(vec_remove_item)] + /// # #![feature(vec_remove_item)] /// let mut vec = vec![1, 2, 3, 1]; /// /// vec.remove_item(&1); diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 4e5ddfb541e89..2e1058bfc3413 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -153,8 +153,9 @@ unsafe impl Sync for AtomicPtr {} /// Rust's memory orderings are [the same as /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// -/// For more information see the [nomicon][1]. -/// [1]: ../../../nomicon/atomics.html +/// For more information see the [nomicon]. +/// +/// [nomicon]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 1b00eb95de2bc..6b1267d89b6d5 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1176,6 +1176,7 @@ impl AsInner for DirEntry { /// This function currently corresponds to the `unlink` function on Unix /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1212,6 +1213,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// This function currently corresponds to the `stat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1245,6 +1247,7 @@ pub fn metadata>(path: P) -> io::Result { /// This function currently corresponds to the `lstat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1287,6 +1290,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// on Windows, `from` can be anything, but `to` must *not* be a directory. /// /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1330,6 +1334,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// `O_CLOEXEC` is set for returned file descriptors. /// On Windows, this function currently corresponds to `CopyFileEx`. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1366,6 +1371,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// This function currently corresponds to the `link` function on Unix /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1424,6 +1430,7 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1457,6 +1464,7 @@ pub fn read_link>(path: P) -> io::Result { /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1489,6 +1497,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1522,6 +1531,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1562,6 +1572,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// This function currently corresponds to the `rmdir` function on Unix /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1599,6 +1610,7 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions /// on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1633,6 +1645,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// This function currently corresponds to the `opendir` function on Unix /// and the `FindFirstFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1679,6 +1692,7 @@ pub fn read_dir>(path: P) -> io::Result { /// This function currently corresponds to the `chmod` function on Unix /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index f98a3a87b018f..3b82412716e54 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -21,12 +21,12 @@ use memchr; /// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`] on [`TcpStream`] results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying [`Read`] -/// and maintains an in-memory buffer of the results. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. /// /// [`Read`]: ../../std/io/trait.Read.html -/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples @@ -261,9 +261,10 @@ impl Seek for BufReader { /// Wraps a writer and buffers its output. /// /// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`] -/// results in a system call. A `BufWriter` keeps an in-memory buffer of data -/// and writes it to an underlying writer in large, infrequent batches. +/// implements [`Write`]. For example, every call to +/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. /// @@ -303,7 +304,7 @@ impl Seek for BufReader { /// the `stream` is dropped. /// /// [`Write`]: ../../std/io/trait.Write.html -/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write /// [`TcpStream`]: ../../std/net/struct.TcpStream.html #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8ebc5c0a8fe2d..cd096c115ba5a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,8 @@ //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For -//! example, [`Read`] adds a [`read`] method, which we can use on `File`s: +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! `File`s: //! //! ``` //! use std::io; @@ -106,7 +107,7 @@ //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write`]: +//! to [`write`][`Write::write`]: //! //! ``` //! use std::io; @@ -257,13 +258,13 @@ //! [`Vec`]: ../vec/struct.Vec.html //! [`BufReader`]: struct.BufReader.html //! [`BufWriter`]: struct.BufWriter.html -//! [`write`]: trait.Write.html#tymethod.write +//! [`Write::write`]: trait.Write.html#tymethod.write //! [`io::stdout`]: fn.stdout.html //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`?` operator]: ../../book/syntax-index.html -//! [`read`]: trait.Read.html#tymethod.read +//! [`Read::read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index cf119720e5a17..bc315d54100e4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -58,7 +58,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens /// for incoming TCP connections. These can be accepted by calling [`accept`] or by -/// iterating over the [`Incoming`] iterator returned by [`incoming`]. +/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. /// /// The socket will be closed when the value is dropped. /// @@ -68,7 +68,7 @@ pub struct TcpStream(net_imp::TcpStream); /// [`bind`]: #method.bind /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`Incoming`]: ../../std/net/struct.Incoming.html -/// [`incoming`]: #method.incoming +/// [`TcpListener::incoming`]: #method.incoming /// /// # Examples /// diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index c71e0b2a7035a..86e661d7948f0 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -56,14 +56,14 @@ //! traits indicate fundamental properties of types. //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various //! operations for both destructors and overloading `()`. -//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a -//! value. +//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly +//! dropping a value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`], -//! the method for producing a copy of a value. +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines +//! [`clone`][`Clone::clone`], the method for producing a copy of a value. //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The //! comparison traits, which implement the comparison operators and are often //! seen in trait bounds. @@ -117,8 +117,8 @@ //! [`ToOwned`]: ../borrow/trait.ToOwned.html //! [`ToString`]: ../string/trait.ToString.html //! [`Vec`]: ../vec/struct.Vec.html -//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone -//! [`drop`]: ../mem/fn.drop.html +//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [`mem::drop`]: ../mem/fn.drop.html //! [`std::borrow`]: ../borrow/index.html //! [`std::boxed`]: ../boxed/index.html //! [`std::clone`]: ../clone/index.html diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index c63dd8a47ca4f..d6e2fed56be96 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -144,7 +144,7 @@ pub trait OpenOptionsExt { /// `CreateFile`). /// /// If a _new_ file is created because it does not yet exist and - ///`.create(true)` or `.create_new(true)` are specified, the new file is + /// `.create(true)` or `.create_new(true)` are specified, the new file is /// given the attributes declared with `.attributes()`. /// /// If an _existing_ file is opened with `.create(true).truncate(true)`, its diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 1419a4af42738..759f055c4b123 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -104,6 +104,7 @@ pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 18c00e7c5f1b6..7ab6b82ada344 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -90,7 +90,7 @@ //! two ways: //! //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread`] on the [`JoinHandle`]. +//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. //! * By requesting the current thread, using the [`thread::current`] function. //! //! The [`thread::current`] function is available even for threads not spawned @@ -151,7 +151,7 @@ //! [`Arc`]: ../../std/sync/struct.Arc.html //! [`spawn`]: ../../std/thread/fn.spawn.html //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread +//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join //! [`Result`]: ../../std/result/enum.Result.html //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok From f9fb381b2a13260c3fcdae2f6d9546ab2c87e717 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 6 Apr 2017 13:09:20 +0100 Subject: [PATCH 545/662] rustdoc: Use pulldown-cmark for Markdown HTML rendering Instead of rendering all of the HTML in rustdoc this relies on pulldown-cmark's `push_html` to do most of the work. A few iterator adapters are used to make rustdoc specific modifications to the output. This also fixes MarkdownHtml and link titles in plain_summary_line. --- src/librustdoc/html/markdown.rs | 728 +++++++----------- src/librustdoc/html/render.rs | 12 +- src/librustdoc/markdown.rs | 4 +- src/test/rustdoc/check-hard-break.rs | 3 +- src/test/rustdoc/check-rule-image-footnote.rs | 14 +- src/test/rustdoc/test-lists.rs | 14 +- src/tools/error_index_generator/main.rs | 4 +- 7 files changed, 296 insertions(+), 483 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 245a3946a3709..1e687d63f5875 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -16,10 +16,10 @@ //! of `fmt::Display`. Example usage: //! //! ```rust,ignore -//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle}; +//! use rustdoc::html::markdown::Markdown; //! //! let s = "My *markdown* _text_"; -//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy)); +//! let html = format!("{}", Markdown(s)); //! // ... something using html //! ``` @@ -27,7 +27,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::default::Default; use std::fmt::{self, Write}; use std::str; @@ -37,43 +37,23 @@ use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; use html::highlight; -use html::escape::Escape; use test; -use pulldown_cmark::{self, Event, Parser, Tag}; - -#[derive(Copy, Clone)] -pub enum MarkdownOutputStyle { - Compact, - Fancy, -} - -impl MarkdownOutputStyle { - pub fn is_compact(&self) -> bool { - match *self { - MarkdownOutputStyle::Compact => true, - _ => false, - } - } - - pub fn is_fancy(&self) -> bool { - match *self { - MarkdownOutputStyle::Fancy => true, - _ => false, - } - } -} +use pulldown_cmark::{html, Event, Tag, Parser}; +use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle); +pub struct Markdown<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); +/// A unit struct like `Markdown`, that renders only the first paragraph. +pub struct MarkdownSummaryLine<'a>(pub &'a str); /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of @@ -90,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } -/// Returns a new string with all consecutive whitespace collapsed into -/// single spaces. +/// Convert chars from a title for an id. /// -/// Any leading or trailing whitespace will be trimmed. -fn collapse_whitespace(s: &str) -> String { - s.split_whitespace().collect::>().join(" ") +/// "Hello, world!" -> "hello-world" +fn slugify(c: char) -> Option { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } } // Information about the playground if a URL has been specified, containing an @@ -104,103 +93,50 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); -macro_rules! event_loop_break { - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr, - $($end_event:pat)|*) => {{ - fn inner(id: &mut Option<&mut String>, s: &str) { - if let Some(ref mut id) = *id { - id.push_str(s); - } - } - while let Some(event) = $parser.next() { - match event { - $($end_event)|* => break, - Event::Text(ref s) => { - debug!("Text"); - inner($id, s); - if $escape { - $buf.push_str(&format!("{}", Escape(s))); - } else { - $buf.push_str(s); - } - } - Event::SoftBreak => { - debug!("SoftBreak"); - if !$buf.is_empty() { - $buf.push(' '); - } - } - x => { - looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); - } - } - } - }} -} - -struct ParserWrapper<'a> { - parser: Parser<'a>, - // The key is the footnote reference. The value is the footnote definition and the id. - footnotes: HashMap, +/// Adds syntax highlighting and playground Run buttons to rust code blocks. +struct CodeBlocks<'a, I: Iterator>> { + inner: I, } -impl<'a> ParserWrapper<'a> { - pub fn new(s: &'a str) -> ParserWrapper<'a> { - ParserWrapper { - parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | - pulldown_cmark::OPTION_ENABLE_FOOTNOTES), - footnotes: HashMap::new(), +impl<'a, I: Iterator>> CodeBlocks<'a, I> { + fn new(iter: I) -> Self { + CodeBlocks { + inner: iter, } } +} - pub fn next(&mut self) -> Option> { - self.parser.next() - } +impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { + type Item = Event<'a>; - pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) { - let new_id = self.footnotes.keys().count() + 1; - let key = key.to_owned(); - self.footnotes.entry(key).or_insert((String::new(), new_id as u16)) - } -} + fn next(&mut self) -> Option { + let event = self.inner.next(); + if let Some(Event::Start(Tag::CodeBlock(lang))) = event { + if !LangString::parse(&lang).rust { + return Some(Event::Start(Tag::CodeBlock(lang))); + } + } else { + return event; + } -pub fn render(w: &mut fmt::Formatter, - s: &str, - print_toc: bool, - shorter: MarkdownOutputStyle) -> fmt::Result { - fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { - debug!("CodeBlock"); let mut origtext = String::new(); - while let Some(event) = parser.next() { + for event in &mut self.inner { match event { - Event::End(Tag::CodeBlock(_)) => break, + Event::End(Tag::CodeBlock(..)) => break, Event::Text(ref s) => { origtext.push_str(s); } _ => {} } } - let origtext = origtext.trim_left(); - debug!("docblock: ==============\n{:?}\n=======", origtext); - let lines = origtext.lines().filter(|l| { stripped_filtered_line(*l).is_none() }); let text = lines.collect::>().join("\n"); - let block_info = if lang.is_empty() { - LangString::all_false() - } else { - LangString::parse(lang) - }; - if !block_info.rust { - buffer.push_str(&format!("

    {}
    ", - lang, text)); - return - } PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output - buffer.push('\n'); + let mut s = String::from("\n"); let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { if url.is_empty() { return None; @@ -210,7 +146,7 @@ pub fn render(w: &mut fmt::Formatter, }).collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let test = test::maketest(&test, krate, false, - &Default::default()); + &Default::default()); let channel = if test.contains("#![feature(") { "&version=nightly" } else { @@ -239,376 +175,186 @@ pub fn render(w: &mut fmt::Formatter, url, test_escaped, channel )) }); - buffer.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - }); - } - - fn heading(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { - debug!("Heading"); - let mut ret = String::new(); - let mut id = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), - Event::End(Tag::Header(_))); - ret = ret.trim_right().to_owned(); - - let id = id.chars().filter_map(|c| { - if c.is_alphanumeric() || c == '-' || c == '_' { - if c.is_ascii() { - Some(c.to_ascii_lowercase()) - } else { - Some(c) - } - } else if c.is_whitespace() && c.is_ascii() { - Some('-') - } else { - None - } - }).collect::(); - - let id = derive_id(id); - - let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| { - format!("{} ", builder.push(level as u32, ret.clone(), id.clone())) - }); - - // Render the HTML - buffer.push_str(&format!("\ - {sec}{}", - ret, lvl = level, id = id, sec = sec)); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + Some(Event::Html(s.into())) + }) } +} - fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("InlineCode"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); - buffer.push_str(&format!("{}", - Escape(&collapse_whitespace(content.trim_right())))); - } +/// Make headings links with anchor ids and build up TOC. +struct HeadingLinks<'a, 'b, I: Iterator>> { + inner: I, + toc: Option<&'b mut TocBuilder>, + buf: VecDeque>, +} - fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, url: &str, title: &str, - id: &mut Option<&mut String>) { - debug!("Link"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Link(_, _))); - if title.is_empty() { - buffer.push_str(&format!("{}", url, content)); - } else { - buffer.push_str(&format!("{}", - url, Escape(title), content)); +impl<'a, 'b, I: Iterator>> HeadingLinks<'a, 'b, I> { + fn new(iter: I, toc: Option<&'b mut TocBuilder>) -> Self { + HeadingLinks { + inner: iter, + toc: toc, + buf: VecDeque::new(), } } +} - fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, url: &str, mut title: String, - id: &mut Option<&mut String>) { - debug!("Image"); - event_loop_break!(parser, toc_builder, shorter, title, true, id, - Event::End(Tag::Image(_, _))); - buffer.push_str(&format!("\"{}\"", url, title)); - } - - fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("Paragraph"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Paragraph)); - buffer.push_str(&format!("

    {}

    ", content.trim_right())); - } - - fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("TableCell"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell)); - buffer.push_str(&format!("{}", content.trim())); - } +impl<'a, 'b, I: Iterator>> Iterator for HeadingLinks<'a, 'b, I> { + type Item = Event<'a>; - fn table_row(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("TableRow"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) => break, - Event::Start(Tag::TableCell) => { - table_cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } + fn next(&mut self) -> Option { + if let Some(e) = self.buf.pop_front() { + return Some(e); } - buffer.push_str(&format!("{}", content)); - } - fn table_head(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("TableHead"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableCell) => { - table_cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + let event = self.inner.next(); + if let Some(Event::Start(Tag::Header(level))) = event { + let mut id = String::new(); + for event in &mut self.inner { + match event { + Event::End(Tag::Header(..)) => break, + Event::Text(ref text) => id.extend(text.chars().filter_map(slugify)), + _ => {}, } + self.buf.push_back(event); } - } - if !content.is_empty() { - buffer.push_str(&format!("{}", content.replace("td>", "th>"))); - } - } + let id = derive_id(id); - fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { - debug!("Table"); - let mut content = String::new(); - let mut rows = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableHead) => { - table_head(parser, &mut content, toc_builder, shorter); - } - Event::Start(Tag::TableRow) => { - table_row(parser, &mut rows, toc_builder, shorter); - } - _ => {} + if let Some(ref mut builder) = self.toc { + let mut html_header = String::new(); + html::push_html(&mut html_header, self.buf.iter().cloned()); + let sec = builder.push(level as u32, html_header, id.clone()); + self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into())); } - } - buffer.push_str(&format!("{}{}
    ", - content, - if shorter.is_compact() || rows.is_empty() { - String::new() - } else { - format!("{}", rows) - })); - } - fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("BlockQuote"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, - Event::End(Tag::BlockQuote)); - buffer.push_str(&format!("
    {}
    ", content.trim_right())); - } + self.buf.push_back(Event::InlineHtml(format!("", level).into())); - fn list_item(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("ListItem"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Item) => break, - Event::Text(ref s) => { - content.push_str(&format!("{}", Escape(s))); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } - if shorter.is_compact() { - break - } + let start_tags = format!("\ + ", + id = id, + level = level); + return Some(Event::InlineHtml(start_tags.into())); } - buffer.push_str(&format!("
  • {}
  • ", content)); + event } +} - fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, is_sorted_list: bool) { - debug!("List"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::List(_)) => break, - Event::Start(Tag::Item) => { - list_item(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } - if shorter.is_compact() { - break - } +/// Extracts just the first paragraph. +struct SummaryLine<'a, I: Iterator>> { + inner: I, + started: bool, + depth: u32, +} + +impl<'a, I: Iterator>> SummaryLine<'a, I> { + fn new(iter: I) -> Self { + SummaryLine { + inner: iter, + started: false, + depth: 0, } - buffer.push_str(&format!("<{0}>{1}", - if is_sorted_list { "ol" } else { "ul" }, - content)); } +} - fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("Emphasis"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, - Event::End(Tag::Emphasis)); - buffer.push_str(&format!("{}", content)); - } +impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { + type Item = Event<'a>; - fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - debug!("Strong"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, - Event::End(Tag::Strong)); - buffer.push_str(&format!("{}", content)); + fn next(&mut self) -> Option { + if self.started && self.depth == 0 { + return None; + } + if !self.started { + self.started = true; + } + let event = self.inner.next(); + match event { + Some(Event::Start(..)) => self.depth += 1, + Some(Event::End(..)) => self.depth -= 1, + _ => {} + } + event } +} - fn footnote(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("FootnoteDefinition"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::FootnoteDefinition(_))); - buffer.push_str(&content); - } +/// Moves all footnote definitions to the end and add back links to the +/// references. +struct Footnotes<'a, I: Iterator>> { + inner: I, + footnotes: HashMap>, u16)>, +} - fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - debug!("Rule"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Rule)); - buffer.push_str("
    "); +impl<'a, I: Iterator>> Footnotes<'a, I> { + fn new(iter: I) -> Self { + Footnotes { + inner: iter, + footnotes: HashMap::new(), + } + } + fn get_entry(&mut self, key: &str) -> &mut (Vec>, u16) { + let new_id = self.footnotes.keys().count() + 1; + let key = key.to_owned(); + self.footnotes.entry(key).or_insert((Vec::new(), new_id as u16)) } +} - fn looper<'a>(parser: &'a mut ParserWrapper, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) -> bool { - if let Some(event) = next_event { - match event { - Event::Start(Tag::CodeBlock(lang)) => { - code_block(parser, buffer, &*lang); - } - Event::Start(Tag::Header(level)) => { - heading(parser, buffer, toc_builder, shorter, level); - } - Event::Start(Tag::Code) => { - inline_code(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref(), id); - } - Event::Start(Tag::Image(ref url, ref t)) => { - image(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); - } - Event::Start(Tag::Table(_)) => { - table(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::BlockQuote) => { - blockquote(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::List(x)) => { - list(parser, buffer, toc_builder, shorter, x.is_some()); - } - Event::Start(Tag::Emphasis) => { - emphasis(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Strong) => { - strong(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Rule) => { - rule(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::FootnoteDefinition(ref def)) => { - debug!("FootnoteDefinition"); - let mut content = String::new(); - let def = def.as_ref(); - footnote(parser, &mut content, toc_builder, shorter, id); - let entry = parser.get_entry(def); - let cur_id = (*entry).1; - (*entry).0.push_str(&format!("
  • {} 

  • ", - cur_id, - if content.ends_with("

    ") { - &content[..content.len() - 4] - } else { - &content - })); - } - Event::FootnoteReference(ref reference) => { - debug!("FootnoteReference"); - let entry = parser.get_entry(reference.as_ref()); - buffer.push_str(&format!("{0}\ - ", - (*entry).1)); - } - Event::HardBreak => { - debug!("HardBreak"); - if shorter.is_fancy() { - buffer.push_str("
    "); - } else if !buffer.is_empty() { - buffer.push(' '); +impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option { + loop { + match self.inner.next() { + Some(Event::FootnoteReference(ref reference)) => { + let entry = self.get_entry(&reference); + let reference = format!("{0}\ + ", + (*entry).1); + return Some(Event::Html(reference.into())); + } + Some(Event::Start(Tag::FootnoteDefinition(def))) => { + let mut content = Vec::new(); + for event in &mut self.inner { + if let Event::End(Tag::FootnoteDefinition(..)) = event { + break; + } + content.push(event); + } + let entry = self.get_entry(&def); + (*entry).0 = content; + } + Some(e) => return Some(e), + None => { + if !self.footnotes.is_empty() { + let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect(); + v.sort_by(|a, b| a.1.cmp(&b.1)); + let mut ret = String::from("

      "); + for (mut content, id) in v { + write!(ret, "
    1. ", id).unwrap(); + let mut is_paragraph = false; + if let Some(&Event::End(Tag::Paragraph)) = content.last() { + content.pop(); + is_paragraph = true; + } + html::push_html(&mut ret, content.into_iter()); + write!(ret, + " ", + id).unwrap(); + if is_paragraph { + ret.push_str("

      "); + } + ret.push_str("
    2. "); + } + ret.push_str("
    "); + return Some(Event::Html(ret.into())); + } else { + return None; } } - Event::Html(h) | Event::InlineHtml(h) => { - debug!("Html/InlineHtml"); - buffer.push_str(&*h); - } - _ => {} } - shorter.is_fancy() - } else { - false } } - - let mut toc_builder = if print_toc { - Some(TocBuilder::new()) - } else { - None - }; - let mut buffer = String::new(); - let mut parser = ParserWrapper::new(s); - loop { - let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { - break - } - } - if !parser.footnotes.is_empty() { - let mut v: Vec<_> = parser.footnotes.values().collect(); - v.sort_by(|a, b| a.1.cmp(&b.1)); - buffer.push_str(&format!("

      {}
    ", - v.iter() - .map(|s| s.0.as_str()) - .collect::>() - .join(""))); - } - let mut ret = toc_builder.map_or(Ok(()), |builder| { - write!(w, "", builder.into_toc()) - }); - - if ret.is_ok() { - ret = w.write_str(&buffer); - } - ret } pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { @@ -755,17 +501,45 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md, shorter) = *self; + let Markdown(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, shorter) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + + fmt.write_str(&s) } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, MarkdownOutputStyle::Fancy) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + let mut toc = TocBuilder::new(); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); + + write!(fmt, "", toc.into_toc())?; + + fmt.write_str(&s) } } @@ -774,7 +548,41 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, MarkdownOutputStyle::Fancy) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + // Treat inline HTML as plain text. + let p = p.map(|event| match event { + Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + _ => event + }); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + + fmt.write_str(&s) + } +} + +impl<'a> fmt::Display for MarkdownSummaryLine<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let MarkdownSummaryLine(md) = *self; + // This is actually common enough to special-case + if md.is_empty() { return Ok(()) } + + let p = Parser::new(md); + + let mut s = String::new(); + + html::push_html(&mut s, SummaryLine::new(p)); + + fmt.write_str(&s) } } @@ -796,14 +604,10 @@ pub fn plain_summary_line(md: &str) -> String { let next_event = next_event.unwrap(); let (ret, is_in) = match next_event { Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Link(_, ref t)) if !self.is_first => { - (Some(t.as_ref().to_owned()), 1) - } Event::Start(Tag::Code) => (Some("`".to_owned()), 1), Event::End(Tag::Code) => (Some("`".to_owned()), -1), Event::Start(Tag::Header(_)) => (None, 1), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), _ => (None, 0), }; @@ -834,7 +638,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { - use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle}; + use super::{LangString, Markdown, MarkdownHtml}; use super::plain_summary_line; use html::render::reset_ids; @@ -874,14 +678,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy)); + format!("{}", Markdown(markdown)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + let output = format!("{}", Markdown(input)); assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -903,7 +707,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + let output = format!("{}", Markdown(input)); assert_eq!(output, expect, "original: {}", input); } @@ -934,6 +738,7 @@ mod tests { } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); t("code `let x = i32;` ...", "code `let x = i32;` ..."); t("type `Type<'static>` ...", "type `Type<'static>` ..."); t("# top header", "top header"); @@ -947,7 +752,8 @@ mod tests { assert_eq!(output, expect, "original: {}", input); } - t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); - t("Struct<'a, T>", "

    Struct<'a, T>

    "); + t("`Struct<'a, T>`", "

    Struct<'a, T>

    \n"); + t("Struct<'a, T>", "

    Struct<'a, T>

    \n"); + t("Struct
    ", "

    Struct<br>

    \n"); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f0b624105e347..1e1202f04005c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -1651,7 +1651,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin format!("{}", &plain_summary_line(Some(s))) }; write!(w, "
    {}
    ", - Markdown(&markdown, MarkdownOutputStyle::Fancy))?; + Markdown(&markdown))?; } Ok(()) } @@ -1684,8 +1684,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
    {}
    ", - Markdown(&format!("{}{}", md_render_assoc_item(item), s), - MarkdownOutputStyle::Fancy))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; } Ok(()) } @@ -1873,8 +1872,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value, - MarkdownOutputStyle::Compact).to_string())), + docs = MarkdownSummaryLine(doc_value), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2904,7 +2902,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
    {}
    ", Markdown(dox, MarkdownOutputStyle::Fancy))?; + write!(w, "
    {}
    ", Markdown(dox))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 5cc0f03e1f629..5fadda030a4b4 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -96,7 +96,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text, MarkdownOutputStyle::Fancy)) + format!("{}", Markdown(text)) }; let err = write!( diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs index 5c5e3f8136c73..f048b64d104ab 100644 --- a/src/test/rustdoc/check-hard-break.rs +++ b/src/test/rustdoc/check-hard-break.rs @@ -13,7 +13,8 @@ // ignore-tidy-end-whitespace // @has foo/fn.f.html -// @has - '

    hard break:
    after hard break

    ' +// @has - '

    hard break:
    ' +// @has - 'after hard break

    ' /// hard break: /// after hard break pub fn f() {} diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs index 4d3bea20ba895..46542677857fc 100644 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -13,16 +13,21 @@ // ignore-tidy-linelength // @has foo/fn.f.html -// @has - '

    markdown test

    this is a link.

    hard break: after hard break


    a footnote1.

    another footnote2.

    Rust


    1. Thing 

    2. Another Thing 

    ' +// @has - '

    markdown test

    ' +// @has - '

    this is a link.

    ' +// @has - '
    ' +// @has - '

    a footnote1.

    ' +// @has - '

    another footnote2.

    ' +// @has - '

    Rust

    ' +// @has - '

    1. ' +// @has - '

      Thing 

    2. ' +// @has - '

      Another Thing 

    ' /// markdown test /// /// this is a [link]. /// /// [link]: https://example.com "this is a title" /// -/// hard break: -/// after hard break -/// /// ----------- /// /// a footnote[^footnote]. @@ -36,5 +41,4 @@ /// /// /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) -#[deprecated(note = "Struct")] pub fn f() {} diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs index 71a826a2bed7f..29f157e0425c9 100644 --- a/src/test/rustdoc/test-lists.rs +++ b/src/test/rustdoc/test-lists.rs @@ -10,10 +10,11 @@ #![crate_name = "foo"] -// ignore-tidy-linelength - // @has foo/fn.f.html -// @has - "
    pub fn f()
    1. list
      1. fooooo
      2. x
    2. foo
    " +// @has - //ol/li "list" +// @has - //ol/li/ol/li "fooooo" +// @has - //ol/li/ol/li "x" +// @has - //ol/li "foo" /// 1. list /// 1. fooooo /// 2. x @@ -21,7 +22,10 @@ pub fn f() {} // @has foo/fn.foo2.html -// @has - "
    pub fn foo2()
    • normal list
      • sub list

      • new elem still same elem

        and again same elem!

    • new big elem
    " +// @has - //ul/li "normal list" +// @has - //ul/li/ul/li "sub list" +// @has - //ul/li/ul/li "new elem still same elem and again same elem!" +// @has - //ul/li "new big elem" /// * normal list /// * sub list /// * new elem @@ -29,4 +33,4 @@ pub fn f() {} /// /// and again same elem! /// * new big elem -pub fn foo2() {} \ No newline at end of file +pub fn foo2() {} diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 5db2ad83a0a7a..efadde992277f 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?, + Some(ref desc) => write!(output, "{}", Markdown(desc))?, None => write!(output, "

    No description.

    \n")?, } From 7d25e768ea58658a6523f4a0c1579582b298e43d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 08:48:48 -0500 Subject: [PATCH 546/662] add link to issue number, ignore snippet that requires custom linking --- src/doc/unstable-book/src/used.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md index 749c9a8ec288c..cdda24acd708b 100644 --- a/src/doc/unstable-book/src/used.md +++ b/src/doc/unstable-book/src/used.md @@ -1,6 +1,7 @@ # `used` -The tracking issue for this feature is: 40289. +The tracking issue for this feature +is: [40289](https://github.com/rust-lang/rust/issues/40289). ------------------------ @@ -85,7 +86,7 @@ turned on, to be placed near the start of their FLASH memory to boot properly. This condition can be met using `#[used]` and `#[link_section]` plus a linker script. -``` rust +``` rust,ignore #![feature(lang_items)] #![feature(used)] #![no_main] From 1f93a78cdc388835bb2575c5432950294ad5809c Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Thu, 6 Apr 2017 21:48:56 +0800 Subject: [PATCH 547/662] .gitmodules: use the official Git URL w/o redirect --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 53d1787492409..3533f0df5d1ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,4 +25,4 @@ url = https://github.com/rust-lang-nursery/reference.git [submodule "book"] path = src/doc/book - url = https://github.com/rust-lang/book + url = https://github.com/rust-lang/book.git From c47cdc0d93726429ee18b418b1f85fae67b82d41 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 30 Mar 2017 15:27:27 +0200 Subject: [PATCH 548/662] Introduce HashStable trait and base ICH implementations on it. This initial commit provides implementations for HIR, MIR, and everything that also needs to be supported for those two. --- src/librustc/hir/map/definitions.rs | 4 + src/librustc/ich/hcx.rs | 300 +++++ src/librustc/ich/impls_const_math.rs | 71 ++ src/librustc/ich/impls_hir.rs | 1104 ++++++++++++++++ src/librustc/ich/impls_mir.rs | 407 ++++++ src/librustc/ich/impls_syntax.rs | 301 +++++ src/librustc/ich/impls_ty.rs | 415 ++++++ src/librustc/ich/mod.rs | 28 +- src/librustc/lib.rs | 1 + src/librustc/macros.rs | 79 ++ src/librustc/mir/cache.rs | 11 +- src/librustc/mir/mod.rs | 18 + src/librustc/ty/mod.rs | 29 + src/librustc_data_structures/lib.rs | 2 + src/librustc_data_structures/stable_hasher.rs | 192 ++- src/librustc_incremental/calculate_svh/mod.rs | 197 ++- .../calculate_svh/svh_visitor.rs | 1111 ----------------- src/librustc_incremental/lib.rs | 1 - src/librustc_trans/assert_module_sources.rs | 7 +- src/libsyntax/ptr.rs | 12 + src/libsyntax/util/rc_slice.rs | 13 + 21 files changed, 3080 insertions(+), 1223 deletions(-) create mode 100644 src/librustc/ich/hcx.rs create mode 100644 src/librustc/ich/impls_const_math.rs create mode 100644 src/librustc/ich/impls_hir.rs create mode 100644 src/librustc/ich/impls_mir.rs create mode 100644 src/librustc/ich/impls_syntax.rs create mode 100644 src/librustc/ich/impls_ty.rs delete mode 100644 src/librustc_incremental/calculate_svh/svh_visitor.rs diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 809d5db3071d7..dca9ebb3397a6 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -394,6 +394,10 @@ impl Definitions { } } + pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { + self.node_to_hir_id[node_id] + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, parent: Option, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs new file mode 100644 index 0000000000000..73d81212cd77e --- /dev/null +++ b/src/librustc/ich/hcx.rs @@ -0,0 +1,300 @@ +// Copyright 2017 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 hir; +use hir::def_id::DefId; +use ich::{self, CachingCodemapView, DefPathHashes}; +use session::config::DebugInfoLevel::NoDebugInfo; +use ty; + +use std::hash as std_hash; + +use syntax::ast; +use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; +use syntax::symbol::Symbol; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform DefIds and HirIds into stable DefPaths (i.e. +/// a reference to the TyCtxt) and it holds a few caches for speeding up various +/// things (e.g. each DefId/DefPath is only hashed once). +pub struct StableHashingContext<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_path_hashes: DefPathHashes<'a, 'tcx>, + codemap: CachingCodemapView<'tcx>, + hash_spans: bool, + hash_bodies: bool, + overflow_checks_enabled: bool, + node_id_hashing_mode: NodeIdHashingMode, + // A sorted array of symbol keys for fast lookup. + ignored_attr_names: Vec, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NodeIdHashingMode { + Ignore, + HashDefPath, + HashTraitsInScope, +} + +impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { + + pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self { + let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo; + let check_overflow_initial = tcx.sess.overflow_checks(); + + let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES + .iter() + .map(|&s| Symbol::intern(s)) + .collect(); + + ignored_attr_names.sort(); + + StableHashingContext { + tcx: tcx, + def_path_hashes: DefPathHashes::new(tcx), + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans_initial, + hash_bodies: true, + overflow_checks_enabled: check_overflow_initial, + node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + ignored_attr_names: ignored_attr_names, + } + } + + #[inline] + pub fn while_hashing_hir_bodies(&mut self, + hash_bodies: bool, + f: F) { + let prev_hash_bodies = self.hash_bodies; + self.hash_bodies = hash_bodies; + f(self); + self.hash_bodies = prev_hash_bodies; + } + + #[inline] + pub fn while_hashing_spans(&mut self, + hash_spans: bool, + f: F) { + let prev_hash_spans = self.hash_spans; + self.hash_spans = hash_spans; + f(self); + self.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn with_node_id_hashing_mode(&mut self, + mode: NodeIdHashingMode, + f: F) { + let prev = self.node_id_hashing_mode; + self.node_id_hashing_mode = mode; + f(self); + self.node_id_hashing_mode = prev; + } + + #[inline] + pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + #[inline] + pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { + self.def_path_hashes.hash(def_id) + } + + #[inline] + pub fn hash_spans(&self) -> bool { + self.hash_spans + } + + #[inline] + pub fn hash_bodies(&self) -> bool { + self.hash_bodies + } + + #[inline] + pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> { + &mut self.codemap + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + self.ignored_attr_names.binary_search(&name).is_ok() + } + + pub fn hash_hir_item_like(&mut self, + item_attrs: &[ast::Attribute], + f: F) { + let prev_overflow_checks = self.overflow_checks_enabled; + if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { + self.overflow_checks_enabled = true; + } + let prev_hash_node_ids = self.node_id_hashing_mode; + self.node_id_hashing_mode = NodeIdHashingMode::Ignore; + + f(self); + + self.node_id_hashing_mode = prev_hash_node_ids; + self.overflow_checks_enabled = prev_overflow_checks; + } + + #[inline] + pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool + { + match binop { + hir::BiAdd | + hir::BiSub | + hir::BiMul => self.overflow_checks_enabled, + + hir::BiDiv | + hir::BiRem => true, + + hir::BiAnd | + hir::BiOr | + hir::BiBitXor | + hir::BiBitAnd | + hir::BiBitOr | + hir::BiShl | + hir::BiShr | + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => false + } + } + + #[inline] + pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool + { + match unop { + hir::UnDeref | + hir::UnNot => false, + hir::UnNeg => self.overflow_checks_enabled, + } + } +} + + +impl<'a, 'tcx> HashStable> for ast::NodeId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Most NodeIds in the HIR can be ignored, but if there is a + // corresponding entry in the `trait_map` we need to hash that. + // Make sure we don't ignore too much by checking that there is + // no entry in a debug_assert!(). + debug_assert!(hcx.tcx.trait_map.get(self).is_none()); + } + NodeIdHashingMode::HashDefPath => { + hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher); + } + NodeIdHashingMode::HashTraitsInScope => { + if let Some(traits) = hcx.tcx.trait_map.get(self) { + // The ordering of the candidates is not fixed. So we hash + // the def-ids and then sort them and hash the collection. + let mut candidates: AccumulateVec<[_; 8]> = + traits.iter() + .map(|&hir::TraitCandidate { def_id, import_id: _ }| { + hcx.def_path_hash(def_id) + }) + .collect(); + if traits.len() > 1 { + candidates.sort(); + } + candidates.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for Span { + + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // within the CodeMap. + // Also note that we are hashing byte offsets for the column, not unicode + // codepoint offsets. For the purpose of the hash that's sufficient. + // Also, hashing filenames is expensive so we avoid doing it twice when the + // span starts and ends in the same file, which is almost always the case. + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use syntax_pos::Pos; + + if !hcx.hash_spans { + return + } + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if self.hi > self.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + self.hi - ::syntax_pos::BytePos(1) + } else { + self.hi + }; + + { + let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + if loc1.0 == loc2.0 { + std_hash::Hash::hash(&0u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + // Do not hash the file name twice + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } else { + std_hash::Hash::hash(&1u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + std_hash::Hash::hash(loc2.0, hasher); + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } + } + + if self.ctxt == SyntaxContext::empty() { + 0u8.hash_stable(hcx, hasher); + } else { + 1u8.hash_stable(hcx, hasher); + self.source_callsite().hash_stable(hcx, hasher); + } + } +} diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs new file mode 100644 index 0000000000000..6d11f2a87a413 --- /dev/null +++ b/src/librustc/ich/impls_const_math.rs @@ -0,0 +1,71 @@ +// Copyright 2017 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 module contains `HashStable` implementations for various data types +//! from `rustc_const_math` in no particular order. + +impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat { + F32(val), + F64(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstInt { + I8(val), + I16(val), + I32(val), + I64(val), + I128(val), + Isize(val), + U8(val), + U16(val), + U32(val), + U64(val), + U128(val), + Usize(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize { + Is16(i16), + Is32(i32), + Is64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize { + Us16(i16), + Us32(i32), + Us64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { + NotInRange, + CmpBetweenUnequalTypes, + UnequalTypes(op), + Overflow(op), + ShiftNegative, + DivisionByZero, + RemainderByZero, + UnsignedNegation, + ULitOutOfRange(int_ty), + LitOutOfRange(int_ty) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::Op { + Add, + Sub, + Mul, + Div, + Rem, + Shr, + Shl, + Neg, + BitAnd, + BitOr, + BitXor +}); diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs new file mode 100644 index 0000000000000..fb18f50027e29 --- /dev/null +++ b/src/librustc/ich/impls_hir.rs @@ -0,0 +1,1104 @@ +// Copyright 2017 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 module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use hir; +use hir::def_id::DefId; +use ich::{StableHashingContext, NodeIdHashingMode}; +use std::mem; + +use syntax::ast; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; + +impl<'a, 'tcx> HashStable> for DefId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.def_path_hash(*self).hash_stable(hcx, hasher); + } +} + + +impl<'a, 'tcx> HashStable> for hir::HirId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::HirId { + owner, + local_id, + } = *self; + + hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); + +// The following implementations of HashStable for ItemId, TraitItemId, and +// ImplItemId deserve special attention. Normally we do not hash NodeIds within +// the HIR, since they just signify a HIR nodes own path. But ItemId et al +// are used when another item in the HIR is *referenced* and we certainly +// want to pick up on a reference changing its target, so we hash the NodeIds +// in "DefPath Mode". + +impl<'a, 'tcx> HashStable> for hir::ItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ItemId { + id + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::ImplItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(struct hir::Lifetime { + id, + span, + name +}); + +impl_stable_hash_for!(struct hir::LifetimeDef { + lifetime, + bounds, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Path { + span, + def, + segments +}); + +impl_stable_hash_for!(struct hir::PathSegment { + name, + parameters +}); + +impl_stable_hash_for!(enum hir::PathParameters { + AngleBracketedParameters(data), + ParenthesizedParameters(data) +}); + +impl_stable_hash_for!(struct hir::AngleBracketedParameterData { + lifetimes, + types, + infer_types, + bindings +}); + +impl_stable_hash_for!(struct hir::ParenthesizedParameterData { + span, + inputs, + output +}); + +impl_stable_hash_for!(enum hir::TyParamBound { + TraitTyParamBound(poly_trait_ref, trait_bound_modifier), + RegionTyParamBound(lifetime) +}); + +impl_stable_hash_for!(enum hir::TraitBoundModifier { + None, + Maybe +}); + +impl_stable_hash_for!(struct hir::TyParam { + name, + id, + bounds, + default, + span, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Generics { + lifetimes, + ty_params, + where_clause, + span +}); + +impl_stable_hash_for!(struct hir::WhereClause { + id, + predicates +}); + +impl_stable_hash_for!(enum hir::WherePredicate { + BoundPredicate(pred), + RegionPredicate(pred), + EqPredicate(pred) +}); + +impl_stable_hash_for!(struct hir::WhereBoundPredicate { + span, + bound_lifetimes, + bounded_ty, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereRegionPredicate { + span, + lifetime, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereEqPredicate { + id, + span, + lhs_ty, + rhs_ty +}); + +impl_stable_hash_for!(struct hir::MutTy { + ty, + mutbl +}); + +impl_stable_hash_for!(struct hir::MethodSig { + unsafety, + constness, + abi, + decl, + generics +}); + +impl_stable_hash_for!(struct hir::TypeBinding { + id, + name, + ty, + span +}); + +impl<'a, 'tcx> HashStable> for hir::Ty { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::TySlice(..) | + hir::TyArray(..) | + hir::TyPtr(..) | + hir::TyRptr(..) | + hir::TyBareFn(..) | + hir::TyNever | + hir::TyTup(..) | + hir::TyTraitObject(..) | + hir::TyImplTrait(..) | + hir::TyTypeof(..) | + hir::TyInfer => { + NodeIdHashingMode::Ignore + } + hir::TyPath(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { + id, + ref node, + ref span, + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(enum hir::PrimTy { + TyInt(int_ty), + TyUint(uint_ty), + TyFloat(float_ty), + TyStr, + TyBool, + TyChar +}); + +impl_stable_hash_for!(struct hir::BareFnTy { + unsafety, + abi, + lifetimes, + decl +}); + +impl_stable_hash_for!(enum hir::Ty_ { + TySlice(t), + TyArray(t, body_id), + TyPtr(t), + TyRptr(lifetime, t), + TyBareFn(t), + TyNever, + TyTup(ts), + TyPath(qpath), + TyTraitObject(trait_refs, lifetime), + TyImplTrait(bounds), + TyTypeof(body_id), + TyInfer +}); + +impl_stable_hash_for!(struct hir::FnDecl { + inputs, + output, + variadic, + has_implicit_self +}); + +impl_stable_hash_for!(enum hir::FunctionRetTy { + DefaultReturn(span), + Return(t) +}); + +impl<'a, 'tcx> HashStable> for hir::TraitRef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitRef { + ref path, + ref_id, + } = *self; + + path.hash_stable(hcx, hasher); + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + ref_id.hash_stable(hcx, hasher); + }); + } +} + + +impl_stable_hash_for!(struct hir::PolyTraitRef { + bound_lifetimes, + trait_ref, + span +}); + +impl_stable_hash_for!(enum hir::QPath { + Resolved(t, path), + TypeRelative(t, path_segment) +}); + +impl_stable_hash_for!(struct hir::MacroDef { + name, + attrs, + id, + span, + body +}); + + +impl<'a, 'tcx> HashStable> for hir::Block { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Block { + ref stmts, + ref expr, + id, + rules, + span, + targeted_by_break, + } = *self; + + let non_item_stmts = || stmts.iter().filter(|stmt| { + match stmt.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { + // If this is a declaration of a nested item, we don't + // want to leave any trace of it in the hash value, not + // even that it exists. Otherwise changing the position + // of nested items would invalidate the containing item + // even though that does not constitute a semantic + // change. + hir::DeclItem(_) => false, + hir::DeclLocal(_) => true + } + } + hir::StmtExpr(..) | + hir::StmtSemi(..) => true + } + }); + + let count = non_item_stmts().count(); + + count.hash_stable(hcx, hasher); + + for stmt in non_item_stmts() { + stmt.hash_stable(hcx, hasher); + } + + expr.hash_stable(hcx, hasher); + id.hash_stable(hcx, hasher); + rules.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + targeted_by_break.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::Pat { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::PatKind::Wild | + hir::PatKind::Binding(..) | + hir::PatKind::Tuple(..) | + hir::PatKind::Box(..) | + hir::PatKind::Ref(..) | + hir::PatKind::Lit(..) | + hir::PatKind::Range(..) | + hir::PatKind::Slice(..) => { + NodeIdHashingMode::Ignore + } + hir::PatKind::Path(..) | + hir::PatKind::Struct(..) | + hir::PatKind::TupleStruct(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Pat { + id, + ref node, + ref span + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for_spanned!(hir::FieldPat); +impl_stable_hash_for!(struct hir::FieldPat { + name, + pat, + is_shorthand +}); + +impl_stable_hash_for!(enum hir::BindingMode { + BindByRef(mutability), + BindByValue(mutability) +}); + +impl_stable_hash_for!(enum hir::RangeEnd { + Included, + Excluded +}); + +impl_stable_hash_for!(enum hir::PatKind { + Wild, + Binding(binding_mode, var, name, sub), + Struct(path, field_pats, dotdot), + TupleStruct(path, field_pats, dotdot), + Path(path), + Tuple(field_pats, dotdot), + Box(sub), + Ref(sub, mutability), + Lit(expr), + Range(start, end, end_kind), + Slice(one, two, three) +}); + +impl_stable_hash_for!(enum hir::BinOp_ { + BiAdd, + BiSub, + BiMul, + BiDiv, + BiRem, + BiAnd, + BiOr, + BiBitXor, + BiBitAnd, + BiBitOr, + BiShl, + BiShr, + BiEq, + BiLt, + BiLe, + BiNe, + BiGe, + BiGt +}); + +impl_stable_hash_for_spanned!(hir::BinOp_); + +impl_stable_hash_for!(enum hir::UnOp { + UnDeref, + UnNot, + UnNeg +}); + +impl_stable_hash_for_spanned!(hir::Stmt_); + +impl_stable_hash_for!(struct hir::Local { + pat, + ty, + init, + id, + span, + attrs +}); + +impl_stable_hash_for_spanned!(hir::Decl_); +impl_stable_hash_for!(enum hir::Decl_ { + DeclLocal(local), + DeclItem(item_id) +}); + +impl_stable_hash_for!(struct hir::Arm { + attrs, + pats, + guard, + body +}); + +impl_stable_hash_for!(struct hir::Field { + name, + expr, + span, + is_shorthand +}); + +impl_stable_hash_for_spanned!(ast::Name); + + +impl_stable_hash_for!(enum hir::BlockCheckMode { + DefaultBlock, + UnsafeBlock(src), + PushUnsafeBlock(src), + PopUnsafeBlock(src) +}); + +impl_stable_hash_for!(enum hir::UnsafeSource { + CompilerGenerated, + UserProvided +}); + +impl<'a, 'tcx> HashStable> for hir::Expr { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { + id, + ref span, + ref node, + ref attrs + } = *self; + + let (spans_always_on, node_id_hashing_mode) = match *node { + hir::ExprBox(..) | + hir::ExprArray(..) | + hir::ExprCall(..) | + hir::ExprLit(..) | + hir::ExprCast(..) | + hir::ExprType(..) | + hir::ExprIf(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprAssign(..) | + hir::ExprTupField(..) | + hir::ExprAddrOf(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprInlineAsm(..) | + hir::ExprRepeat(..) | + hir::ExprTup(..) => { + // For these we only hash the span when debuginfo is on. + (false, NodeIdHashingMode::Ignore) + } + // For the following, spans might be significant because of + // panic messages indicating the source location. + hir::ExprBinary(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprUnary(op, _) => { + (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore) + } + hir::ExprAssignOp(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprIndex(..) => { + (true, NodeIdHashingMode::Ignore) + } + // For these we don't care about the span, but want to hash the + // trait in scope + hir::ExprMethodCall(..) | + hir::ExprPath(..) | + hir::ExprStruct(..) | + hir::ExprField(..) => { + (false, NodeIdHashingMode::HashTraitsInScope) + } + }; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + + if spans_always_on { + hcx.while_hashing_spans(true, |hcx| { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + }); + } else { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + } + }) + } +} + +impl_stable_hash_for!(enum hir::Expr_ { + ExprBox(sub), + ExprArray(subs), + ExprCall(callee, args), + ExprMethodCall(name, ts, args), + ExprTup(fields), + ExprBinary(op, lhs, rhs), + ExprUnary(op, operand), + ExprLit(value), + ExprCast(expr, t), + ExprType(expr, t), + ExprIf(cond, then, els), + ExprWhile(cond, body, label), + ExprLoop(body, label, loop_src), + ExprMatch(matchee, arms, match_src), + ExprClosure(capture_clause, decl, body_id, span), + ExprBlock(blk), + ExprAssign(lhs, rhs), + ExprAssignOp(op, lhs, rhs), + ExprField(owner, field_name), + ExprTupField(owner, idx), + ExprIndex(lhs, rhs), + ExprPath(path), + ExprAddrOf(mutability, sub), + ExprBreak(destination, sub), + ExprAgain(destination), + ExprRet(val), + ExprInlineAsm(asm, inputs, outputs), + ExprStruct(path, fields, base), + ExprRepeat(val, times) +}); + +impl_stable_hash_for!(enum hir::LoopSource { + Loop, + WhileLet, + ForLoop +}); + +impl<'a, 'tcx> HashStable> for hir::MatchSource { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use hir::MatchSource; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + MatchSource::Normal | + MatchSource::WhileLetDesugar | + MatchSource::ForLoopDesugar | + MatchSource::TryDesugar => { + // No fields to hash. + } + MatchSource::IfLetDesugar { contains_else_clause } => { + contains_else_clause.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::CaptureClause { + CaptureByValue, + CaptureByRef +}); + +impl_stable_hash_for_spanned!(usize); + +impl_stable_hash_for!(struct hir::Destination { + ident, + target_id +}); + +impl_stable_hash_for_spanned!(ast::Ident); + +impl_stable_hash_for!(enum hir::LoopIdResult { + Ok(node_id), + Err(loop_id_error) +}); + +impl_stable_hash_for!(enum hir::LoopIdError { + OutsideLoopScope, + UnlabeledCfInWhileCondition, + UnresolvedLabel +}); + +impl_stable_hash_for!(enum hir::ScopeTarget { + Block(node_id), + Loop(loop_id_result) +}); + +impl<'a, 'tcx> HashStable> for ast::Ident { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ast::Ident { + ref name, + ctxt: _ // Ignore this + } = *self; + + name.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItem { + id, + name, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::TraitMethod { + Required(name), + Provided(body) +}); + +impl_stable_hash_for!(enum hir::TraitItemKind { + Const(t, body), + Method(sig, method), + Type(bounds, rhs) +}); + +impl<'a, 'tcx> HashStable> for hir::ImplItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItem { + id, + name, + ref vis, + defaultness, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + defaultness.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::ImplItemKind { + Const(t, body), + Method(sig, body), + Type(t) +}); + +impl<'a, 'tcx> HashStable> for hir::Visibility { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Visibility::Public | + hir::Visibility::Crate | + hir::Visibility::Inherited => { + // No fields to hash. + } + hir::Visibility::Restricted { ref path, id } => { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + id.hash_stable(hcx, hasher); + }); + path.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for hir::Defaultness { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Defaultness::Final => { + // No fields to hash. + } + hir::Defaultness::Default { has_value } => { + has_value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::ImplPolarity { + Positive, + Negative +}); + +impl<'a, 'tcx> HashStable> for hir::Mod { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Mod { + inner, + // We are not hashing the IDs of the items contained in the module. + // This is harmless and matches the current behavior but it's not + // actually correct. See issue #40876. + item_ids: _, + } = *self; + + inner.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::ForeignMod { + abi, + items +}); + +impl_stable_hash_for!(struct hir::EnumDef { + variants +}); + +impl_stable_hash_for!(struct hir::Variant_ { + name, + attrs, + data, + disr_expr +}); + +impl_stable_hash_for_spanned!(hir::Variant_); + +impl_stable_hash_for!(enum hir::UseKind { + Single, + Glob, + ListStem +}); + +impl_stable_hash_for!(struct hir::StructField { + span, + name, + vis, + id, + ty, + attrs +}); + +impl_stable_hash_for!(enum hir::VariantData { + Struct(fields, id), + Tuple(fields, id), + Unit(id) +}); + +impl<'a, 'tcx> HashStable> for hir::Item { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::ItemExternCrate(..) | + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemMod(..) | + hir::ItemForeignMod(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemTrait(..) | + hir::ItemDefaultImpl(..) | + hir::ItemImpl(..) => { + NodeIdHashingMode::Ignore + } + hir::ItemUse(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Item { + name, + ref attrs, + id, + ref node, + ref vis, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::Item_ { + ItemExternCrate(name), + ItemUse(path, use_kind), + ItemStatic(ty, mutability, body_id), + ItemConst(ty, body_id), + ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), + ItemMod(module), + ItemForeignMod(foreign_mod), + ItemTy(ty, generics), + ItemEnum(enum_def, generics), + ItemStruct(variant_data, generics), + ItemUnion(variant_data, generics), + ItemTrait(unsafety, generics, bounds, item_refs), + ItemDefaultImpl(unsafety, trait_ref), + ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) +}); + +impl_stable_hash_for!(struct hir::TraitItemRef { + id, + name, + kind, + span, + defaultness +}); + +impl_stable_hash_for!(struct hir::ImplItemRef { + id, + name, + kind, + span, + vis, + defaultness +}); + +impl<'a, 'tcx> HashStable> for hir::AssociatedItemKind { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Type => { + // No fields to hash. + } + hir::AssociatedItemKind::Method { has_self } => { + has_self.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct hir::ForeignItem { + name, + attrs, + node, + id, + span, + vis +}); + +impl_stable_hash_for!(enum hir::ForeignItem_ { + ForeignItemFn(fn_decl, arg_names, generics), + ForeignItemStatic(ty, is_mutbl) +}); + +impl_stable_hash_for!(enum hir::Stmt_ { + StmtDecl(decl, id), + StmtExpr(expr, id), + StmtSemi(expr, id) +}); + +impl_stable_hash_for!(struct hir::Arg { + pat, + id +}); + +impl_stable_hash_for!(struct hir::Body { + arguments, + value +}); + +impl<'a, 'tcx> HashStable> for hir::BodyId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + if hcx.hash_bodies() { + hcx.tcx().hir.body(*self).hash_stable(hcx, hasher); + } + } +} + +impl_stable_hash_for!(struct hir::InlineAsmOutput { + constraint, + is_rw, + is_indirect +}); + +impl<'a, 'tcx> HashStable> for hir::InlineAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::InlineAsm { + asm, + asm_str_style, + ref outputs, + ref inputs, + ref clobbers, + volatile, + alignstack, + dialect, + ctxt: _, // This is used for error reporting + } = *self; + + asm.hash_stable(hcx, hasher); + asm_str_style.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + clobbers.hash_stable(hcx, hasher); + volatile.hash_stable(hcx, hasher); + alignstack.hash_stable(hcx, hasher); + dialect.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum hir::def::CtorKind { + Fn, + Const, + Fictive +}); + +impl_stable_hash_for!(enum hir::def::Def { + Mod(def_id), + Struct(def_id), + Union(def_id), + Enum(def_id), + Variant(def_id), + Trait(def_id), + TyAlias(def_id), + AssociatedTy(def_id), + PrimTy(prim_ty), + TyParam(def_id), + SelfTy(trait_def_id, impl_def_id), + Fn(def_id), + Const(def_id), + Static(def_id, is_mutbl), + StructCtor(def_id, ctor_kind), + VariantCtor(def_id, ctor_kind), + Method(def_id), + AssociatedConst(def_id), + Local(def_id), + Upvar(def_id, index, expr_id), + Label(node_id), + Macro(def_id, macro_kind), + Err +}); + +impl_stable_hash_for!(enum hir::Mutability { + MutMutable, + MutImmutable +}); + + +impl_stable_hash_for!(enum hir::Unsafety { + Unsafe, + Normal +}); + + +impl_stable_hash_for!(enum hir::Constness { + Const, + NotConst +}); + +impl<'a, 'tcx> HashStable> for hir::def_id::DefIndex { + + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + DefId::local(*self).hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::def::Export { + name, + def, + span +}); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs new file mode 100644 index 0000000000000..401f7e1921ab4 --- /dev/null +++ b/src/librustc/ich/impls_mir.rs @@ -0,0 +1,407 @@ +// Copyright 2017 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 module contains `HashStable` implementations for various MIR data +//! types in no particular order. + +use ich::StableHashingContext; +use mir; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + + +impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); +impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); +impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); +impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); +impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); +impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::Local { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::BasicBlock { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Field { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::VisibilityScope { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Promoted { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::TerminatorKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::TerminatorKind::Goto { ref target } => { + target.hash_stable(hcx, hasher); + } + mir::TerminatorKind::SwitchInt { ref discr, + switch_ty, + ref values, + ref targets } => { + discr.hash_stable(hcx, hasher); + switch_ty.hash_stable(hcx, hasher); + values.hash_stable(hcx, hasher); + targets.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Drop { ref location, target, unwind } => { + location.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::DropAndReplace { ref location, + ref value, + target, + unwind, } => { + location.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Call { ref func, + ref args, + ref destination, + cleanup } => { + func.hash_stable(hcx, hasher); + args.hash_stable(hcx, hasher); + destination.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Assert { ref cond, + expected, + ref msg, + target, + cleanup } => { + cond.hash_stable(hcx, hasher); + expected.hash_stable(hcx, hasher); + msg.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::AssertMessage<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::AssertMessage::BoundsCheck { ref len, ref index } => { + len.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + } + mir::AssertMessage::Math(ref const_math_err) => { + const_math_err.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::StatementKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { + lvalue.hash_stable(hcx, hasher); + rvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => { + lvalue.hash_stable(hcx, hasher); + variant_index.hash_stable(hcx, hasher); + } + mir::StatementKind::StorageLive(ref lvalue) | + mir::StatementKind::StorageDead(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::Nop => {} + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + asm.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Lvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Lvalue::Local(ref local) => { + local.hash_stable(hcx, hasher); + } + mir::Lvalue::Static(ref statik) => { + statik.hash_stable(hcx, hasher); + } + mir::Lvalue::Projection(ref lvalue_projection) => { + lvalue_projection.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx, B, V> HashStable> for mir::Projection<'tcx, B, V> + where B: HashStable>, + V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let mir::Projection { + ref base, + ref elem, + } = *self; + + base.hash_stable(hcx, hasher); + elem.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, V> HashStable> for mir::ProjectionElem<'tcx, V> + where V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::ProjectionElem::Deref => {} + mir::ProjectionElem::Field(field, ty) => { + field.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Index(ref value) => { + value.hash_stable(hcx, hasher); + } + mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + offset.hash_stable(hcx, hasher); + min_length.hash_stable(hcx, hasher); + from_end.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Subslice { from, to } => { + from.hash_stable(hcx, hasher); + to.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Downcast(adt_def, variant) => { + adt_def.hash_stable(hcx, hasher); + variant.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); + +impl<'a, 'tcx> HashStable> for mir::Operand<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Operand::Consume(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Operand::Constant(ref constant) => { + constant.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Rvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Rvalue::Use(ref operand) => { + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Repeat(ref operand, ref val) => { + operand.hash_stable(hcx, hasher); + val.hash_stable(hcx, hasher); + } + mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => { + region.hash_stable(hcx, hasher); + borrow_kind.hash_stable(hcx, hasher); + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Len(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Cast(cast_kind, ref operand, ty) => { + cast_kind.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) | + mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => { + op.hash_stable(hcx, hasher); + operand1.hash_stable(hcx, hasher); + operand2.hash_stable(hcx, hasher); + } + mir::Rvalue::UnaryOp(op, ref operand) => { + op.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Discriminant(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Box(ty) => { + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::Aggregate(ref kind, ref operands) => { + kind.hash_stable(hcx, hasher); + operands.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::CastKind { + Misc, + ReifyFnPointer, + ClosureFnPointer, + UnsafeFnPointer, + Unsize +}); + +impl<'a, 'tcx> HashStable> for mir::AggregateKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::AggregateKind::Tuple => {} + mir::AggregateKind::Array(t) => { + t.hash_stable(hcx, hasher); + } + mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => { + adt_def.hash_stable(hcx, hasher); + idx.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + active_field.hash_stable(hcx, hasher); + } + mir::AggregateKind::Closure(def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::BinOp { + Add, + Sub, + Mul, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt +}); + +impl_stable_hash_for!(enum mir::UnOp { + Not, + Neg +}); + + +impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); + +impl<'a, 'tcx> HashStable> for mir::Literal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Literal::Item { def_id, substs } => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + mir::Literal::Value { ref value } => { + value.hash_stable(hcx, hasher); + } + mir::Literal::Promoted { index } => { + index.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Location { block, statement_index }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs new file mode 100644 index 0000000000000..26734500001f6 --- /dev/null +++ b/src/librustc/ich/impls_syntax.rs @@ -0,0 +1,301 @@ +// Copyright 2017 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 module contains `HashStable` implementations for various data types +//! from libsyntax in no particular order. + +use ich::StableHashingContext; + +use std::hash as std_hash; +use std::mem; + +use syntax::ast; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +impl<'a, 'tcx> HashStable> for ::syntax::symbol::InternedString { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ast::Name { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_str().hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { + Att, + Intel +}); + +impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { + Bang, + Attr, + Derive +}); + + +impl_stable_hash_for!(enum ::syntax::abi::Abi { + Cdecl, + Stdcall, + Fastcall, + Vectorcall, + Aapcs, + Win64, + SysV64, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + Rust, + C, + System, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted +}); + +impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note }); +impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr }); + +impl<'a, 'tcx> HashStable> for ::syntax::attr::StabilityLevel { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + reason.hash_stable(hcx, hasher); + issue.hash_stable(hcx, hasher); + } + ::syntax::attr::StabilityLevel::Stable { ref since } => { + since.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason }); + + +impl_stable_hash_for!(enum ::syntax::attr::IntType { + SignedInt(int_ty), + UnsignedInt(uint_ty) +}); + +impl_stable_hash_for!(enum ::syntax::ast::LitIntType { + Signed(int_ty), + Unsigned(int_ty), + Unsuffixed +}); + +impl_stable_hash_for_spanned!(::syntax::ast::LitKind); +impl_stable_hash_for!(enum ::syntax::ast::LitKind { + Str(value, style), + ByteStr(value), + Byte(value), + Char(value), + Int(value, lit_int_type), + Float(value, float_ty), + FloatUnsuffixed(value), + Bool(value) +}); + +impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 }); +impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 }); +impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); +impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); +impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); +impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); +impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name }); +impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); +impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); + +impl<'a, 'tcx> HashStable> for [ast::Attribute] { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Some attributes are always ignored during hashing. + let filtered: AccumulateVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_sugared_doc && + attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'a, 'tcx> HashStable> for ast::Attribute { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); + debug_assert!(!self.is_sugared_doc); + + let ast::Attribute { + id: _, + style, + ref path, + ref tokens, + is_sugared_doc: _, + span, + } = *self; + + style.hash_stable(hcx, hasher); + path.segments.len().hash_stable(hcx, hasher); + for segment in &path.segments { + segment.identifier.name.hash_stable(hcx, hasher); + } + for tt in tokens.trees() { + tt.hash_stable(hcx, hasher); + } + span.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenTree { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + tokenstream::TokenTree::Token(span, ref token) => { + span.hash_stable(hcx, hasher); + hash_token(token, hcx, hasher, span); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + span.hash_stable(hcx, hasher); + std_hash::Hash::hash(&delimited.delim, hasher); + for sub_tt in delimited.stream().trees() { + sub_tt.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenStream { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + for sub_tt in self.trees() { + sub_tt.hash_stable(hcx, hasher); + } + } +} + +fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + error_reporting_span: Span) { + mem::discriminant(token).hash_stable(hcx, hasher); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => { + std_hash::Hash::hash(&bin_op_token, hasher); + } + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => { + std_hash::Hash::hash(&delim_token, hasher); + } + token::Token::Literal(ref lit, ref opt_name) => { + mem::discriminant(lit).hash_stable(hcx, hasher); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.hash_stable(hcx, hasher); + n.hash_stable(hcx, hasher); + } + }; + opt_name.hash_stable(hcx, hasher); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher), + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]); + } + + std_hash::Hash::hash(non_terminal, hasher); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.hash_stable(hcx, hasher), + } +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs new file mode 100644 index 0000000000000..7b6f3af2a11ec --- /dev/null +++ b/src/librustc/ich/impls_ty.rs @@ -0,0 +1,415 @@ +// Copyright 2017 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 module contains `HashStable` implementations for various data types +//! from rustc::ty in no particular order. + +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::hash as std_hash; +use std::mem; +use ty; + + +impl<'a, 'tcx> HashStable> for ty::Ty<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let type_hash = hcx.tcx().type_id_hash(*self); + type_hash.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); + +impl<'a, 'tcx, T> HashStable> for ty::Slice + where T: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + (&**self).hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_type().hash_stable(hcx, hasher); + self.as_region().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::Region { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ReErased | + ty::ReStatic | + ty::ReEmpty => { + // No variant fields to hash for these ... + } + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.depth.hash_stable(hcx, hasher); + i.hash_stable(hcx, hasher); + } + ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { + index.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + bug!("TypeIdHasher: unexpected region {:?}", *self) + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::AutoBorrow<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::AutoBorrow::Ref(ref region, mutability) => { + region.hash_stable(hcx, hasher); + mutability.hash_stable(hcx, hasher); + } + ty::adjustment::AutoBorrow::RawPtr(mutability) => { + mutability.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::Adjust<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => {} + ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + autoderefs.hash_stable(hcx, hasher); + autoref.hash_stable(hcx, hasher); + unsize.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); +impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); +impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); + +impl_stable_hash_for!(enum ty::BorrowKind { + ImmBorrow, + UniqueImmBorrow, + MutBorrow +}); + + +impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(ref up_var_borrow) => { + up_var_borrow.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::FnSig<'tcx> { + inputs_and_output, + variadic, + unsafety, + abi +}); + +impl<'a, 'tcx, T> HashStable> for ty::Binder + where T: HashStable> + ty::fold::TypeFoldable<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce }); + +impl_stable_hash_for!(enum ty::Visibility { + Public, + Restricted(def_id), + Invisible +}); + +impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); +impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); + +impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate + where A: HashStable>, + B: HashStable>, +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::OutlivesPredicate(ref a, ref b) = *self; + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }); +impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name }); + + +impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::Predicate::Trait(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Equate(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::RegionOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::TypeOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Projection(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::WellFormed(ty) => { + ty.hash_stable(hcx, hasher); + } + ty::Predicate::ObjectSafe(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ty::Predicate::ClosureKind(def_id, closure_kind) => { + def_id.hash_stable(hcx, hasher); + closure_kind.hash_stable(hcx, hasher); + } + } + } +} + + +impl<'a, 'tcx> HashStable> for ty::AdtFlags { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + std_hash::Hash::hash(self, hasher); + } +} + +impl_stable_hash_for!(struct ty::VariantDef { + did, + name, + discr, + fields, + ctor_kind +}); + +impl_stable_hash_for!(enum ty::VariantDiscr { + Explicit(def_id), + Relative(distance) +}); + +impl_stable_hash_for!(struct ty::FieldDef { + did, + name, + vis +}); + +impl<'a, 'tcx> HashStable> +for ::middle::const_val::ConstVal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::const_val::ConstVal; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ConstVal::Float(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Integral(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Str(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::ByteStr(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Bool(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Function(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + ConstVal::Struct(ref _name_value_map) => { + // BTreeMap>), + panic!("Ordering still unstable") + } + ConstVal::Tuple(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Array(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Repeat(ref value, times) => { + value.hash_stable(hcx, hasher); + times.hash_stable(hcx, hasher); + } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); + + +impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { + parent, + predicates +}); + +impl_stable_hash_for!(enum ty::Variance { + Covariant, + Invariant, + Contravariant, + Bivariant +}); + +impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { + Struct(index) +}); + +impl<'a, 'tcx> HashStable> for ty::Generics { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::Generics { + parent, + parent_regions, + parent_types, + ref regions, + ref types, + + // Reverse map to each `TypeParameterDef`'s `index` field, from + // `def_id.index` (`def_id.krate` is the same as the item's). + type_param_to_index: _, // Don't hash this + has_self, + } = *self; + + parent.hash_stable(hcx, hasher); + parent_regions.hash_stable(hcx, hasher); + parent_types.hash_stable(hcx, hasher); + regions.hash_stable(hcx, hasher); + types.hash_stable(hcx, hasher); + has_self.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::RegionParameterDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::RegionParameterDef { + name, + def_id, + index, + issue_32330: _, + pure_wrt_drop + } = *self; + + name.hash_stable(hcx, hasher); + def_id.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + pure_wrt_drop.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::TypeParameterDef { + name, + def_id, + index, + has_default, + object_lifetime_default, + pure_wrt_drop +}); + + +impl<'a, 'tcx, T> HashStable> +for ::middle::resolve_lifetime::Set1 + where T: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::resolve_lifetime::Set1; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Set1::Empty | + Set1::Many => { + // Nothing to do. + } + Set1::One(ref value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { + Static, + EarlyBound(index, decl), + LateBound(db_index, decl), + LateBoundAnon(db_index, anon_index), + Free(call_site_scope_data, decl) +}); + +impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { + fn_id, + body_id +}); + +impl_stable_hash_for!(struct ty::DebruijnIndex { + depth +}); diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 209953f3c686b..f0601a0efabf8 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -8,13 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! ICH - Incremental Compilation Hash + pub use self::fingerprint::Fingerprint; pub use self::def_path_hash::DefPathHashes; pub use self::caching_codemap_view::CachingCodemapView; +pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; mod fingerprint; mod def_path_hash; mod caching_codemap_view; +mod hcx; + +mod impls_const_math; +mod impls_hir; +mod impls_mir; +mod impls_ty; +mod impls_syntax; pub const ATTR_DIRTY: &'static str = "rustc_dirty"; pub const ATTR_CLEAN: &'static str = "rustc_clean"; @@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean"; pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; +pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused"; +pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; + + +pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ + ATTR_IF_THIS_CHANGED, + ATTR_THEN_THIS_WOULD_NEED, + ATTR_DIRTY, + ATTR_CLEAN, + ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, +]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ "cfg", @@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, - ATTR_CLEAN_METADATA + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, ]; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 294f80d7d2301..3b002fd4dfc1a 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -41,6 +41,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(discriminant_value)] extern crate arena; extern crate core; diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b649..c18e585f79553 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + macro_rules! enum_from_u32 { ($(#[$attr:meta])* pub enum $name:ident { $($variant:ident = $e:expr,)* @@ -59,3 +61,80 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! __impl_stable_hash_field { + (DECL IGNORED) => (_); + (DECL $name:ident) => (ref $name); + (USE IGNORED $ctx:expr, $hasher:expr) => ({}); + (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher)); +} + +#[macro_export] +macro_rules! impl_stable_hash_for { + (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + use $enum_name::*; + ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); + + match *self { + $( + $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => { + $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)* + } + )* + } + } + } + }; + (struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; + (tuple_struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name ( + $(ref $field),* + ) = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; +} + +#[macro_export] +macro_rules! impl_stable_hash_for_spanned { + ($T:path) => ( + + impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.node.hash_stable(hcx, hasher); + self.span.hash_stable(hcx, hasher); + } + } + ); +} + diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index bc9bbebb1796a..799686ceca4a0 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -10,7 +10,9 @@ use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; - +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use ich::StableHashingContext; use mir::{Mir, BasicBlock}; use rustc_serialize as serialize; @@ -33,6 +35,13 @@ impl serialize::Decodable for Cache { } } +impl<'a, 'tcx> HashStable> for Cache { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHasher) { + // do nothing + } +} impl Cache { pub fn new() -> Self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 01dc7f51e29d9..aea4684e526ce 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> { } } +impl_stable_hash_for!(struct Mir<'tcx> { + basic_blocks, + visibility_scopes, + promoted, + return_ty, + local_decls, + arg_count, + upvar_decls, + spread_arg, + span, + cache +}); + impl<'tcx> Index for Mir<'tcx> { type Output = BasicBlockData<'tcx>; @@ -830,6 +843,11 @@ pub struct Static<'tcx> { pub ty: Ty<'tcx>, } +impl_stable_hash_for!(struct Static<'tcx> { + def_id, + ty +}); + /// The `Projection` data structure defines things of the form `B.x` /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6a4e7db21dd12..3c529a6982042 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,6 +19,7 @@ use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use ich::StableHashingContext; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; @@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} + +impl<'a, 'tcx> HashStable> for AdtDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::AdtDef { + did, + ref variants, + ref flags, + ref repr, + } = *self; + + did.hash_stable(hcx, hasher); + variants.hash_stable(hcx, hasher); + flags.hash_stable(hcx, hasher); + repr.hash_stable(hcx, hasher); + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } @@ -1391,6 +1413,13 @@ pub struct ReprOptions { pub int: Option, } +impl_stable_hash_for!(struct ReprOptions { + c, + packed, + simd, + int +}); + impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut ret = ReprOptions::default(); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 9ccd95dd8d805..c1735b4a4ec9a 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -37,6 +37,8 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(conservative_impl_trait)] +#![feature(discriminant_value)] +#![feature(specialization)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 231c01c9ab78d..dc412a0763ef7 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::Hasher; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use blake2b::Blake2bHasher; @@ -174,3 +174,193 @@ impl Hasher for StableHasher { self.write_ileb128(i as i64); } } + + +/// Something that implements `HashStable` can be hashed in a way that is +/// stable across multiple compiliation sessions. +pub trait HashStable { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher); +} + +// Implement HashStable by just calling `Hash::hash()`. This works fine for +// self-contained values that don't depend on the hashing context `CTX`. +macro_rules! impl_stable_hash_via_hash { + ($t:ty) => ( + impl HashStable for $t { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } + } + ); +} + +impl_stable_hash_via_hash!(i8); +impl_stable_hash_via_hash!(i16); +impl_stable_hash_via_hash!(i32); +impl_stable_hash_via_hash!(i64); +impl_stable_hash_via_hash!(isize); + +impl_stable_hash_via_hash!(u8); +impl_stable_hash_via_hash!(u16); +impl_stable_hash_via_hash!(u32); +impl_stable_hash_via_hash!(u64); +impl_stable_hash_via_hash!(usize); + +impl_stable_hash_via_hash!(u128); +impl_stable_hash_via_hash!(i128); + +impl_stable_hash_via_hash!(char); +impl_stable_hash_via_hash!(()); + +impl HashStable for f32 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u32 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl HashStable for f64 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u64 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl, T2: HashStable, CTX> HashStable for (T1, T2) { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.0.hash_stable(ctx, hasher); + self.1.hash_stable(ctx, hasher); + } +} + +impl, CTX> HashStable for [T] { + default fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for item in self { + item.hash_stable(ctx, hasher); + } + } +} + +impl, CTX> HashStable for Vec { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(ctx, hasher); + } +} + +impl HashStable for str { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash(hasher); + self.as_bytes().hash(hasher); + } +} + +impl HashStable for bool { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); + } +} + + +impl HashStable for Option + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + if let Some(ref value) = *self { + 1u8.hash_stable(ctx, hasher); + value.hash_stable(ctx, hasher); + } else { + 0u8.hash_stable(ctx, hasher); + } + } +} + +impl<'a, T, CTX> HashStable for &'a T + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(ctx, hasher); + } +} + +impl HashStable for ::std::mem::Discriminant { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } +} + +impl HashStable for ::std::collections::BTreeMap + where K: Ord + HashStable, + V: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for (k, v) in self { + k.hash_stable(ctx, hasher); + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::std::collections::BTreeSet + where T: Ord + HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in self { + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::indexed_vec::IndexVec + where T: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c9496a4deb8eb..c80a5a1627797 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -27,24 +27,17 @@ //! at the end of compilation would be different from those computed //! at the beginning. -use syntax::ast; use std::cell::RefCell; use std::hash::Hash; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::intravisit as visit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ich::{Fingerprint, StableHashingContext}; use rustc::ty::TyCtxt; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; -use rustc::session::config::DebugInfoLevel::NoDebugInfo; - -use self::svh_visitor::StrictVersionHashVisitor; - -mod svh_visitor; pub type IchHasher = StableHasher; @@ -94,91 +87,42 @@ impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { } } - -pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> IncrementalHashesMap { - let _ignore = tcx.dep_graph.in_ignore(); - let krate = tcx.hir.krate(); - let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo; - let mut visitor = HashItemsVisitor { - tcx: tcx, - hashes: IncrementalHashesMap::new(), - def_path_hashes: DefPathHashes::new(tcx), - codemap: CachingCodemapView::new(tcx), - hash_spans: hash_spans, - }; - record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| { - v.hash_crate_root_module(krate); - }); - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); - - for macro_def in krate.exported_macros.iter() { - visitor.calculate_node_id(macro_def.id, - |v| v.visit_macro_def(macro_def)); - } - }); - - tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); - - record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); - visitor.hashes -} - -struct HashItemsVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefPathHashes<'a, 'tcx>, - codemap: CachingCodemapView<'tcx>, +struct ComputeItemHashesVisitor<'a, 'tcx: 'a> { + hcx: StableHashingContext<'a, 'tcx>, hashes: IncrementalHashesMap, - hash_spans: bool, } -impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { - fn calculate_node_id(&mut self, id: ast::NodeId, walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let def_id = self.tcx.hir.local_def_id(id); - self.calculate_def_id(def_id, walk_op) - } - - fn calculate_def_id(&mut self, def_id: DefId, mut walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) +impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { + fn compute_and_store_ich_for_item_like(&mut self, + dep_node: DepNode, + hash_bodies: bool, + item_like: T) + where T: HashStable> { - assert!(def_id.is_local()); - debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); - self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op); - self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op); - } + let mut hasher = IchHasher::new(); + self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| { + item_like.hash_stable(hcx, &mut hasher); + }); - fn calculate_def_hash(&mut self, - dep_node: DepNode, - hash_bodies: bool, - walk_op: &mut W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let mut state = IchHasher::new(); - walk_op(&mut StrictVersionHashVisitor::new(&mut state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - hash_bodies)); - let bytes_hashed = state.bytes_hashed(); - let item_hash = state.finish(); + let bytes_hashed = hasher.bytes_hashed(); + let item_hash = hasher.finish(); debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash); self.hashes.insert(dep_node, item_hash); - let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + + let tcx = self.hcx.tcx(); + let bytes_hashed = + tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + bytes_hashed; - self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); + tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); } fn compute_crate_hash(&mut self) { - let krate = self.tcx.hir.krate(); + let tcx = self.hcx.tcx(); + let krate = tcx.hir.krate(); let mut crate_state = IchHasher::new(); - let crate_disambiguator = self.tcx.sess.local_crate_disambiguator(); + let crate_disambiguator = tcx.sess.local_crate_disambiguator(); "crate_disambiguator".hash(&mut crate_state); crate_disambiguator.as_str().len().hash(&mut crate_state); crate_disambiguator.as_str().hash(&mut crate_state); @@ -186,7 +130,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // add each item (in some deterministic order) to the overall // crate hash. { - let def_path_hashes = &mut self.def_path_hashes; + let hcx = &mut self.hcx; let mut item_hashes: Vec<_> = self.hashes.iter() .map(|(item_dep_node, &item_hash)| { @@ -194,7 +138,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // DepNode where the u64 is the // hash of the def-id's def-path: let item_dep_node = - item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did))) + item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did))) .unwrap(); (item_dep_node, item_hash) }) @@ -203,40 +147,85 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { item_hashes.hash(&mut crate_state); } - { - let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - false); - visitor.hash_attributes(&krate.attrs); - } + krate.attrs.hash_stable(&mut self.hcx, &mut crate_state); let crate_hash = crate_state.finish(); self.hashes.insert(DepNode::Krate, crate_hash); debug!("calculate_crate_hash: crate_hash={:?}", crate_hash); } -} - -impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None + fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) { + let hir::Crate { + ref module, + // Crate attributes are not copied over to the root `Mod`, so hash + // them explicitly here. + ref attrs, + span, + + // These fields are handled separately: + exported_macros: _, + items: _, + trait_items: _, + impl_items: _, + bodies: _, + trait_impls: _, + trait_default_impl: _, + body_ids: _, + } = *krate; + + let def_id = DefId::local(CRATE_DEF_INDEX); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), + false, + (module, (span, attrs))); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), + true, + (module, (span, attrs))); } +} +impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - self.calculate_node_id(item.id, |v| v.visit_item(item)); - visit::walk_item(self, item); + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item)); - visit::walk_trait_item(self, trait_item); + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item)); - visit::walk_impl_item(self, impl_item); + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } } + +pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> IncrementalHashesMap { + let _ignore = tcx.dep_graph.in_ignore(); + let krate = tcx.hir.krate(); + + let mut visitor = ComputeItemHashesVisitor { + hcx: StableHashingContext::new(tcx), + hashes: IncrementalHashesMap::new(), + }; + + record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { + visitor.hash_crate_root_module(krate); + krate.visit_all_item_likes(&mut visitor); + + for macro_def in krate.exported_macros.iter() { + let def_id = tcx.hir.local_def_id(macro_def.id); + visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def); + visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def); + } + }); + + tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); + + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); + visitor.hashes +} diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs deleted file mode 100644 index 5401b371888e9..0000000000000 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ /dev/null @@ -1,1111 +0,0 @@ -// 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 self::SawExprComponent::*; -use self::SawAbiComponent::*; -use self::SawItemComponent::*; -use self::SawPatComponent::*; -use self::SawTyComponent::*; -use self::SawTraitOrImplItemComponent::*; -use syntax::abi::Abi; -use syntax::ast::{self, Name, NodeId}; -use syntax::attr; -use syntax::ext::hygiene::SyntaxContext; -use syntax::parse::token; -use syntax::symbol::InternedString; -use syntax_pos::{Span, BytePos}; -use syntax::tokenstream; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{self as visit, Visitor}; -use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES}; -use rustc::ty::TyCtxt; -use std::hash::{Hash, Hasher}; - -use super::IchHasher; - -pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { - pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, - pub st: &'a mut IchHasher, - // collect a deterministic hash of def-ids that we have seen - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - hash_spans: bool, - codemap: &'a mut CachingCodemapView<'tcx>, - overflow_checks_enabled: bool, - hash_bodies: bool, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - pub fn new(st: &'a mut IchHasher, - tcx: TyCtxt<'hash, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - codemap: &'a mut CachingCodemapView<'tcx>, - hash_spans: bool, - hash_bodies: bool) - -> Self { - let check_overflow = tcx.sess.overflow_checks(); - - StrictVersionHashVisitor { - st: st, - tcx: tcx, - def_path_hashes: def_path_hashes, - hash_spans: hash_spans, - codemap: codemap, - overflow_checks_enabled: check_overflow, - hash_bodies: hash_bodies, - } - } - - fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { - self.def_path_hashes.hash(def_id) - } - - // Hash a span in a stable way. We can't directly hash the span's BytePos - // fields (that would be similar to hashing pointers, since those are just - // offsets into the CodeMap). Instead, we hash the (file name, line, column) - // triple, which stays the same even if the containing FileMap has moved - // within the CodeMap. - // Also note that we are hashing byte offsets for the column, not unicode - // codepoint offsets. For the purpose of the hash that's sufficient. - // Also, hashing filenames is expensive so we avoid doing it twice when the - // span starts and ends in the same file, which is almost always the case. - fn hash_span(&mut self, span: Span) { - debug!("hash_span: st={:?}", self.st); - - // If this is not an empty or invalid span, we want to hash the last - // position that belongs to it, as opposed to hashing the first - // position past it. - let span_hi = if span.hi > span.lo { - // We might end up in the middle of a multibyte character here, - // but that's OK, since we are not trying to decode anything at - // this position. - span.hi - BytePos(1) - } else { - span.hi - }; - - let expn_kind = if span.ctxt == SyntaxContext::empty() { - SawSpanExpnKind::NoExpansion - } else { - SawSpanExpnKind::SomeExpansion - }; - - let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); - let loc1 = loc1.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) - .unwrap_or(("???", 0, BytePos(0))); - - let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); - let loc2 = loc2.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) - .unwrap_or(("???", 0, BytePos(0))); - - let saw = if loc1.0 == loc2.0 { - SawSpan(loc1.0, - loc1.1, loc1.2, - loc2.1, loc2.2, - expn_kind) - } else { - SawSpanTwoFiles(loc1.0, loc1.1, loc1.2, - loc2.0, loc2.1, loc2.2, - expn_kind) - }; - saw.hash(self.st); - - if expn_kind == SawSpanExpnKind::SomeExpansion { - self.hash_span(span.source_callsite()); - } - } - - fn hash_discriminant(&mut self, v: &T) { - unsafe { - let disr = ::std::intrinsics::discriminant_value(v); - debug!("hash_discriminant: disr={}, st={:?}", disr, self.st); - disr.hash(self.st); - } - } -} - -// To off-load the bulk of the hash-computation on #[derive(Hash)], -// we define a set of enums corresponding to the content that our -// crate visitor will encounter as it traverses the ast. -// -// The important invariant is that all of the Saw*Component enums -// do not carry any Spans, Names, or Idents. -// -// Not carrying any Names/Idents is the important fix for problem -// noted on PR #13948: using the ident.name as the basis for a -// hash leads to unstable SVH, because ident.name is just an index -// into intern table (i.e. essentially a random address), not -// computed from the name content. -// -// With the below enums, the SVH computation is not sensitive to -// artifacts of how rustc was invoked nor of how the source code -// was laid out. (Or at least it is *less* sensitive.) - -// This enum represents the different potential bits of code the -// visitor could encounter that could affect the ABI for the crate, -// and assigns each a distinct tag to feed into the hash computation. -#[derive(Hash)] -enum SawAbiComponent<'a> { - - // FIXME (#14132): should we include (some function of) - // ident.ctxt as well? - SawIdent(InternedString), - SawStructDef(InternedString), - - SawLifetime, - SawLifetimeDef(usize), - - SawMod, - SawForeignItem(SawForeignItemComponent), - SawItem(SawItemComponent), - SawTy(SawTyComponent), - SawFnDecl(bool), - SawGenerics, - SawTraitItem(SawTraitOrImplItemComponent), - SawImplItem(SawTraitOrImplItemComponent), - SawStructField, - SawVariant(bool), - SawQPath, - SawPathSegment, - SawPathParameters, - SawBlock, - SawPat(SawPatComponent), - SawLocal, - SawArm, - SawExpr(SawExprComponent<'a>), - SawStmt, - SawVis, - SawAssociatedItemKind(hir::AssociatedItemKind), - SawDefaultness(hir::Defaultness), - SawWherePredicate, - SawTyParamBound, - SawPolyTraitRef, - SawAssocTypeBinding, - SawAttribute(ast::AttrStyle), - SawMacroDef, - SawSpan(&'a str, - usize, BytePos, - usize, BytePos, - SawSpanExpnKind), - SawSpanTwoFiles(&'a str, usize, BytePos, - &'a str, usize, BytePos, - SawSpanExpnKind), -} - -/// SawExprComponent carries all of the information that we want -/// to include in the hash that *won't* be covered by the -/// subsequent recursive traversal of the expression's -/// substructure by the visitor. -/// -/// We know every Expr_ variant is covered by a variant because -/// `fn saw_expr` maps each to some case below. Ensuring that -/// each variant carries an appropriate payload has to be verified -/// by hand. -/// -/// (However, getting that *exactly* right is not so important -/// because the SVH is just a developer convenience; there is no -/// guarantee of collision-freedom, hash collisions are just -/// (hopefully) unlikely.) -/// -/// The xxxComponent enums and saw_xxx functions for Item, Pat, -/// Ty, TraitItem and ImplItem follow the same methodology. -#[derive(Hash)] -enum SawExprComponent<'a> { - - SawExprLoop(Option), - SawExprField(InternedString), - SawExprTupField(usize), - SawExprBreak(Option), - SawExprAgain(Option), - - SawExprBox, - SawExprArray, - SawExprCall, - SawExprMethodCall, - SawExprTup, - SawExprBinary(hir::BinOp_), - SawExprUnary(hir::UnOp), - SawExprLit(ast::LitKind), - SawExprLitStr(InternedString, ast::StrStyle), - SawExprLitFloat(InternedString, Option), - SawExprCast, - SawExprType, - SawExprIf, - SawExprWhile, - SawExprMatch, - SawExprClosure(CaptureClause), - SawExprBlock, - SawExprAssign, - SawExprAssignOp(hir::BinOp_), - SawExprIndex, - SawExprPath, - SawExprAddrOf(hir::Mutability), - SawExprRet, - SawExprInlineAsm(StableInlineAsm<'a>), - SawExprStruct, - SawExprRepeat, -} - -// The boolean returned indicates whether the span of this expression is always -// significant, regardless of debuginfo. -fn saw_expr<'a>(node: &'a Expr_, - overflow_checks_enabled: bool) - -> (SawExprComponent<'a>, bool) { - let binop_can_panic_at_runtime = |binop| { - match binop { - BiAdd | - BiSub | - BiMul => overflow_checks_enabled, - - BiDiv | - BiRem => true, - - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr | - BiShl | - BiShr | - BiEq | - BiLt | - BiLe | - BiNe | - BiGe | - BiGt => false - } - }; - - let unop_can_panic_at_runtime = |unop| { - match unop { - UnDeref | - UnNot => false, - UnNeg => overflow_checks_enabled, - } - }; - - match *node { - ExprBox(..) => (SawExprBox, false), - ExprArray(..) => (SawExprArray, false), - ExprCall(..) => (SawExprCall, false), - ExprMethodCall(..) => (SawExprMethodCall, false), - ExprTup(..) => (SawExprTup, false), - ExprBinary(op, ..) => { - (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprUnary(op, _) => { - (SawExprUnary(op), unop_can_panic_at_runtime(op)) - } - ExprLit(ref lit) => (saw_lit(lit), false), - ExprCast(..) => (SawExprCast, false), - ExprType(..) => (SawExprType, false), - ExprIf(..) => (SawExprIf, false), - ExprWhile(..) => (SawExprWhile, false), - ExprLoop(_, id, _) => (SawExprLoop(id.map(|id| id.node.as_str())), false), - ExprMatch(..) => (SawExprMatch, false), - ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false), - ExprBlock(..) => (SawExprBlock, false), - ExprAssign(..) => (SawExprAssign, false), - ExprAssignOp(op, ..) => { - (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprField(_, name) => (SawExprField(name.node.as_str()), false), - ExprTupField(_, id) => (SawExprTupField(id.node), false), - ExprIndex(..) => (SawExprIndex, true), - ExprPath(_) => (SawExprPath, false), - ExprAddrOf(m, _) => (SawExprAddrOf(m), false), - ExprBreak(label, _) => (SawExprBreak(label.ident.map(|i| - i.node.name.as_str())), false), - ExprAgain(label) => (SawExprAgain(label.ident.map(|i| - i.node.name.as_str())), false), - ExprRet(..) => (SawExprRet, false), - ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false), - ExprStruct(..) => (SawExprStruct, false), - ExprRepeat(..) => (SawExprRepeat, false), - } -} - -fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> { - match lit.node { - ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style), - ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)), - ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None), - ref node @ _ => SawExprLit(node.clone()), - } -} - -#[derive(Hash)] -enum SawItemComponent { - SawItemExternCrate, - SawItemUse(UseKind), - SawItemStatic(Mutability), - SawItemConst, - SawItemFn(Unsafety, Constness, Abi), - SawItemMod, - SawItemForeignMod(Abi), - SawItemTy, - SawItemEnum, - SawItemStruct, - SawItemUnion, - SawItemTrait(Unsafety), - SawItemDefaultImpl(Unsafety), - SawItemImpl(Unsafety, ImplPolarity) -} - -fn saw_item(node: &Item_) -> SawItemComponent { - match *node { - ItemExternCrate(..) => SawItemExternCrate, - ItemUse(_, kind) => SawItemUse(kind), - ItemStatic(_, mutability, _) => SawItemStatic(mutability), - ItemConst(..) =>SawItemConst, - ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), - ItemMod(..) => SawItemMod, - ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi), - ItemTy(..) => SawItemTy, - ItemEnum(..) => SawItemEnum, - ItemStruct(..) => SawItemStruct, - ItemUnion(..) => SawItemUnion, - ItemTrait(unsafety, ..) => SawItemTrait(unsafety), - ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety), - ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity) - } -} - -#[derive(Hash)] -enum SawForeignItemComponent { - Static { mutable: bool }, - Fn, -} - -#[derive(Hash)] -enum SawPatComponent { - SawPatWild, - SawPatBinding(BindingMode), - SawPatStruct, - SawPatTupleStruct, - SawPatPath, - SawPatTuple, - SawPatBox, - SawPatRef(Mutability), - SawPatLit, - SawPatRange, - SawPatSlice -} - -fn saw_pat(node: &PatKind) -> SawPatComponent { - match *node { - PatKind::Wild => SawPatWild, - PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode), - PatKind::Struct(..) => SawPatStruct, - PatKind::TupleStruct(..) => SawPatTupleStruct, - PatKind::Path(_) => SawPatPath, - PatKind::Tuple(..) => SawPatTuple, - PatKind::Box(..) => SawPatBox, - PatKind::Ref(_, mutability) => SawPatRef(mutability), - PatKind::Lit(..) => SawPatLit, - PatKind::Range(..) => SawPatRange, - PatKind::Slice(..) => SawPatSlice - } -} - -#[derive(Hash)] -enum SawTyComponent { - SawTySlice, - SawTyArray, - SawTyPtr(Mutability), - SawTyRptr(Mutability), - SawTyBareFn(Unsafety, Abi), - SawTyNever, - SawTyTup, - SawTyPath, - SawTyObjectSum, - SawTyImplTrait, - SawTyTypeof, - SawTyInfer -} - -fn saw_ty(node: &Ty_) -> SawTyComponent { - match *node { - TySlice(..) => SawTySlice, - TyArray(..) => SawTyArray, - TyPtr(ref mty) => SawTyPtr(mty.mutbl), - TyRptr(_, ref mty) => SawTyRptr(mty.mutbl), - TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi), - TyNever => SawTyNever, - TyTup(..) => SawTyTup, - TyPath(_) => SawTyPath, - TyTraitObject(..) => SawTyObjectSum, - TyImplTrait(..) => SawTyImplTrait, - TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer - } -} - -#[derive(Hash)] -enum SawTraitOrImplItemComponent { - SawTraitOrImplItemConst, - // The boolean signifies whether a body is present - SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool), - SawTraitOrImplItemType -} - -fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent { - match *ti { - TraitItemKind::Const(..) => SawTraitOrImplItemConst, - TraitItemKind::Method(ref sig, TraitMethod::Required(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false), - TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - TraitItemKind::Type(..) => SawTraitOrImplItemType - } -} - -fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { - match *ii { - ImplItemKind::Const(..) => SawTraitOrImplItemConst, - ImplItemKind::Method(ref sig, _) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - ImplItemKind::Type(..) => SawTraitOrImplItemType - } -} - -#[derive(Clone, Copy, Hash, Eq, PartialEq)] -enum SawSpanExpnKind { - NoExpansion, - SomeExpansion, -} - -/// A wrapper that provides a stable Hash implementation. -struct StableInlineAsm<'a>(&'a InlineAsm); - -impl<'a> Hash for StableInlineAsm<'a> { - fn hash(&self, state: &mut H) { - let InlineAsm { - asm, - asm_str_style, - ref outputs, - ref inputs, - ref clobbers, - volatile, - alignstack, - dialect, - ctxt: _, // This is used for error reporting - } = *self.0; - - asm.as_str().hash(state); - asm_str_style.hash(state); - outputs.len().hash(state); - for output in outputs { - let InlineAsmOutput { constraint, is_rw, is_indirect } = *output; - constraint.as_str().hash(state); - is_rw.hash(state); - is_indirect.hash(state); - } - inputs.len().hash(state); - for input in inputs { - input.as_str().hash(state); - } - clobbers.len().hash(state); - for clobber in clobbers { - clobber.as_str().hash(state); - } - volatile.hash(state); - alignstack.hash(state); - dialect.hash(state); - } -} - -macro_rules! hash_attrs { - ($visitor:expr, $attrs:expr) => ({ - let attrs = $attrs; - if attrs.len() > 0 { - $visitor.hash_attributes(attrs); - } - }) -} - -macro_rules! hash_span { - ($visitor:expr, $span:expr) => ({ - hash_span!($visitor, $span, false) - }); - ($visitor:expr, $span:expr, $force:expr) => ({ - if $force || $visitor.hash_spans { - $visitor.hash_span($span); - } - }); -} - -impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> { - if self.hash_bodies { - visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } else { - visit::NestedVisitorMap::None - } - } - - fn visit_variant_data(&mut self, - s: &'tcx VariantData, - name: Name, - _: &'tcx Generics, - _: NodeId, - span: Span) { - debug!("visit_variant_data: st={:?}", self.st); - SawStructDef(name.as_str()).hash(self.st); - hash_span!(self, span); - visit::walk_struct_def(self, s); - } - - fn visit_variant(&mut self, - v: &'tcx Variant, - g: &'tcx Generics, - item_id: NodeId) { - debug!("visit_variant: st={:?}", self.st); - SawVariant(v.node.disr_expr.is_some()).hash(self.st); - hash_attrs!(self, &v.node.attrs); - visit::walk_variant(self, v, g, item_id) - } - - fn visit_name(&mut self, span: Span, name: Name) { - debug!("visit_name: st={:?}", self.st); - SawIdent(name.as_str()).hash(self.st); - hash_span!(self, span); - } - - fn visit_lifetime(&mut self, l: &'tcx Lifetime) { - debug!("visit_lifetime: st={:?}", self.st); - SawLifetime.hash(self.st); - visit::walk_lifetime(self, l); - } - - fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { - debug!("visit_lifetime_def: st={:?}", self.st); - SawLifetimeDef(l.bounds.len()).hash(self.st); - visit::walk_lifetime_def(self, l); - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - debug!("visit_expr: st={:?}", self.st); - let (saw_expr, force_span) = saw_expr(&ex.node, - self.overflow_checks_enabled); - SawExpr(saw_expr).hash(self.st); - // No need to explicitly hash the discriminant here, since we are - // implicitly hashing the discriminant of SawExprComponent. - hash_span!(self, ex.span, force_span); - hash_attrs!(self, &ex.attrs); - - // Always hash nested constant bodies (e.g. n in `[x; n]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_expr(self, ex); - self.hash_bodies = hash_bodies; - } - - fn visit_stmt(&mut self, s: &'tcx Stmt) { - debug!("visit_stmt: st={:?}", self.st); - - // We don't want to modify the hash for decls, because - // they might be item decls (if they are local decls, - // we'll hash that fact in visit_local); but we do want to - // remember if this was a StmtExpr or StmtSemi (the later - // had an explicit semi-colon; this affects the typing - // rules). - match s.node { - StmtDecl(..) => (), - StmtExpr(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - StmtSemi(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - } - - visit::walk_stmt(self, s) - } - - fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { - debug!("visit_foreign_item: st={:?}", self.st); - - match i.node { - ForeignItemFn(..) => { - SawForeignItem(SawForeignItemComponent::Fn) - } - ForeignItemStatic(_, mutable) => { - SawForeignItem(SawForeignItemComponent::Static { - mutable: mutable - }) - } - }.hash(self.st); - - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_foreign_item(self, i) - } - - fn visit_item(&mut self, i: &'tcx Item) { - debug!("visit_item: {:?} st={:?}", i, self.st); - - self.maybe_enable_overflow_checks(&i.attrs); - - SawItem(saw_item(&i.node)).hash(self.st); - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_item(self, i) - } - - fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) { - debug!("visit_mod: st={:?}", self.st); - SawMod.hash(self.st); - hash_span!(self, span); - visit::walk_mod(self, m, n) - } - - fn visit_ty(&mut self, t: &'tcx Ty) { - debug!("visit_ty: st={:?}", self.st); - SawTy(saw_ty(&t.node)).hash(self.st); - hash_span!(self, t.span); - - // Always hash nested constant bodies (e.g. N in `[T; N]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_ty(self, t); - self.hash_bodies = hash_bodies; - } - - fn visit_generics(&mut self, g: &'tcx Generics) { - debug!("visit_generics: st={:?}", self.st); - SawGenerics.hash(self.st); - visit::walk_generics(self, g) - } - - fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) { - debug!("visit_fn_decl: st={:?}", self.st); - SawFnDecl(fd.variadic).hash(self.st); - visit::walk_fn_decl(self, fd) - } - - fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { - debug!("visit_trait_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ti.attrs); - - SawTraitItem(saw_trait_item(&ti.node)).hash(self.st); - hash_span!(self, ti.span); - hash_attrs!(self, &ti.attrs); - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { - debug!("visit_impl_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ii.attrs); - - SawImplItem(saw_impl_item(&ii.node)).hash(self.st); - hash_span!(self, ii.span); - hash_attrs!(self, &ii.attrs); - visit::walk_impl_item(self, ii) - } - - fn visit_struct_field(&mut self, s: &'tcx StructField) { - debug!("visit_struct_field: st={:?}", self.st); - SawStructField.hash(self.st); - hash_span!(self, s.span); - hash_attrs!(self, &s.attrs); - visit::walk_struct_field(self, s) - } - - fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) { - debug!("visit_qpath: st={:?}", self.st); - SawQPath.hash(self.st); - self.hash_discriminant(qpath); - visit::walk_qpath(self, qpath, id, span) - } - - fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { - debug!("visit_path: st={:?}", self.st); - hash_span!(self, path.span); - visit::walk_path(self, path) - } - - fn visit_def_mention(&mut self, def: Def) { - self.hash_def(def); - } - - fn visit_block(&mut self, b: &'tcx Block) { - debug!("visit_block: st={:?}", self.st); - SawBlock.hash(self.st); - hash_span!(self, b.span); - visit::walk_block(self, b) - } - - fn visit_pat(&mut self, p: &'tcx Pat) { - debug!("visit_pat: st={:?}", self.st); - SawPat(saw_pat(&p.node)).hash(self.st); - hash_span!(self, p.span); - visit::walk_pat(self, p) - } - - fn visit_local(&mut self, l: &'tcx Local) { - debug!("visit_local: st={:?}", self.st); - SawLocal.hash(self.st); - hash_attrs!(self, &l.attrs); - visit::walk_local(self, l) - // No need to hash span, we are hashing all component spans - } - - fn visit_arm(&mut self, a: &'tcx Arm) { - debug!("visit_arm: st={:?}", self.st); - SawArm.hash(self.st); - hash_attrs!(self, &a.attrs); - visit::walk_arm(self, a) - } - - fn visit_id(&mut self, id: NodeId) { - debug!("visit_id: id={} st={:?}", id, self.st); - self.hash_resolve(id) - } - - fn visit_vis(&mut self, v: &'tcx Visibility) { - debug!("visit_vis: st={:?}", self.st); - SawVis.hash(self.st); - self.hash_discriminant(v); - visit::walk_vis(self, v) - } - - fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawAssociatedItemKind(*kind).hash(self.st); - visit::walk_associated_item_kind(self, kind); - } - - fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawDefaultness(*defaultness).hash(self.st); - visit::walk_defaultness(self, defaultness); - } - - fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { - debug!("visit_where_predicate: st={:?}", self.st); - SawWherePredicate.hash(self.st); - self.hash_discriminant(predicate); - // Ignoring span. Any important nested components should be visited. - visit::walk_where_predicate(self, predicate) - } - - fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) { - debug!("visit_ty_param_bound: st={:?}", self.st); - SawTyParamBound.hash(self.st); - self.hash_discriminant(bounds); - // The TraitBoundModifier in TraitTyParamBound will be hash in - // visit_poly_trait_ref() - visit::walk_ty_param_bound(self, bounds) - } - - fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) { - debug!("visit_poly_trait_ref: st={:?}", self.st); - SawPolyTraitRef.hash(self.st); - m.hash(self.st); - visit::walk_poly_trait_ref(self, t, m) - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { - debug!("visit_path_segment: st={:?}", self.st); - SawPathSegment.hash(self.st); - visit::walk_path_segment(self, path_span, path_segment) - } - - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) { - debug!("visit_path_parameters: st={:?}", self.st); - SawPathParameters.hash(self.st); - self.hash_discriminant(path_parameters); - visit::walk_path_parameters(self, path_span, path_parameters) - } - - fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { - debug!("visit_assoc_type_binding: st={:?}", self.st); - SawAssocTypeBinding.hash(self.st); - hash_span!(self, type_binding.span); - visit::walk_assoc_type_binding(self, type_binding) - } - - fn visit_attribute(&mut self, _: &ast::Attribute) { - // We explicitly do not use this method, since doing that would - // implicitly impose an order on the attributes being hashed, while we - // explicitly don't want their order to matter - } - - fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { - debug!("visit_macro_def: st={:?}", self.st); - SawMacroDef.hash(self.st); - hash_attrs!(self, ¯o_def.attrs); - for tt in macro_def.body.trees() { - self.hash_token_tree(&tt); - } - visit::walk_macro_def(self, macro_def) - } -} - -#[derive(Hash)] -pub enum DefHash { - SawDefId, - SawLabel, - SawPrimTy, - SawSelfTy, - SawErr, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn hash_resolve(&mut self, id: ast::NodeId) { - // Because whether or not a given id has an entry is dependent - // solely on expr variant etc, we don't need to hash whether - // or not an entry was present (we are already hashing what - // variant it is above when we visit the HIR). - - if let Some(traits) = self.tcx.trait_map.get(&id) { - debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st); - traits.len().hash(self.st); - - // The ordering of the candidates is not fixed. So we hash - // the def-ids and then sort them and hash the collection. - let mut candidates: Vec<_> = - traits.iter() - .map(|&TraitCandidate { def_id, import_id: _ }| { - self.compute_def_id_hash(def_id) - }) - .collect(); - candidates.sort(); - candidates.hash(self.st); - } - } - - fn hash_def_id(&mut self, def_id: DefId) { - self.compute_def_id_hash(def_id).hash(self.st); - } - - fn hash_def(&mut self, def: Def) { - match def { - // Crucial point: for all of these variants, the variant + - // add'l data that is added is always the same if the - // def-id is the same, so it suffices to hash the def-id - Def::Fn(..) | - Def::Mod(..) | - Def::Static(..) | - Def::Variant(..) | - Def::VariantCtor(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::TyParam(..) | - Def::Struct(..) | - Def::StructCtor(..) | - Def::Union(..) | - Def::Trait(..) | - Def::Method(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) | - Def::Macro(..) => { - DefHash::SawDefId.hash(self.st); - self.hash_def_id(def.def_id()); - } - - Def::Label(..) => { - DefHash::SawLabel.hash(self.st); - // we don't encode the `id` because it always refers to something - // within this item, so if it changed, there would have to be other - // changes too - } - Def::PrimTy(ref prim_ty) => { - DefHash::SawPrimTy.hash(self.st); - prim_ty.hash(self.st); - } - Def::SelfTy(..) => { - DefHash::SawSelfTy.hash(self.st); - // the meaning of Self is always the same within a - // given context, so we don't need to hash the other - // fields - } - Def::Err => { - DefHash::SawErr.hash(self.st); - } - } - } - - pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { - debug!("hash_attributes: st={:?}", self.st); - let indices = self.indices_sorted_by(attributes, |attr| attr.name()); - - for i in indices { - let attr = &attributes[i]; - match attr.name() { - Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue, - _ => {} - }; - if !attr.is_sugared_doc { - SawAttribute(attr.style).hash(self.st); - for segment in &attr.path.segments { - SawIdent(segment.identifier.name.as_str()).hash(self.st); - } - for tt in attr.tokens.trees() { - self.hash_token_tree(&tt); - } - } - } - } - - fn indices_sorted_by(&mut self, items: &[T], get_key: F) -> Vec - where K: Ord, - F: Fn(&T) -> K - { - let mut indices = Vec::with_capacity(items.len()); - indices.extend(0 .. items.len()); - indices.sort_by_key(|index| get_key(&items[*index])); - indices - } - - fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) { - if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { - self.overflow_checks_enabled = true; - } - } - - fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) { - self.hash_discriminant(tt); - match *tt { - tokenstream::TokenTree::Token(span, ref token) => { - hash_span!(self, span); - self.hash_token(token, span); - } - tokenstream::TokenTree::Delimited(span, ref delimited) => { - hash_span!(self, span); - delimited.delim.hash(self.st); - for sub_tt in delimited.stream().trees() { - self.hash_token_tree(&sub_tt); - } - } - } - } - - fn hash_token(&mut self, - token: &token::Token, - error_reporting_span: Span) { - self.hash_discriminant(token); - match *token { - token::Token::Eq | - token::Token::Lt | - token::Token::Le | - token::Token::EqEq | - token::Token::Ne | - token::Token::Ge | - token::Token::Gt | - token::Token::AndAnd | - token::Token::OrOr | - token::Token::Not | - token::Token::Tilde | - token::Token::At | - token::Token::Dot | - token::Token::DotDot | - token::Token::DotDotDot | - token::Token::Comma | - token::Token::Semi | - token::Token::Colon | - token::Token::ModSep | - token::Token::RArrow | - token::Token::LArrow | - token::Token::FatArrow | - token::Token::Pound | - token::Token::Dollar | - token::Token::Question | - token::Token::Underscore | - token::Token::Whitespace | - token::Token::Comment | - token::Token::Eof => {} - - token::Token::BinOp(bin_op_token) | - token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st), - - token::Token::OpenDelim(delim_token) | - token::Token::CloseDelim(delim_token) => delim_token.hash(self.st), - - token::Token::Literal(ref lit, ref opt_name) => { - self.hash_discriminant(lit); - match *lit { - token::Lit::Byte(val) | - token::Lit::Char(val) | - token::Lit::Integer(val) | - token::Lit::Float(val) | - token::Lit::Str_(val) | - token::Lit::ByteStr(val) => val.as_str().hash(self.st), - token::Lit::StrRaw(val, n) | - token::Lit::ByteStrRaw(val, n) => { - val.as_str().hash(self.st); - n.hash(self.st); - } - }; - opt_name.map(ast::Name::as_str).hash(self.st); - } - - token::Token::Ident(ident) | - token::Token::Lifetime(ident) | - token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st), - - token::Token::Interpolated(ref non_terminal) => { - // FIXME(mw): This could be implemented properly. It's just a - // lot of work, since we would need to hash the AST - // in a stable way, in addition to the HIR. - // Since this is hardly used anywhere, just emit a - // warning for now. - if self.tcx.sess.opts.debugging_opts.incremental.is_some() { - let msg = format!("Quasi-quoting might make incremental \ - compilation very inefficient: {:?}", - non_terminal); - self.tcx.sess.span_warn(error_reporting_span, &msg[..]); - } - - non_terminal.hash(self.st); - } - - token::Token::DocComment(val) | - token::Token::Shebang(val) => val.as_str().hash(self.st), - } - } - - pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) { - let hir::Crate { - ref module, - ref attrs, - span, - - // These fields are handled separately: - exported_macros: _, - items: _, - trait_items: _, - impl_items: _, - bodies: _, - trait_impls: _, - trait_default_impl: _, - body_ids: _, - } = *krate; - - visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); - // Crate attributes are not copied over to the root `Mod`, so hash them - // explicitly here. - hash_attrs!(self, attrs); - } -} diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 477777c975db2..d10df17f85837 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,7 +22,6 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] -#![feature(core_intrinsics)] #![feature(conservative_impl_trait)] #![cfg_attr(stage0, feature(pub_restricted))] diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 8528482c7856c..63cfe591ce366 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -32,8 +32,7 @@ use syntax::ast; use {ModuleSource, ModuleTranslation}; -const PARTITION_REUSED: &'static str = "rustc_partition_reused"; -const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; +use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED}; const MODULE: &'static str = "module"; const CFG: &'static str = "cfg"; @@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> { impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { fn check_attr(&self, attr: &ast::Attribute) { - let disposition = if attr.check_name(PARTITION_REUSED) { + let disposition = if attr.check_name(ATTR_PARTITION_REUSED) { Disposition::Reused - } else if attr.check_name(PARTITION_TRANSLATED) { + } else if attr.check_name(ATTR_PARTITION_TRANSLATED) { Disposition::Translated } else { return; diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 5875015893144..15111bbba0a92 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct P { @@ -215,3 +217,13 @@ impl Decodable for P<[T]> { })) } } + +impl HashStable for P + where T: ?Sized + HashStable +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs index 195fb23f9d8c7..2d9fd7aa87553 100644 --- a/src/libsyntax/util/rc_slice.rs +++ b/src/libsyntax/util/rc_slice.rs @@ -12,6 +12,9 @@ use std::fmt; use std::ops::Deref; use std::rc::Rc; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; + #[derive(Clone)] pub struct RcSlice { data: Rc>, @@ -41,3 +44,13 @@ impl fmt::Debug for RcSlice { fmt::Debug::fmt(self.deref(), f) } } + +impl HashStable for RcSlice + where T: HashStable +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher); + } +} From edc7f9abec051b3c388f3199c052a0f617a99423 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 27 Mar 2017 21:52:51 +0300 Subject: [PATCH 549/662] Avoid type-checking addition and indexing twice. --- src/librustc_typeck/check/mod.rs | 1 - src/librustc_typeck/check/op.rs | 21 +++++++++++---------- src/test/compile-fail/issue-40610.rs | 16 ++++++++++++++++ src/test/compile-fail/issue-40861.rs | 16 ++++++++++++++++ 4 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/issue-40610.rs create mode 100644 src/test/compile-fail/issue-40861.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aaa3cf0f29e74..c995b7e92843d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3884,7 +3884,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { element_ty } None => { - self.check_expr_has_type(&idx, self.tcx.types.err); let mut err = self.type_error_struct( expr.span, |actual| { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f492ab12e3f99..cc33bd8754d9e 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -184,9 +184,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], - Symbol::intern(name), trait_def_id, - lhs_expr) { + let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + Symbol::intern(name), trait_def_id, + lhs_expr); + + // see `NB` above + let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + + let return_ty = match return_ty { Ok(return_ty) => return_ty, Err(()) => { // error types are considered "builtin" @@ -209,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty], Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.note( @@ -240,7 +245,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(missing_trait) = missing_trait { if missing_trait == "std::ops::Add" && self.check_str_addition(expr, lhs_expr, lhs_ty, - rhs_expr, rhs_ty_var, &mut err) { + rhs_expr, rhs_ty, &mut err) { // This has nothing here because it means we did string // concatenation (e.g. "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -257,9 +262,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - // see `NB` above - self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - (rhs_ty_var, return_ty) } @@ -268,12 +270,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_expr: &'gcx hir::Expr, - rhs_ty_var: Ty<'tcx>, + rhs_ty: Ty<'tcx>, mut err: &mut errors::DiagnosticBuilder) -> bool { // If this function returns true it means a note was printed, so we don't need // to print the normal "implementation of `std::ops::Add` might be missing" note let mut is_string_addition = false; - let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); if let TyRef(_, l_ty) = lhs_ty.sty { if let TyRef(_, r_ty) = rhs_ty.sty { if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { diff --git a/src/test/compile-fail/issue-40610.rs b/src/test/compile-fail/issue-40610.rs new file mode 100644 index 0000000000000..aec20b4ad87b7 --- /dev/null +++ b/src/test/compile-fail/issue-40610.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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 f(_: &[f32]) {} + +fn main() { + () + f(&[1.0]); + //~^ ERROR binary operation `+` cannot be applied to type `()` +} diff --git a/src/test/compile-fail/issue-40861.rs b/src/test/compile-fail/issue-40861.rs new file mode 100644 index 0000000000000..e525b3954f5ed --- /dev/null +++ b/src/test/compile-fail/issue-40861.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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 f(_: &[f32]) {} + +fn main() { + ()[f(&[1.0])]; + //~^ ERROR cannot index a value of type `()` +} From ae0e45c02808551ec27ed940fad9a05cd9bcbaed Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 6 Apr 2017 14:19:45 -0500 Subject: [PATCH 550/662] rustdoc: where clause adjustment to fix tests - add spaces to output so stripping lines and breaking spaces renders the same - add commas to where clauses in rustdoc tests to match the new output --- src/librustdoc/html/format.rs | 11 +++++++---- src/librustdoc/html/render.rs | 4 ++-- src/test/rustdoc/impl-parts.rs | 4 ++-- src/test/rustdoc/issue-20727-4.rs | 4 ++-- src/test/rustdoc/where.rs | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7c1139d7135c1..13a31c557021d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -192,9 +192,9 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(" where"); } else { if end_newline { - clause.push_str("where"); + clause.push_str(" where"); } else { - clause.push_str("where"); + clause.push_str(" where"); } } for (i, pred) in gens.where_predicates.iter().enumerate() { @@ -241,8 +241,11 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(""); let padding = repeat(" ").take(indent + 4).collect::(); clause = clause.replace("
    ", &format!("
    {}", padding)); - clause.insert_str(0, &repeat(" ").take(indent).collect::()); - if !end_newline { + clause.insert_str(0, &repeat(" ").take(indent.saturating_sub(1)) + .collect::()); + if end_newline { + clause.push(' '); + } else { clause.insert_str(0, "
    "); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b1ac6a5127f2a..af2beacf58ace 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2710,14 +2710,14 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } write!(w, ")")?; if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })? } write!(w, ";")?; } doctree::Unit => { // Needed for PhantomData. if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })? } write!(w, ";")?; } diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 89c5e60e34314..48ef4b6be66de 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -17,7 +17,7 @@ impl AnOibit for .. {} pub struct Foo { field: T } // @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \ -// "impl !AnOibit for Foo where T: Sync" +// "impl !AnOibit for Foo where T: Sync," // @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \ -// "impl !AnOibit for Foo where T: Sync" +// "impl !AnOibit for Foo where T: Sync," impl !AnOibit for Foo where T: Sync {} diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs index 9ebd1c448eeb0..960e40b070985 100644 --- a/src/test/rustdoc/issue-20727-4.rs +++ b/src/test/rustdoc/issue-20727-4.rs @@ -35,7 +35,7 @@ pub trait IndexMut: Index { pub mod reexport { // @has issue_20727_4/reexport/trait.Index.html - // @has - '//*[@class="rust trait"]' 'trait Index where Idx: ?Sized {' + // @has - '//*[@class="rust trait"]' 'trait Index where Idx: ?Sized, {' // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' // @has - '//*[@class="rust trait"]' \ // 'fn index(&self, index: Idx) -> &Self::Output' @@ -43,7 +43,7 @@ pub mod reexport { // @has issue_20727_4/reexport/trait.IndexMut.html // @has - '//*[@class="rust trait"]' \ - // 'trait IndexMut: Index where Idx: ?Sized {' + // 'trait IndexMut: Index where Idx: ?Sized, {' // @has - '//*[@class="rust trait"]' \ // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' pub use issue_20727::IndexMut; diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index d8dc115abf91e..e691f7c5bea01 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -44,5 +44,5 @@ pub enum Foxtrot { Foxtrot1(F) } impl MyTrait for Foxtrot where F: MyTrait {} // @has foo/type.Golf.html '//pre[@class="rust typedef"]' \ -// "type Golf where T: Clone = (T, T)" +// "type Golf where T: Clone, = (T, T)" pub type Golf where T: Clone = (T, T); From 9ffb54568c1d52bfee0162dd75b2c415cbf6fce4 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Thu, 6 Apr 2017 14:43:37 -0400 Subject: [PATCH 551/662] Remove some CStr transmutes. --- src/libstd/ffi/c_str.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2d14bb66bf4f9..fc1b9a976322e 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -356,7 +356,7 @@ impl ops::Deref for CString { type Target = CStr; fn deref(&self) -> &CStr { - unsafe { mem::transmute(self.as_bytes_with_nul()) } + unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } } } @@ -583,7 +583,8 @@ impl CStr { #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { let len = libc::strlen(ptr); - mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) + let ptr = ptr as *const u8; + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) } /// Creates a C string wrapper from a byte slice. From f4f79c3304602701b0a48e3ab77bc87903440e82 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 18:32:39 -0500 Subject: [PATCH 552/662] ignore the .init_array doctest as it's specific to ELF and won't pass on macOS / Windows --- src/doc/unstable-book/src/used.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md index cdda24acd708b..75a8b2774f422 100644 --- a/src/doc/unstable-book/src/used.md +++ b/src/doc/unstable-book/src/used.md @@ -55,7 +55,7 @@ The ELF standard defines two special sections, `.init_array` and in these sections (at least when linking programs that target the `*-*-linux-*` targets). -``` rust +``` rust,ignore #![feature(used)] extern "C" fn before_main() { From bfd01b7f40ae2cbfe9acbc1d10e79ffe16870df8 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 6 Apr 2017 18:36:14 -0500 Subject: [PATCH 553/662] rustdoc: move the space at the end of where clauses ...so that we don't indent the next line by one extra space --- src/librustdoc/html/format.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 13a31c557021d..d9bbc957c8a2d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -237,15 +237,23 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push(','); } } + + if end_newline { + //add a space so stripping
    tags and breaking spaces still renders properly + if f.alternate() { + clause.push(' '); + } else { + clause.push_str(" "); + } + } + if !f.alternate() { clause.push_str("
    "); let padding = repeat(" ").take(indent + 4).collect::(); clause = clause.replace("
    ", &format!("
    {}", padding)); clause.insert_str(0, &repeat(" ").take(indent.saturating_sub(1)) .collect::()); - if end_newline { - clause.push(' '); - } else { + if !end_newline { clause.insert_str(0, "
    "); } } From 8a1d2a3a5a4ec0288c72a1b68864c8ac8a3074e4 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 6 Apr 2017 14:53:15 -0400 Subject: [PATCH 554/662] rustdoc: collapse docblock before showing label --- src/librustdoc/html/static/main.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 200285862276a..cf9408abf5e89 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -951,14 +951,21 @@ if (relatedDoc.is(".docblock")) { if (relatedDoc.is(":visible")) { if (animate === true) { - relatedDoc.slideUp({duration: 'fast', easing: 'linear'}); - toggle.children(".toggle-label").fadeIn(); + relatedDoc.slideUp({ + duration: 'fast', + easing: 'linear', + complete: function() { + toggle.children(".toggle-label").fadeIn(); + toggle.parent(".toggle-wrapper").addClass("collapsed"); + toggle.children(".inner").text(labelForToggleButton(true)); + }, + }); } else { relatedDoc.hide(); toggle.children(".toggle-label").show(); + toggle.parent(".toggle-wrapper").addClass("collapsed"); + toggle.children(".inner").text(labelForToggleButton(true)); } - toggle.parent(".toggle-wrapper").addClass("collapsed"); - toggle.children(".inner").text(labelForToggleButton(true)); } else { relatedDoc.slideDown({duration: 'fast', easing: 'linear'}); toggle.parent(".toggle-wrapper").removeClass("collapsed"); From c9932b395ada3c367aea5e79645c10657262ea6f Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Fri, 7 Apr 2017 12:20:37 +0900 Subject: [PATCH 555/662] Changes based on PR feedback --- src/librustc_mir/transform/qualify_consts.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cdbc0bd8858a5..8eabe92fb98c0 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -603,7 +603,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Rvalue::Cast(CastKind::ReifyFnPointer, ..) | Rvalue::Cast(CastKind::UnsafeFnPointer, ..) | Rvalue::Cast(CastKind::ClosureFnPointer, ..) | - Rvalue::Cast(CastKind::Unsize, ..) => {} + Rvalue::Cast(CastKind::Unsize, ..) | + Rvalue::Discriminant(..) => {} Rvalue::Len(_) => { // Static lvalues in consts would have errored already, @@ -721,12 +722,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - Rvalue::Discriminant(..) => { - // FIXME implement discriminant const qualify - self.add(Qualif::NOT_CONST); - // Discriminants in consts will error elsewhere as an unimplemented expression type - } - Rvalue::Box(_) => { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { From 5202ac57531ca42d26a778d99165f22db3c61632 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 6 Apr 2017 23:29:16 -0400 Subject: [PATCH 556/662] Correct book examples for hardware re-ordering --- .../unstable-book/src/compiler-barriers.md | 116 ++++++++++-------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 5a5c539609c72..3108494aa79f0 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -21,78 +21,86 @@ A `compiler_barrier` restricts the kinds of memory re-ordering the compiler is allowed to do. Specifically, depending on the given ordering semantics, the compiler may be disallowed from moving reads or writes from before or after the call to the other side of the call to -`compiler_barrier`. +`compiler_barrier`. Note that it does **not** prevent the *hardware* +from doing such re-orderings -- for that, the `volatile_*` class of +functions, or full memory fences, need to be used. ## Examples -The need to prevent re-ordering of reads and writes often arises when -working with low-level devices. Consider a piece of code that interacts -with an ethernet card with a set of internal registers that are accessed -through an address port register (`a: &mut usize`) and a data port -register (`d: &usize`). To read internal register 5, the following code -might then be used: +`compiler_barrier` is generally only useful for preventing a thread from +racing *with itself*. That is, if a given thread is executing one piece +of code, and is then interrupted, and starts executing code elsewhere +(while still in the same thread, and conceptually still on the same +core). In traditional programs, this can only occur when a signal +handler is registered. Consider the following code: ```rust -fn read_fifth(a: &mut usize, d: &usize) -> usize { - *a = 5; - *d +#use std::sync::atomic::{AtomicBool, AtomicUsize}; +#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +#use std::sync::atomic::Ordering; +static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; +static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; + +fn main() { + IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); + IS_READY.store(true, Ordering::Relaxed); +} + +fn signal_handler() { + if IS_READY.load(Ordering::Relaxed) { + assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); + } } ``` -In this case, the compiler is free to re-order these two statements if -it thinks doing so might result in better performance, register use, or -anything else compilers care about. However, in doing so, it would break -the code, as `x` would be set to the value of some other device -register! +The way it is currently written, the `assert_eq!` is *not* guaranteed to +succeed, despite everything happening in a single thread. To see why, +remember that the compiler is free to swap the stores to +`IMPORTANT_VARIABLE` and `IS_READ` since they are both +`Ordering::Relaxed`. If it does, and the signal handler is invoked right +after `IS_READY` is updated, then the signal handler will see +`IS_READY=1`, but `IMPORTANT_VARIABLE=0`. -By inserting a compiler barrier, we can force the compiler to not -re-arrange these two statements, making the code function correctly -again: +Using a `compiler_barrier`, we can remedy this situation: ```rust #![feature(compiler_barriers)] -use std::sync::atomic; - -fn read_fifth(a: &mut usize, d: &usize) -> usize { - *a = 5; - atomic::compiler_barrier(atomic::Ordering::SeqCst); - *d +#use std::sync::atomic::{AtomicBool, AtomicUsize}; +#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +#use std::sync::atomic::Ordering; +use std::sync::atomic::compiler_barrier; + +static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; +static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; + +fn main() { + IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); + // prevent earlier writes from being moved beyond this point + compiler_barrier(Ordering::Release); + IS_READY.store(true, Ordering::Relaxed); } -``` - -Compiler barriers are also useful in code that implements low-level -synchronization primitives. Consider a structure with two different -atomic variables, with a dependency chain between them: -```rust -use std::sync::atomic; - -fn thread1(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { - x.store(1, atomic::Ordering::Release); - let v1 = y.load(atomic::Ordering::Acquire); -} -fn thread2(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { - y.store(1, atomic::Ordering::Release); - let v2 = x.load(atomic::Ordering::Acquire); +fn signal_handler() { + if IS_READY.load(Ordering::Relaxed) { + assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); + } } ``` -This code will guarantee that `thread1` sees any writes to `y` made by -`thread2`, and that `thread2` sees any writes to `x`. Intuitively, one -might also expect that if `thread2` sees `v2 == 0`, `thread1` must see -`v1 == 1` (since `thread2`'s store happened before its `load`, and its -load did not see `thread1`'s store). However, the code as written does -*not* guarantee this, because the compiler is allowed to re-order the -store and load within each thread. To enforce this particular behavior, -a call to `compiler_barrier(Ordering::SeqCst)` would need to be inserted -between the `store` and `load` in both functions. - -Compiler barriers with weaker re-ordering semantics (such as -`Ordering::Acquire`) can also be useful, but are beyond the scope of -this text. Curious readers are encouraged to read the Linux kernel's -discussion of [memory barriers][1], as well as C++ references on -[`std::memory_order`][2] and [`atomic_signal_fence`][3]. +In more advanced cases (for example, if `IMPORTANT_VARIABLE` was an +`AtomicPtr` that starts as `NULL`), it may also be unsafe for the +compiler to hoist code using `IMPORTANT_VARIABLE` above the +`IS_READY.load`. In that case, a `compiler_barrier(Ordering::Acquire)` +should be placed at the top of the `if` to prevent this optimizations. + +A deeper discussion of compiler barriers with various re-ordering +semantics (such as `Ordering::SeqCst`) is beyond the scope of this text. +Curious readers are encouraged to read the Linux kernel's discussion of +[memory barriers][1], the C++ references on [`std::memory_order`][2] and +[`atomic_signal_fence`][3], and [this StackOverflow answer][4] for +further details. [1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt [2]: http://en.cppreference.com/w/cpp/atomic/memory_order [3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/ +[4]: http://stackoverflow.com/a/18454971/472927 From 98037ca43d4d96f93e73e1eb3df8e64372d8f929 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 23:53:32 -0500 Subject: [PATCH 557/662] don't pass -C to nm the nm in our macOS bots don't support that flag and it's not really required --- src/test/run-make/used/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 5fe09e95a828d..9d7aa30f87482 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -7,5 +7,5 @@ all: else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm -C $(TMPDIR)/used.o | grep FOO + nm $(TMPDIR)/used.o | grep FOO endif From f45c6d8fc7097b5186ece9c43c3237d1c58e8dd4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 01:05:03 -0500 Subject: [PATCH 558/662] document some existing unstable features "msp430-interrupt", "ptx-kernel" and #![compiler_builtins_lib] --- .../unstable-book/src/abi-msp430-interrupt.md | 35 ++++++++++++ src/doc/unstable-book/src/abi-ptx.md | 56 ++++++++++++++++++- .../src/compiler-builtins-lib.md | 32 ++++++++++- .../unstable-book/src/compiler-builtins.md | 3 +- 4 files changed, 122 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/abi-msp430-interrupt.md b/src/doc/unstable-book/src/abi-msp430-interrupt.md index 9b2c7f298979d..b10bc41cb1439 100644 --- a/src/doc/unstable-book/src/abi-msp430-interrupt.md +++ b/src/doc/unstable-book/src/abi-msp430-interrupt.md @@ -5,3 +5,38 @@ The tracking issue for this feature is: [#38487] [#38487]: https://github.com/rust-lang/rust/issues/38487 ------------------------ + +In the MSP430 architecture, interrupt handlers have a special calling +convention. You can use the `"msp430-interrupt"` ABI to make the compiler apply +the right calling convention to the interrupt handlers you define. + + + +``` rust,ignore +#![feature(abi_msp430_interrupt)] +#![no_std] + +// Place the interrupt handler at the appropriate memory address +// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`) +#[link_section = "__interrupt_vector_10"] +#[no_mangle] +pub static TIM0_VECTOR: extern "msp430-interrupt" fn() = tim0; + +// The interrupt handler +extern "msp430-interrupt" fn tim0() { + // .. +} +``` + +``` text +$ msp430-elf-objdump -CD ./target/msp430/release/app +Disassembly of section __interrupt_vector_10: + +0000fff2 : + fff2: 00 c0 interrupt service routine at 0xc000 + +Disassembly of section .text: + +0000c000 : + c000: 00 13 reti +``` diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/abi-ptx.md index 9c1b8868aceb4..89b2a199279bc 100644 --- a/src/doc/unstable-book/src/abi-ptx.md +++ b/src/doc/unstable-book/src/abi-ptx.md @@ -1,5 +1,59 @@ # `abi_ptx` -The tracking issue for this feature is: None. +The tracking issue for this feature +is: [38788](https://github.com/rust-lang/rust/issues/38788) ------------------------ + +When emitting PTX code, all vanilla Rust functions (`fn`) get translated to +"device" functions. These functions are *not* callable from the host via the +CUDA API so a crate with only device functions is not too useful! + +OTOH, "global" functions *can* be called by the host; you can think of them +as the real public API of your crate. To produce a global function use the +`"ptx-kernel"` ABI. + + + +``` rust,ignore +#![feature(abi_ptx)] +#![no_std] + +pub unsafe extern "ptx-kernel" fn global_function() { + device_function(); +} + +pub fn device_function() { + // .. +} +``` + +``` text +$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm + +$ cat $(find -name '*.s') +// +// Generated by LLVM NVPTX Back-End +// + +.version 3.2 +.target sm_20 +.address_size 64 + + // .globl _ZN6kernel15global_function17h46111ebe6516b382E + +.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E() +{ + + + ret; +} + + // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E +.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E() +{ + + + ret; +} +``` diff --git a/src/doc/unstable-book/src/compiler-builtins-lib.md b/src/doc/unstable-book/src/compiler-builtins-lib.md index 8986b968ca6c4..5da8968fd0ce2 100644 --- a/src/doc/unstable-book/src/compiler-builtins-lib.md +++ b/src/doc/unstable-book/src/compiler-builtins-lib.md @@ -1,5 +1,35 @@ # `compiler_builtins_lib` -This feature is internal to the Rust compiler and is not intended for general use. +The tracking issue for this feature is: None. ------------------------ + +This feature is required to link to the `compiler_builtins` crate which contains +"compiler intrinsics". Compiler intrinsics are software implementations of basic +operations like multiplication of `u64`s. These intrinsics are only required on +platforms where these operations don't directly map to a hardware instruction. + +You should never need to explicitly link to the `compiler_builtins` crate when +building "std" programs as `compiler_builtins` is already in the dependency +graph of `std`. But you may need it when building `no_std` **binary** crates. If +you get a *linker* error like: + +``` text +$PWD/src/main.rs:11: undefined reference to `__aeabi_lmul' +$PWD/src/main.rs:11: undefined reference to `__aeabi_uldivmod' +``` + +That means that you need to link to this crate. + +When you link to this crate, make sure it only appears once in your crate +dependency graph. Also, it doesn't matter where in the dependency graph, you +place the `compiler_builtins` crate. + + + +``` rust,ignore +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; +``` diff --git a/src/doc/unstable-book/src/compiler-builtins.md b/src/doc/unstable-book/src/compiler-builtins.md index 3ec3cba257a99..52fac575b6e86 100644 --- a/src/doc/unstable-book/src/compiler-builtins.md +++ b/src/doc/unstable-book/src/compiler-builtins.md @@ -1,6 +1,5 @@ # `compiler_builtins` -The tracking issue for this feature is: None. +This feature is internal to the Rust compiler and is not intended for general use. ------------------------ - From b135c1291d8cc186647092765c5d94955a311410 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Thu, 6 Apr 2017 18:49:41 -0700 Subject: [PATCH 559/662] travis: Use upstream LLVM repositories for Fuchsia The Fuchsia copies of LLVM repositories contain additional patches for work-in-progress features and there is some amount of churn that may break Rust. Use upstream LLVM repositories instead for building the toolchain used by the Fuchsia builder. --- src/ci/docker/dist-fuchsia/Dockerfile | 5 ++- src/ci/docker/dist-fuchsia/build-toolchain.sh | 30 +++++++++----- .../dist-fuchsia/compiler-rt-dso-handle.patch | 41 +++++++++++++++++++ 3 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index ed37a9e842e22..0fd55b585a52c 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -14,13 +14,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ swig \ libedit-dev \ - libncurses5-dev + libncurses5-dev \ + patch RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \ tar xzf - -C /usr/local --strip-components=1 WORKDIR /tmp -COPY shared.sh build-toolchain.sh /tmp/ +COPY shared.sh build-toolchain.sh compiler-rt-dso-handle.patch /tmp/ RUN /tmp/build-toolchain.sh RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/dist-fuchsia/build-toolchain.sh index cad73eee1e013..10b285a546655 100755 --- a/src/ci/docker/dist-fuchsia/build-toolchain.sh +++ b/src/ci/docker/dist-fuchsia/build-toolchain.sh @@ -9,26 +9,31 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +# ignore-tidy-linelength + set -ex source shared.sh # Download sources SRCS=( - "https://fuchsia.googlesource.com/magenta magenta ac69119" - "https://fuchsia.googlesource.com/third_party/llvm llvm 5463083" - "https://fuchsia.googlesource.com/third_party/clang llvm/tools/clang 4ff7b4b" - "https://fuchsia.googlesource.com/third_party/lld llvm/tools/lld fd465a3" - "https://fuchsia.googlesource.com/third_party/lldb llvm/tools/lldb 6bb11f8" - "https://fuchsia.googlesource.com/third_party/compiler-rt llvm/runtimes/compiler-rt 52d4ecc" - "https://fuchsia.googlesource.com/third_party/libcxx llvm/runtimes/libcxx e891cc8" - "https://fuchsia.googlesource.com/third_party/libcxxabi llvm/runtimes/libcxxabi f0f0257" - "https://fuchsia.googlesource.com/third_party/libunwind llvm/runtimes/libunwind 50bddc1" + "https://fuchsia.googlesource.com/magenta magenta d17073dc8de344ead3b65e8cc6a12280dec38c84" + "https://llvm.googlesource.com/llvm llvm 3f58a16d8eec385e2b3ebdfbb84ff9d3bf27e025" + "https://llvm.googlesource.com/clang llvm/tools/clang 727ea63e6e82677f6e10e05e08bc7d6bdbae3111" + "https://llvm.googlesource.com/lld llvm/tools/lld a31286c1366e5e89b8872803fded13805a1a084b" + "https://llvm.googlesource.com/lldb llvm/tools/lldb 0b2384abec4cb99ad66687712e07dee4dd9d187e" + "https://llvm.googlesource.com/compiler-rt llvm/runtimes/compiler-rt 9093a35c599fe41278606a20b51095ea8bd5a081" + "https://llvm.googlesource.com/libcxx llvm/runtimes/libcxx 607e0c71ec4f7fd377ad3f6c47b08dbe89f66eaa" + "https://llvm.googlesource.com/libcxxabi llvm/runtimes/libcxxabi 0a3a1a8a5ca5ef69e0f6b7d5b9d13e63e6fd2c19" + "https://llvm.googlesource.com/libunwind llvm/runtimes/libunwind e128003563d99d9ee62247c4cee40f07d21c03e3" ) fetch() { mkdir -p $2 pushd $2 > /dev/null - curl -sL $1/+archive/$3.tar.gz | tar xzf - + git init + git remote add origin $1 + git fetch --depth=1 origin $3 + git reset --hard FETCH_HEAD popd > /dev/null } @@ -36,6 +41,11 @@ for i in "${SRCS[@]}"; do fetch $i done +# Remove this once https://reviews.llvm.org/D28791 is resolved +cd llvm/runtimes/compiler-rt +patch -Np1 < /tmp/compiler-rt-dso-handle.patch +cd ../../.. + # Build toolchain cd llvm mkdir build diff --git a/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch new file mode 100644 index 0000000000000..0b702894bb216 --- /dev/null +++ b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch @@ -0,0 +1,41 @@ +diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt +index fc4384af2..b442264c0 100644 +--- a/lib/builtins/CMakeLists.txt ++++ b/lib/builtins/CMakeLists.txt +@@ -194,6 +194,12 @@ if(APPLE) + atomic_thread_fence.c) + endif() + ++if(FUCHSIA) ++ set(GENERIC_SOURCES ++ ${GENERIC_SOURCES} ++ dso_handle.c) ++endif() ++ + if(NOT WIN32 OR MINGW) + set(GENERIC_SOURCES + ${GENERIC_SOURCES} +diff --git a/lib/builtins/dso_handle.c b/lib/builtins/dso_handle.c +new file mode 100644 +index 000000000..7766cd0aa +--- /dev/null ++++ b/lib/builtins/dso_handle.c +@@ -0,0 +1,18 @@ ++/* ===-- dso_handle.c - Provide __dso_handle -------------------------------=== ++ * ++ * The LLVM Compiler Infrastructure ++ * ++ * This file is dual licensed under the MIT and the University of Illinois Open ++ * Source Licenses. See LICENSE.TXT for details. ++ * ++ * ===----------------------------------------------------------------------=== ++ */ ++ ++/* __dso_handle symbol is mandated by C++ ABI with a value which is an address ++ * in one of the object's segments, and as such this symbol has to be included ++ * statically and cannot be a part of a shared library. Traditionally, it has ++ * been defined in crtbegin.o but there's no principled reason for it to be ++ * there. We defined this symbol in the builtin library which is built as a ++ * static library and always included in the final link. ++ */ ++__attribute__((visibility("hidden"))) void *const __dso_handle; From edc1ac3016d0e8383e174312db7c3b7a885af0c3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 3 Apr 2017 19:20:26 +0200 Subject: [PATCH 560/662] ICH: Centrally compute and cache DefPath hashes as part of DefPathTable. --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/def_collector.rs | 19 +-- src/librustc/hir/map/definitions.rs | 115 ++++++++++++++---- src/librustc/ich/def_path_hash.rs | 36 ------ src/librustc/ich/hcx.rs | 6 +- src/librustc/ich/mod.rs | 2 - src/librustc/middle/cstore.rs | 4 + src/librustc/ty/mod.rs | 9 ++ src/librustc/ty/util.rs | 14 +-- src/librustc_driver/driver.rs | 8 +- src/librustc_incremental/persist/directory.rs | 4 - src/librustc_incremental/persist/save.rs | 13 +- src/librustc_metadata/cstore_impl.rs | 6 +- src/librustc_metadata/decoder.rs | 13 +- src/librustc_resolve/lib.rs | 4 +- src/librustc_trans/back/symbol_names.rs | 25 ++-- src/librustc_typeck/collect.rs | 2 +- 17 files changed, 152 insertions(+), 130 deletions(-) delete mode 100644 src/librustc/ich/def_path_hash.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69f4..3f4390536b042 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2697,7 +2697,7 @@ impl<'a> LoweringContext<'a> { fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode) -> P { let id = self.next_id(); - let parent_def = self.parent_def; + let parent_def = self.parent_def.unwrap(); let def_id = { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index afdb9059ea7c0..c1417f718b27a 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -40,11 +40,9 @@ impl<'a> DefCollector<'a> { } } - pub fn collect_root(&mut self) { - let root = self.create_def_with_parent(None, - CRATE_NODE_ID, - DefPathData::CrateRoot, - ITEM_LIKE_SPACE); + pub fn collect_root(&mut self, crate_name: &str, crate_disambiguator: &str) { + let root = self.definitions.create_root_def(crate_name, + crate_disambiguator); assert_eq!(root, CRATE_DEF_INDEX); self.parent_def = Some(root); } @@ -54,20 +52,11 @@ impl<'a> DefCollector<'a> { data: DefPathData, address_space: DefIndexAddressSpace) -> DefIndex { - let parent_def = self.parent_def; + let parent_def = self.parent_def.unwrap(); debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); self.definitions.create_def_with_parent(parent_def, node_id, data, address_space) } - fn create_def_with_parent(&mut self, - parent: Option, - node_id: NodeId, - data: DefPathData, - address_space: DefIndexAddressSpace) - -> DefIndex { - self.definitions.create_def_with_parent(parent, node_id, data, address_space) - } - pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { let parent = self.parent_def; self.parent_def = Some(parent_def); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index dca9ebb3397a6..6118df2ddfc89 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -21,7 +21,7 @@ use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::fmt::Write; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use syntax::ast; use syntax::symbol::{Symbol, InternedString}; use ty::TyCtxt; @@ -34,6 +34,7 @@ use util::nodemap::NodeMap; pub struct DefPathTable { index_to_key: [Vec; 2], key_to_index: FxHashMap, + def_path_hashes: [Vec; 2], } // Unfortunately we have to provide a manual impl of Clone because of the @@ -44,6 +45,8 @@ impl Clone for DefPathTable { index_to_key: [self.index_to_key[0].clone(), self.index_to_key[1].clone()], key_to_index: self.key_to_index.clone(), + def_path_hashes: [self.def_path_hashes[0].clone(), + self.def_path_hashes[1].clone()], } } } @@ -52,6 +55,7 @@ impl DefPathTable { fn allocate(&mut self, key: DefKey, + def_path_hash: u64, address_space: DefIndexAddressSpace) -> DefIndex { let index = { @@ -62,6 +66,9 @@ impl DefPathTable { index }; self.key_to_index.insert(key, index); + self.def_path_hashes[address_space.index()].push(def_path_hash); + debug_assert!(self.def_path_hashes[address_space.index()].len() == + self.index_to_key[address_space.index()].len()); index } @@ -71,6 +78,12 @@ impl DefPathTable { [index.as_array_index()].clone() } + #[inline(always)] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.def_path_hashes[index.address_space().index()] + [index.as_array_index()] + } + #[inline(always)] pub fn def_index_for_def_key(&self, key: &DefKey) -> Option { self.key_to_index.get(key).cloned() @@ -116,17 +129,28 @@ impl DefPathTable { impl Encodable for DefPathTable { fn encode(&self, s: &mut S) -> Result<(), S::Error> { + // Index to key self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?; - self.index_to_key[DefIndexAddressSpace::High.index()].encode(s) + self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)?; + + // DefPath hashes + self.def_path_hashes[DefIndexAddressSpace::Low.index()].encode(s)?; + self.def_path_hashes[DefIndexAddressSpace::High.index()].encode(s)?; + + Ok(()) } } impl Decodable for DefPathTable { fn decode(d: &mut D) -> Result { let index_to_key_lo: Vec = Decodable::decode(d)?; - let index_to_key_high: Vec = Decodable::decode(d)?; + let index_to_key_hi: Vec = Decodable::decode(d)?; - let index_to_key = [index_to_key_lo, index_to_key_high]; + let def_path_hashes_lo: Vec = Decodable::decode(d)?; + let def_path_hashes_hi: Vec = Decodable::decode(d)?; + + let index_to_key = [index_to_key_lo, index_to_key_hi]; + let def_path_hashes = [def_path_hashes_lo, def_path_hashes_hi]; let mut key_to_index = FxHashMap(); @@ -141,6 +165,7 @@ impl Decodable for DefPathTable { Ok(DefPathTable { index_to_key: index_to_key, key_to_index: key_to_index, + def_path_hashes: def_path_hashes, }) } } @@ -184,6 +209,29 @@ pub struct DefKey { pub disambiguated_data: DisambiguatedDefPathData, } +impl DefKey { + fn compute_stable_hash(&self, parent_hash: u64) -> u64 { + let mut hasher = StableHasher::new(); + + // We hash a 0u8 here to disambiguate between regular DefPath hashes, + // and the special "root_parent" below. + 0u8.hash(&mut hasher); + parent_hash.hash(&mut hasher); + self.disambiguated_data.hash(&mut hasher); + hasher.finish() + } + + fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> u64 { + let mut hasher = StableHasher::new(); + // Disambiguate this from a regular DefPath hash, + // see compute_stable_hash() above. + 1u8.hash(&mut hasher); + crate_name.hash(&mut hasher); + crate_disambiguator.hash(&mut hasher); + hasher.finish() + } +} + /// Pair of `DefPathData` and an integer disambiguator. The integer is /// normally 0, but in the event that there are multiple defs with the /// same `parent` and `data`, we use this field to disambiguate @@ -271,19 +319,6 @@ impl DefPath { s } - - pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 { - debug!("deterministic_hash({:?})", self); - let mut state = StableHasher::new(); - self.deterministic_hash_to(tcx, &mut state); - state.finish() - } - - pub fn deterministic_hash_to(&self, tcx: TyCtxt, state: &mut H) { - tcx.original_crate_name(self.krate).as_str().hash(state); - tcx.crate_disambiguator(self.krate).as_str().hash(state); - self.data.hash(state); - } } #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -338,6 +373,7 @@ impl Definitions { table: DefPathTable { index_to_key: [vec![], vec![]], key_to_index: FxHashMap(), + def_path_hashes: [vec![], vec![]], }, node_to_def_index: NodeMap(), def_index_to_node: [vec![], vec![]], @@ -359,6 +395,11 @@ impl Definitions { self.table.def_key(index) } + #[inline(always)] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.table.def_path_hash(index) + } + pub fn def_index_for_def_key(&self, key: DefKey) -> Option { self.table.def_index_for_def_key(&key) } @@ -398,12 +439,38 @@ impl Definitions { self.node_to_hir_id[node_id] } + /// Add a definition with a parent definition. + pub fn create_root_def(&mut self, + crate_name: &str, + crate_disambiguator: &str) + -> DefIndex { + let key = DefKey { + parent: None, + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::CrateRoot, + disambiguator: 0 + } + }; + + let parent_hash = DefKey::root_parent_stable_hash(crate_name, + crate_disambiguator); + let def_path_hash = key.compute_stable_hash(parent_hash); + + // Create the definition. + let address_space = super::ITEM_LIKE_SPACE; + let index = self.table.allocate(key, def_path_hash, address_space); + assert!(self.def_index_to_node[address_space.index()].is_empty()); + self.def_index_to_node[address_space.index()].push(ast::CRATE_NODE_ID); + self.node_to_def_index.insert(ast::CRATE_NODE_ID, index); + + index + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, - parent: Option, + parent: DefIndex, node_id: ast::NodeId, data: DefPathData, - // is_owner: bool) address_space: DefIndexAddressSpace) -> DefIndex { debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})", @@ -415,12 +482,13 @@ impl Definitions { data, self.table.def_key(self.node_to_def_index[&node_id])); - assert_eq!(parent.is_some(), data != DefPathData::CrateRoot); + // The root node must be created with create_root_def() + assert!(data != DefPathData::CrateRoot); // Find a unique DefKey. This basically means incrementing the disambiguator // until we get no match. let mut key = DefKey { - parent: parent, + parent: Some(parent), disambiguated_data: DisambiguatedDefPathData { data: data, disambiguator: 0 @@ -431,10 +499,13 @@ impl Definitions { key.disambiguated_data.disambiguator += 1; } + let parent_hash = self.table.def_path_hash(parent); + let def_path_hash = key.compute_stable_hash(parent_hash); + debug!("create_def_with_parent: after disambiguation, key = {:?}", key); // Create the definition. - let index = self.table.allocate(key, address_space); + let index = self.table.allocate(key, def_path_hash, address_space); assert_eq!(index.as_array_index(), self.def_index_to_node[address_space.index()].len()); self.def_index_to_node[address_space.index()].push(node_id); diff --git a/src/librustc/ich/def_path_hash.rs b/src/librustc/ich/def_path_hash.rs deleted file mode 100644 index 03051dc003420..0000000000000 --- a/src/librustc/ich/def_path_hash.rs +++ /dev/null @@ -1,36 +0,0 @@ -// 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 hir::def_id::DefId; -use ty::TyCtxt; -use util::nodemap::DefIdMap; - -pub struct DefPathHashes<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: DefIdMap, -} - -impl<'a, 'tcx> DefPathHashes<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - DefPathHashes { - tcx: tcx, - data: DefIdMap() - } - } - - pub fn hash(&mut self, def_id: DefId) -> u64 { - let tcx = self.tcx; - *self.data.entry(def_id) - .or_insert_with(|| { - let def_path = tcx.def_path(def_id); - def_path.deterministic_hash(tcx) - }) - } -} diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 73d81212cd77e..5ef30550f1155 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -10,7 +10,7 @@ use hir; use hir::def_id::DefId; -use ich::{self, CachingCodemapView, DefPathHashes}; +use ich::{self, CachingCodemapView}; use session::config::DebugInfoLevel::NoDebugInfo; use ty; @@ -32,7 +32,6 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; /// things (e.g. each DefId/DefPath is only hashed once). pub struct StableHashingContext<'a, 'tcx: 'a> { tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefPathHashes<'a, 'tcx>, codemap: CachingCodemapView<'tcx>, hash_spans: bool, hash_bodies: bool, @@ -64,7 +63,6 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { StableHashingContext { tcx: tcx, - def_path_hashes: DefPathHashes::new(tcx), codemap: CachingCodemapView::new(tcx), hash_spans: hash_spans_initial, hash_bodies: true, @@ -111,7 +109,7 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { #[inline] pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { - self.def_path_hashes.hash(def_id) + self.tcx.def_path_hash(def_id) } #[inline] diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index f0601a0efabf8..f932c90a331e1 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -11,12 +11,10 @@ //! ICH - Incremental Compilation Hash pub use self::fingerprint::Fingerprint; -pub use self::def_path_hash::DefPathHashes; pub use self::caching_codemap_view::CachingCodemapView; pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; mod fingerprint; -mod def_path_hash; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 8bc0cf2577b5d..ee0635ac9a179 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -230,6 +230,7 @@ pub trait CrateStore { -> Option; fn def_key(&self, def: DefId) -> DefKey; fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn def_path_hash(&self, def: DefId) -> u64; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; @@ -377,6 +378,9 @@ impl CrateStore for DummyCrateStore { fn def_path(&self, def: DefId) -> hir_map::DefPath { bug!("relative_def_path") } + fn def_path_hash(&self, def: DefId) -> u64 { + bug!("wa") + } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3c529a6982042..292e30e3d41f1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,6 +2227,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + #[inline] + pub fn def_path_hash(self, def_id: DefId) -> u64 { + if def_id.is_local() { + self.hir.definitions().def_path_hash(def_id.index) + } else { + self.sess.cstore.def_path_hash(def_id) + } + } + pub fn def_span(self, def_id: DefId) -> Span { if let Some(id) = self.hir.as_local_node_id(def_id) { self.hir.span(id) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1c1e0d91cb4d6..fd8191303a9a6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,7 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use infer::InferCtxt; -use hir::map as hir_map; +// use hir::map as hir_map; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; @@ -441,13 +441,11 @@ impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W> fn def_id(&mut self, did: DefId) { // Hash the DefPath corresponding to the DefId, which is independent - // of compiler internal state. - let path = self.tcx.def_path(did); - self.def_path(&path) - } - - pub fn def_path(&mut self, def_path: &hir_map::DefPath) { - def_path.deterministic_hash_to(self.tcx, &mut self.state); + // of compiler internal state. We already have a stable hash value of + // all DefPaths available via tcx.def_path_hash(), so we just feed that + // into the hasher. + let hash = self.tcx.def_path_hash(did); + self.hash(hash); } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 96eb5dd602f51..4e6c919c7f569 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -647,8 +647,12 @@ pub fn phase_2_configure_and_expand(sess: &Session, let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name); crate_loader.preprocess(&krate); let resolver_arenas = Resolver::arenas(); - let mut resolver = - Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); + let mut resolver = Resolver::new(sess, + &krate, + crate_name, + make_glob_map, + &mut crate_loader, + &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 546feb212243a..b9b860222968b 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -186,10 +186,6 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> { .clone() } - pub fn lookup_def_path(&self, id: DefPathIndex) -> &DefPath { - &self.directory.paths[id.index as usize] - } - pub fn map(&mut self, node: &DepNode) -> DepNode { node.map_def(|&def_id| Some(self.add(def_id))).unwrap() } diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 2e5186493370b..1591503865e81 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -258,8 +258,6 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, index_map: FxHashMap() }; - let mut def_id_hashes = FxHashMap(); - for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() { let index = NodeIndex(index); let def_id = match *target.data { @@ -267,15 +265,6 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, _ => continue, }; - let mut def_id_hash = |def_id: DefId| -> u64 { - *def_id_hashes.entry(def_id) - .or_insert_with(|| { - let index = builder.add(def_id); - let path = builder.lookup_def_path(index); - path.deterministic_hash(tcx) - }) - }; - // To create the hash for each item `X`, we don't hash the raw // bytes of the metadata (though in principle we // could). Instead, we walk the predecessors of `MetaData(X)` @@ -295,7 +284,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, .map(|index| preds.reduced_graph.node_data(index)) .filter(|dep_node| HashContext::is_hashable(dep_node)) .map(|dep_node| { - let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))) + let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))) .unwrap(); let hash = preds.hashes[dep_node]; (hash_dep_node, hash) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 41a2e8a8d55e3..efcd2f007d66c 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -73,7 +73,7 @@ provide! { <'tcx> tcx, def_id, cdata predicates => { cdata.get_predicates(def_id.index, tcx) } super_predicates => { cdata.get_super_predicates(def_id.index, tcx) } trait_def => { - tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx)) + tcx.alloc_trait_def(cdata.get_trait_def(def_id.index)) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { @@ -370,6 +370,10 @@ impl CrateStore for cstore::CStore { self.get_crate_data(def.krate).def_path(def.index) } + fn def_path_hash(&self, def: DefId) -> u64 { + self.get_crate_data(def.krate).def_path_hash(def.index) + } + fn struct_field_names(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 43e076e799b3d..cdbecb3ae2e42 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -492,10 +492,7 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_trait_def(&self, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::TraitDef { + pub fn get_trait_def(&self, item_id: DefIndex) -> ty::TraitDef { let data = match self.entry(item_id).kind { EntryKind::Trait(data) => data.decode(self), _ => bug!(), @@ -504,7 +501,7 @@ impl<'a, 'tcx> CrateMetadata { let def = ty::TraitDef::new(self.local_def_id(item_id), data.unsafety, data.paren_sugar, - self.def_path(item_id).deterministic_hash(tcx)); + self.def_path_table.def_path_hash(item_id)); if data.has_default_impl { def.record_has_default_impl(); @@ -1053,6 +1050,7 @@ impl<'a, 'tcx> CrateMetadata { } } + #[inline] pub fn def_key(&self, index: DefIndex) -> DefKey { self.def_path_table.def_key(index) } @@ -1063,6 +1061,11 @@ impl<'a, 'tcx> CrateMetadata { DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent)) } + #[inline] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.def_path_table.def_path_hash(index) + } + /// Imports the codemap from an external crate into the codemap of the crate /// currently being compiled (the "local crate"). /// diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..d9900340a2e9f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1289,6 +1289,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { impl<'a> Resolver<'a> { pub fn new(session: &'a Session, krate: &Crate, + crate_name: &str, make_glob_map: MakeGlobMap, crate_loader: &'a mut CrateLoader, arenas: &'a ResolverArenas<'a>) @@ -1303,7 +1304,8 @@ impl<'a> Resolver<'a> { module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); let mut definitions = Definitions::new(); - DefCollector::new(&mut definitions).collect_root(); + DefCollector::new(&mut definitions) + .collect_root(crate_name, &session.local_crate_disambiguator().as_str()); let mut invocations = FxHashMap(); invocations.insert(Mark::root(), diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 3ad04e10cb027..3568c1ba8f4c1 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -101,13 +101,13 @@ use common::SharedCrateContext; use monomorphize::Instance; use rustc::middle::weak_lang_items; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; -use rustc::hir::map::definitions::{DefPath, DefPathData}; +use rustc::hir::map::definitions::DefPathData; use rustc::util::common::record_time; use syntax::attr; @@ -115,8 +115,8 @@ use syntax::symbol::{Symbol, InternedString}; fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - // path to the item this name is for - def_path: &DefPath, + // the DefId of the item this name is for + def_id: Option, // type of the item, without any generic // parameters substituted; this is @@ -128,8 +128,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // if any. substs: Option<&'tcx Substs<'tcx>>) -> String { - debug!("get_symbol_hash(def_path={:?}, parameters={:?})", - def_path, substs); + debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); let tcx = scx.tcx(); @@ -139,7 +138,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // the main symbol name is not necessarily unique; hash in the // compiler's internal def-path, guaranteeing each symbol has a // truly unique path - hasher.def_path(def_path); + hasher.hash(def_id.map(|def_id| tcx.def_path_hash(def_id))); // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type @@ -224,8 +223,6 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, return scx.tcx().item_name(def_id).as_str().to_string(); } - let def_path = scx.tcx().def_path(def_id); - // We want to compute the "type" of this item. Unfortunately, some // kinds of items (e.g., closures) don't have an entry in the // item-type array. So walk back up the find the closest parent @@ -256,10 +253,10 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, // and should not matter anyhow. let instance_ty = scx.tcx().erase_regions(&instance_ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); + let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs)); let mut buffer = SymbolPathBuffer { - names: Vec::with_capacity(def_path.data.len()) + names: Vec::new() }; item_path::with_forced_absolute_paths(|| { @@ -288,11 +285,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, t: Ty<'tcx>, prefix: &str) -> String { - let empty_def_path = DefPath { - data: vec![], - krate: LOCAL_CRATE, - }; - let hash = get_symbol_hash(scx, &empty_def_path, t, None); + let hash = get_symbol_hash(scx, None, t, None); let path = [Symbol::intern(prefix).as_str()]; mangle(path.iter().cloned(), &hash) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1ed42b842c6fa..77ab076eba386 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -806,7 +806,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.emit(); } - let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); + let def_path_hash = tcx.def_path_hash(def_id); let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash); if tcx.hir.trait_is_auto(def_id) { From bb6387295a85da70546ed3ce7fa0d702b9cb9d6c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 3 Apr 2017 19:39:12 +0200 Subject: [PATCH 561/662] SVH: Don't hash the HIR twice when once is enough. The SVH (Strict Version Hash) of a crate is currently computed by hashing the ICHes (Incremental Computation Hashes) of the crate's HIR. This is fine, expect that for incr. comp. we compute two ICH values for each HIR item, one for the complete item and one that just includes the item's interface. The two hashes are are needed for dependency tracking but if we are compiling non-incrementally and just need the ICH values for the SVH, one of them is enough, giving us the opportunity to save some work in this case. --- src/librustc_incremental/calculate_svh/mod.rs | 9 ++++++++- src/librustc_incremental/lib.rs | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c80a5a1627797..c67866971e199 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -99,6 +99,13 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { item_like: T) where T: HashStable> { + if !hash_bodies && !self.hcx.tcx().sess.opts.build_dep_graph() { + // If we just need the hashes in order to compute the SVH, we don't + // need have two hashes per item. Just the one containing also the + // item's body is sufficient. + return + } + let mut hasher = IchHasher::new(); self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| { item_like.hash_stable(hcx, &mut hasher); @@ -143,7 +150,7 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { (item_dep_node, item_hash) }) .collect(); - item_hashes.sort(); // avoid artificial dependencies on item ordering + item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering item_hashes.hash(&mut crate_state); } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index d10df17f85837..aa7eb36581f3e 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -23,6 +23,7 @@ #![feature(staged_api)] #![feature(rand)] #![feature(conservative_impl_trait)] +#![feature(sort_unstable)] #![cfg_attr(stage0, feature(pub_restricted))] extern crate graphviz; From 8fc3ab20b01044cfebfcd963ef7b69cdb11381b2 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 7 Apr 2017 09:11:07 -0400 Subject: [PATCH 562/662] rustdoc needs space after # to ignore --- src/doc/unstable-book/src/compiler-barriers.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 3108494aa79f0..df0e20eefadbc 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -35,9 +35,9 @@ core). In traditional programs, this can only occur when a signal handler is registered. Consider the following code: ```rust -#use std::sync::atomic::{AtomicBool, AtomicUsize}; -#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; -#use std::sync::atomic::Ordering; +# use std::sync::atomic::{AtomicBool, AtomicUsize}; +# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +# use std::sync::atomic::Ordering; static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; @@ -65,9 +65,9 @@ Using a `compiler_barrier`, we can remedy this situation: ```rust #![feature(compiler_barriers)] -#use std::sync::atomic::{AtomicBool, AtomicUsize}; -#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; -#use std::sync::atomic::Ordering; +# use std::sync::atomic::{AtomicBool, AtomicUsize}; +# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +# use std::sync::atomic::Ordering; use std::sync::atomic::compiler_barrier; static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; From e6597e12bc40a28ed4c682e71f7159b9cb2403e7 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 7 Apr 2017 09:13:06 -0400 Subject: [PATCH 563/662] Mention interrupts and green threads --- src/doc/unstable-book/src/compiler-barriers.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index df0e20eefadbc..9e137a5c4f878 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -32,7 +32,12 @@ racing *with itself*. That is, if a given thread is executing one piece of code, and is then interrupted, and starts executing code elsewhere (while still in the same thread, and conceptually still on the same core). In traditional programs, this can only occur when a signal -handler is registered. Consider the following code: +handler is registered. In more low-level code, such situations can also +arise when handling interrupts, when implementing green threads with +pre-emption, etc. + +To give a straightforward example of when a `compiler_barrier` is +necessary, consider the following example: ```rust # use std::sync::atomic::{AtomicBool, AtomicUsize}; From 15fa301b7aa903235e70f8b5a4c2ef7ae31268f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 09:46:55 -0500 Subject: [PATCH 564/662] change the format of the linked issue number --- src/doc/unstable-book/src/abi-ptx.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/abi-ptx.md index 89b2a199279bc..0ded3ceeaef2c 100644 --- a/src/doc/unstable-book/src/abi-ptx.md +++ b/src/doc/unstable-book/src/abi-ptx.md @@ -1,7 +1,8 @@ # `abi_ptx` -The tracking issue for this feature -is: [38788](https://github.com/rust-lang/rust/issues/38788) +The tracking issue for this feature is: [#38788] + +[#38788]: https://github.com/rust-lang/rust/issues/38788 ------------------------ From 5c5a5182c94d07409fac8cb40b2cdab488c140ff Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 7 Apr 2017 17:28:55 +0200 Subject: [PATCH 565/662] Optimize AtomicBool::fetch_nand --- src/libcore/sync/atomic.rs | 22 +++++++++++++--------- src/libcore/tests/atomic.rs | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 2e1058bfc3413..dd0069502dee7 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -539,17 +539,21 @@ impl AtomicBool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done // with an 8-bit integer internally, which would set the upper 7 bits. - // So we just use a compare-exchange loop instead, which is what the - // intrinsic actually expands to anyways on many platforms. - let mut old = self.load(Relaxed); - loop { - let new = !(old && val); - match self.compare_exchange_weak(old, new, order, Relaxed) { - Ok(_) => break, - Err(x) => old = x, + // So we just use fetch_xor or compare_exchange instead. + if val { + // !(x & true) == !x + // We must invert the bool. + self.fetch_xor(true, order) + } else { + // !(x & false) == true + // We must set the bool to true. Instead of delegating to swap or fetch_or, use + // compare_exchange instead in order to avoid unnecessary writes to memory, which + // might minimize cache-coherence traffic. + match self.compare_exchange(false, true, order, Ordering::Relaxed) { + Ok(_) => false, + Err(_) => true, } } - old } /// Logical "or" with a boolean value. diff --git a/src/libcore/tests/atomic.rs b/src/libcore/tests/atomic.rs index b6bb5fddf4a4b..9babe24a98563 100644 --- a/src/libcore/tests/atomic.rs +++ b/src/libcore/tests/atomic.rs @@ -24,10 +24,23 @@ fn bool_() { #[test] fn bool_and() { let a = AtomicBool::new(true); - assert_eq!(a.fetch_and(false, SeqCst),true); + assert_eq!(a.fetch_and(false, SeqCst), true); assert_eq!(a.load(SeqCst),false); } +#[test] +fn bool_nand() { + let a = AtomicBool::new(false); + assert_eq!(a.fetch_nand(false, SeqCst), false); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(false, SeqCst), true); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(true, SeqCst), true); + assert_eq!(a.load(SeqCst), false); + assert_eq!(a.fetch_nand(true, SeqCst), false); + assert_eq!(a.load(SeqCst), true); +} + #[test] fn uint_and() { let x = AtomicUsize::new(0xf731); From 9d11b089ad136432dff6c49c6eb3c48c7f6e5273 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 21 Feb 2017 14:47:15 -0500 Subject: [PATCH 566/662] -Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications --- src/librustc/session/config.rs | 16 +- src/librustc/session/mod.rs | 5 +- src/librustc_back/lib.rs | 42 ++++++ src/librustc_back/target/aarch64_apple_ios.rs | 2 + .../target/aarch64_linux_android.rs | 2 + .../target/aarch64_unknown_freebsd.rs | 2 + .../target/aarch64_unknown_fuchsia.rs | 2 + .../target/aarch64_unknown_linux_gnu.rs | 2 + src/librustc_back/target/android_base.rs | 4 +- src/librustc_back/target/apple_base.rs | 4 +- src/librustc_back/target/apple_ios_base.rs | 15 +- .../target/arm_linux_androideabi.rs | 2 + .../target/arm_unknown_linux_gnueabi.rs | 2 + .../target/arm_unknown_linux_gnueabihf.rs | 2 + .../target/arm_unknown_linux_musleabi.rs | 2 + .../target/arm_unknown_linux_musleabihf.rs | 2 + .../target/armv5te_unknown_linux_gnueabi.rs | 3 +- src/librustc_back/target/armv7_apple_ios.rs | 2 + .../target/armv7_linux_androideabi.rs | 2 + .../target/armv7_unknown_linux_gnueabihf.rs | 3 +- .../target/armv7_unknown_linux_musleabihf.rs | 2 + src/librustc_back/target/armv7s_apple_ios.rs | 2 + .../target/asmjs_unknown_emscripten.rs | 11 +- src/librustc_back/target/dragonfly_base.rs | 26 ++-- src/librustc_back/target/freebsd_base.rs | 26 ++-- src/librustc_back/target/fuchsia_base.rs | 34 +++-- src/librustc_back/target/i386_apple_ios.rs | 2 + src/librustc_back/target/i686_apple_darwin.rs | 4 +- .../target/i686_linux_android.rs | 2 + .../target/i686_pc_windows_gnu.rs | 5 +- .../target/i686_pc_windows_msvc.rs | 7 +- .../target/i686_unknown_dragonfly.rs | 4 +- .../target/i686_unknown_freebsd.rs | 4 +- .../target/i686_unknown_haiku.rs | 4 +- .../target/i686_unknown_linux_gnu.rs | 4 +- .../target/i686_unknown_linux_musl.rs | 6 +- .../target/i686_unknown_netbsd.rs | 4 +- .../target/i686_unknown_openbsd.rs | 4 +- src/librustc_back/target/le32_unknown_nacl.rs | 19 ++- src/librustc_back/target/linux_base.rs | 32 ++-- src/librustc_back/target/linux_musl_base.rs | 9 +- .../target/mips64_unknown_linux_gnuabi64.rs | 2 + .../target/mips64el_unknown_linux_gnuabi64.rs | 2 + .../target/mips_unknown_linux_gnu.rs | 2 + .../target/mips_unknown_linux_musl.rs | 2 + .../target/mips_unknown_linux_uclibc.rs | 2 + .../target/mipsel_unknown_linux_gnu.rs | 2 + .../target/mipsel_unknown_linux_musl.rs | 2 + .../target/mipsel_unknown_linux_uclibc.rs | 2 + src/librustc_back/target/mod.rs | 77 ++++++++-- src/librustc_back/target/netbsd_base.rs | 26 ++-- src/librustc_back/target/openbsd_base.rs | 26 ++-- .../target/powerpc64_unknown_linux_gnu.rs | 4 +- .../target/powerpc64le_unknown_linux_gnu.rs | 4 +- .../target/powerpc_unknown_linux_gnu.rs | 4 +- src/librustc_back/target/redox_base.rs | 33 +++-- .../target/s390x_unknown_linux_gnu.rs | 2 + .../target/sparc64_unknown_linux_gnu.rs | 2 + .../target/sparc64_unknown_netbsd.rs | 4 +- .../target/sparcv9_sun_solaris.rs | 4 +- .../target/thumbv6m_none_eabi.rs | 2 + .../target/thumbv7em_none_eabi.rs | 2 + .../target/thumbv7em_none_eabihf.rs | 2 + .../target/thumbv7m_none_eabi.rs | 2 + .../target/wasm32_unknown_emscripten.rs | 14 +- src/librustc_back/target/windows_base.rs | 59 ++++---- src/librustc_back/target/windows_msvc_base.rs | 13 +- .../target/x86_64_apple_darwin.rs | 4 +- src/librustc_back/target/x86_64_apple_ios.rs | 2 + .../target/x86_64_pc_windows_gnu.rs | 4 +- .../target/x86_64_pc_windows_msvc.rs | 2 + .../target/x86_64_rumprun_netbsd.rs | 4 +- .../target/x86_64_sun_solaris.rs | 4 +- .../target/x86_64_unknown_bitrig.rs | 4 +- .../target/x86_64_unknown_dragonfly.rs | 4 +- .../target/x86_64_unknown_freebsd.rs | 4 +- .../target/x86_64_unknown_fuchsia.rs | 4 +- .../target/x86_64_unknown_haiku.rs | 4 +- .../target/x86_64_unknown_linux_gnu.rs | 4 +- .../target/x86_64_unknown_linux_musl.rs | 4 +- .../target/x86_64_unknown_netbsd.rs | 4 +- .../target/x86_64_unknown_openbsd.rs | 4 +- .../target/x86_64_unknown_redox.rs | 4 +- src/librustc_llvm/lib.rs | 1 + src/librustc_trans/back/link.rs | 13 +- src/librustc_trans/back/linker.rs | 138 ++++++++++++------ .../target-specs/my-awesome-platform.json | 1 + .../target-specs/my-incomplete-platform.json | 1 + .../x86_64-unknown-linux-gnu.json | 1 + 89 files changed, 598 insertions(+), 240 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a0603c5795247..ef825a6854cec 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -19,7 +19,7 @@ pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; -use rustc_back::PanicStrategy; +use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; use lint; use middle::cstore; @@ -641,12 +641,14 @@ macro_rules! options { Some("either `panic` or `abort`"); pub const parse_sanitizer: Option<&'static str> = Some("one of: `address`, `leak`, `memory` or `thread`"); + pub const parse_linker_flavor: Option<&'static str> = + Some(::rustc_back::LinkerFlavor::one_of()); } #[allow(dead_code)] mod $mod_set { use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer}; - use rustc_back::PanicStrategy; + use rustc_back::{LinkerFlavor, PanicStrategy}; $( pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { @@ -777,6 +779,14 @@ macro_rules! options { } true } + + fn parse_linker_flavor(slote: &mut Option, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavor::from_str) { + Some(lf) => *slote = Some(lf), + _ => return false, + } + true + } } ) } @@ -979,6 +989,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "pass `-install_name @rpath/...` to the macOS linker"), sanitizer: Option = (None, parse_sanitizer, [TRACKED], "Use a sanitizer"), + linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], + "Linker flavor"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3ba82f34c3266..70b2809ccbed2 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -36,7 +36,7 @@ use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; use syntax_pos::{Span, MultiSpan}; -use rustc_back::PanicStrategy; +use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; use rustc_data_structures::flock; use llvm; @@ -363,6 +363,9 @@ impl Session { pub fn panic_strategy(&self) -> PanicStrategy { self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) } + pub fn linker_flavor(&self) -> LinkerFlavor { + self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor) + } pub fn no_landing_pads(&self) -> bool { self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 000e4eb59bf05..6679cc73029c7 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -52,6 +52,48 @@ pub mod dynamic_lib; use serialize::json::{Json, ToJson}; +macro_rules! linker_flavor { + ($(($variant:ident, $string:expr),)+) => { + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] + pub enum LinkerFlavor { + $($variant,)+ + } + + impl LinkerFlavor { + pub const fn one_of() -> &'static str { + concat!("one of: ", $($string, " ",)+) + } + + pub fn from_str(s: &str) -> Option { + Some(match s { + $($string => LinkerFlavor::$variant,)+ + _ => return None, + }) + } + + pub fn desc(&self) -> &str { + match *self { + $(LinkerFlavor::$variant => $string,)+ + } + } + } + + impl ToJson for LinkerFlavor { + fn to_json(&self) -> Json { + self.desc().to_json() + } + } + } +} + +linker_flavor! { + (Em, "em"), + (Gcc, "gcc"), + (Ld, "ld"), + (Msvc, "msvc"), +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub enum PanicStrategy { Unwind, diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 5ef79359140f7..802a8c77db05b 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 54eead94986cc..7d8610b4a3684 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_freebsd.rs b/src/librustc_back/target/aarch64_unknown_freebsd.rs index 3c5d6308ee6ba..c5cfff0be03ad 100644 --- a/src/librustc_back/target/aarch64_unknown_freebsd.rs +++ b/src/librustc_back/target/aarch64_unknown_freebsd.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_fuchsia.rs b/src/librustc_back/target/aarch64_unknown_fuchsia.rs index 6ba1732e67f79..5d680504a02d0 100644 --- a/src/librustc_back/target/aarch64_unknown_fuchsia.rs +++ b/src/librustc_back/target/aarch64_unknown_fuchsia.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -23,6 +24,7 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index 5f6335d405f5e..043bd881c7290 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { arch: "aarch64".to_string(), target_os: "linux".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/android_base.rs b/src/librustc_back/target/android_base.rs index 9791520e9339b..49baa1b96cee3 100644 --- a/src/librustc_back/target/android_base.rs +++ b/src/librustc_back/target/android_base.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::TargetOptions; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); // Many of the symbols defined in compiler-rt are also defined in libgcc. // Android's linker doesn't like that by default. - base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--allow-multiple-definition".to_string()); base.is_like_android = true; base.position_independent_executables = true; base.has_elf_tls = false; diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs index 3a551a2b124b7..159f93a74c683 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_back/target/apple_base.rs @@ -10,7 +10,7 @@ use std::env; -use target::TargetOptions; +use target::{LinkArgs, TargetOptions}; pub fn opts() -> TargetOptions { // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 @@ -43,7 +43,7 @@ pub fn opts() -> TargetOptions { dll_prefix: "lib".to_string(), dll_suffix: ".dylib".to_string(), archive_format: "bsd".to_string(), - pre_link_args: Vec::new(), + pre_link_args: LinkArgs::new(), exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: version >= (10, 7), .. Default::default() diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 17492b8bdcb64..2e7d30d969ec4 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use std::io; use std::process::Command; -use target::TargetOptions; +use target::{LinkArgs, TargetOptions}; use self::Arch::*; @@ -60,7 +61,7 @@ pub fn get_sdk_root(sdk_name: &str) -> Result { } } -fn build_pre_link_args(arch: Arch) -> Result, String> { +fn build_pre_link_args(arch: Arch) -> Result { let sdk_name = match arch { Armv7 | Armv7s | Arm64 => "iphoneos", I386 | X86_64 => "iphonesimulator" @@ -70,8 +71,14 @@ fn build_pre_link_args(arch: Arch) -> Result, String> { let sdk_root = get_sdk_root(sdk_name)?; - Ok(vec!["-arch".to_string(), arch_name.to_string(), - "-Wl,-syslibroot".to_string(), sdk_root]) + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, + vec!["-arch".to_string(), + arch_name.to_string(), + "-Wl,-syslibroot".to_string(), + sdk_root]); + + Ok(args) } fn target_cpu(arch: Arch) -> String { diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index c7d2df4344cb1..bccd5a41ab115 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -24,6 +25,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 77d35edfbd09c..165d34fe6c7ce 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v6".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index b183412be1934..731021d979bc4 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v6,+vfp2".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 261d4353c7a09..f81bcd78b03aa 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -29,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index 1443dcf5bad41..6c47678ede6ad 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -29,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs index 37216e20762d4..200c6ab74cc6d 100644 --- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -21,6 +22,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+soft-float".to_string(), @@ -31,4 +33,3 @@ pub fn target() -> TargetResult { } }) } - diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index 9e9c443930624..4d87458283294 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index 36f409b7948c2..0c90e834006f1 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#v7a @@ -27,6 +28,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 96ccedd5bea5c..d3a6a68449c39 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -21,6 +22,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // Info about features at https://wiki.debian.org/ArmHardFloatPort @@ -32,4 +34,3 @@ pub fn target() -> TargetResult { } }) } - diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index 8f66e6a4f58d4..5086cd44f7ac9 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index 6edde6e73efd3..96c89a7ed3bd5 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 4d38b0d170596..b884d4e54101e 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions}; use super::emscripten_base::{cmd}; pub fn target() -> Result { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Em, + vec!["-s".to_string(), + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + let opts = TargetOptions { linker: cmd("emcc"), ar: cmd("emar"), @@ -24,7 +30,7 @@ pub fn target() -> Result { obj_is_bitcode: true, is_like_emscripten: true, max_atomic_width: Some(32), - post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + post_link_args: args, target_family: Some("unix".to_string()), .. Default::default() }; @@ -37,6 +43,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "asmjs".to_string(), + linker_flavor: LinkerFlavor::Em, options: opts, }) } diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs index dca33e45af7c7..e44cd393289be 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_back/target/dragonfly_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs index dca33e45af7c7..e44cd393289be 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs index 8c517224201b2..c6207cdc4d9c1 100644 --- a/src/librustc_back/target/fuchsia_base.rs +++ b/src/librustc_back/target/fuchsia_base.rs @@ -8,30 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + // FIXME: figure out whether these linker args are desirable + //"-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + //"-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - // FIXME: figure out whether these linker args are desirable - //"-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - //"-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), has_elf_tls: true, diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index 319ada4f8e17c..a6383179f3ae6 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(64), .. base diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index d3b09d9a0f112..6b14972e9f754 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "yonah".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); Ok(Target { llvm_target: "i686-apple-darwin".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "macos".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index f8a8f5a3500be..a5390cbfb7258 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#x86 @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 2947726139207..4a736a93be7d7 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -18,7 +19,8 @@ pub fn target() -> TargetResult { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args.push("-Wl,--large-address-aware".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string()); Ok(Target { llvm_target: "i686-pc-windows-gnu".to_string(), @@ -29,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs index 2290d2057f130..17fe306804f4a 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -17,12 +18,13 @@ pub fn target() -> TargetResult { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args.push("/LARGEADDRESSAWARE".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string()); // Ensure the linker will only produce an image if it can also produce a table of // the image's safe exception handlers. // https://msdn.microsoft.com/en-us/library/9a89h429.aspx - base.pre_link_args.push("/SAFESEH".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string()); Ok(Target { llvm_target: "i686-pc-windows-msvc".to_string(), @@ -33,6 +35,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index d8f8431e66e7f..052bc23c119ea 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-dragonfly".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "dragonfly".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index ddbc74f25c9cd..d77a9cca2683d 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-freebsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_back/target/i686_unknown_haiku.rs index 9078206c9e069..b0e67bd90ddde 100644 --- a/src/librustc_back/target/i686_unknown_haiku.rs +++ b/src/librustc_back/target/i686_unknown_haiku.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); Ok(Target { llvm_target: "i686-unknown-haiku".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "haiku".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index bf9c28b0c10e5..3c5c10676260e 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-linux-gnu".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs index ced59448f7f65..3ed8c94d0bf2a 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_back/target/i686_unknown_linux_musl.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); - base.pre_link_args.push("-Wl,-melf_i386".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string()); // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. @@ -40,6 +41,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_netbsd.rs b/src/librustc_back/target/i686_unknown_netbsd.rs index e7e2ee3f9056a..fc92e5aee6af1 100644 --- a/src/librustc_back/target/i686_unknown_netbsd.rs +++ b/src/librustc_back/target/i686_unknown_netbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-netbsdelf".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_openbsd.rs b/src/librustc_back/target/i686_unknown_openbsd.rs index 81efd37386a0f..7ef68bd6d9c3a 100644 --- a/src/librustc_back/target/i686_unknown_openbsd.rs +++ b/src/librustc_back/target/i686_unknown_openbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-openbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "openbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index 891e7dda14a2a..f4265e0eb1462 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -8,17 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions, TargetResult}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert(LinkerFlavor::Gcc, + vec!["--pnacl-exceptions=sjlj".to_string(), + "--target=le32-unknown-nacl".to_string(), + "-Wl,--start-group".to_string()]); + let mut post_link_args = LinkArgs::new(); + post_link_args.insert(LinkerFlavor::Gcc, + vec!["-Wl,--end-group".to_string()]); + let opts = TargetOptions { linker: "pnacl-clang".to_string(), ar: "pnacl-ar".to_string(), - pre_link_args: vec!["--pnacl-exceptions=sjlj".to_string(), - "--target=le32-unknown-nacl".to_string(), - "-Wl,--start-group".to_string()], - post_link_args: vec!["-Wl,--end-group".to_string()], + pre_link_args: pre_link_args, + post_link_args: post_link_args, dynamic_linking: false, executables: true, exe_suffix: ".pexe".to_string(), @@ -36,6 +44,7 @@ pub fn target() -> TargetResult { target_vendor: "unknown".to_string(), data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(), arch: "le32".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: opts, }) } diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs index 4b2ae9c8e699c..722d2fa16ef7a 100644 --- a/src/librustc_back/target/linux_base.rs +++ b/src/librustc_back/target/linux_base.rs @@ -8,29 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: true, diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index 18cca425a32c8..236f2c1ef0aa3 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::TargetOptions; pub fn opts() -> TargetOptions { @@ -15,13 +16,13 @@ pub fn opts() -> TargetOptions { // Make sure that the linker/gcc really don't pull in anything, including // default objects, libs, etc. - base.pre_link_args.push("-nostdlib".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string()); // At least when this was tested, the linker would not add the // `GNU_EH_FRAME` program header to executables generated, which is required // when unwinding to locate the unwinding information. I'm not sure why this // argument is *not* necessary for normal builds, but it can't hurt! - base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string()); // There's a whole bunch of circular dependencies when dealing with MUSL // unfortunately. To put this in perspective libc is statically linked to @@ -45,8 +46,8 @@ pub fn opts() -> TargetOptions { // link everything as a group, not stripping anything out until everything // is processed. The linker will still perform a pass to strip out object // files but it won't do so until all objects/archives have been processed. - base.pre_link_args.push("-Wl,-(".to_string()); - base.post_link_args.push("-Wl,-)".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string()); + base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]); // When generating a statically linked executable there's generally some // small setup needed which is listed in these files. These are provided by diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index c284840ecb4bd..038a70ed6b17e 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index 17895836fe87b..aed4c4fbb08de 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index a6d8fae2536ca..9ef61f9caddcd 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index e4a6d2a55d981..f54790bab970b 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs index ccc64ea393b78..59c07efe0fdc1 100644 --- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 9b8b1d5713f1d..ec19cc1a536ad 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index 5693bddd0488a..00085d18e6d09 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), features: "+mips32,+soft-float".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs index 3acade5a47444..b3ca2edec1eda 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 559418d2c4f5f..ca6894a7b7041 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -50,7 +50,7 @@ use std::default::Default; use std::io::prelude::*; use syntax::abi::{Abi, lookup as lookup_abi}; -use PanicStrategy; +use {LinkerFlavor, PanicStrategy}; mod android_base; mod apple_base; @@ -72,6 +72,7 @@ mod thumb_base; mod fuchsia_base; mod redox_base; +pub type LinkArgs = BTreeMap>; pub type TargetResult = Result; macro_rules! supported_targets { @@ -241,6 +242,8 @@ pub struct Target { pub arch: String, /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. pub data_layout: String, + /// Linker flavor + pub linker_flavor: LinkerFlavor, /// Optional settings with defaults. pub options: TargetOptions, } @@ -261,7 +264,7 @@ pub struct TargetOptions { /// Linker arguments that are unconditionally passed *before* any /// user-defined libraries. - pub pre_link_args: Vec, + pub pre_link_args: LinkArgs, /// Objects to link before all others, always found within the /// sysroot folder. pub pre_link_objects_exe: Vec, // ... when linking an executable @@ -269,13 +272,13 @@ pub struct TargetOptions { /// Linker arguments that are unconditionally passed after any /// user-defined but before post_link_objects. Standard platform /// libraries that should be always be linked to, usually go here. - pub late_link_args: Vec, + pub late_link_args: LinkArgs, /// Objects to link after all others, always found within the /// sysroot folder. pub post_link_objects: Vec, /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. - pub post_link_args: Vec, + pub post_link_args: LinkArgs, /// Extra arguments to pass to the external assembler (when used) pub asm_args: Vec, @@ -412,8 +415,8 @@ impl Default for TargetOptions { is_builtin: false, linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(), ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(), - pre_link_args: Vec::new(), - post_link_args: Vec::new(), + pre_link_args: LinkArgs::new(), + post_link_args: LinkArgs::new(), asm_args: Vec::new(), cpu: "generic".to_string(), features: "".to_string(), @@ -445,7 +448,7 @@ impl Default for TargetOptions { pre_link_objects_exe: Vec::new(), pre_link_objects_dll: Vec::new(), post_link_objects: Vec::new(), - late_link_args: Vec::new(), + late_link_args: LinkArgs::new(), archive_format: "gnu".to_string(), custom_unwind_resume: false, lib_allocation_crate: "alloc_system".to_string(), @@ -529,6 +532,10 @@ impl Target { target_os: get_req_field("os")?, target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), + linker_flavor: LinkerFlavor::from_str(&*get_req_field("linker-flavor")?) + .ok_or_else(|| { + format!("linker flavor must be {}", LinkerFlavor::one_of()) + })?, options: Default::default(), }; @@ -579,17 +586,49 @@ impl Target { .map(|s| s.to_string() ); } } ); + ($key_name:ident, LinkerFlavor) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().map(|s| { + LinkerFlavor::from_str(&s).ok_or_else(|| { + Err(format!("'{}' is not a valid value for linker-flavor. \ + Use 'em', 'gcc', 'ld' or 'msvc.", s)) + }) + })).unwrap_or(Ok(())) + } ); + ($key_name:ident, link_args) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(obj) = obj.find(&name[..]).and_then(|o| o.as_object()) { + let mut args = LinkArgs::new(); + for (k, v) in obj { + let k = LinkerFlavor::from_str(&k).ok_or_else(|| { + format!("{}: '{}' is not a valid value for linker-flavor. \ + Use 'em', 'gcc', 'ld' or 'msvc'", name, k) + })?; + + let v = v.as_array().map(|a| { + a + .iter() + .filter_map(|o| o.as_string()) + .map(|s| s.to_owned()) + .collect::>() + }).unwrap_or(vec![]); + + args.insert(k, v); + } + base.options.$key_name = args; + } + } ); } key!(is_builtin, bool); key!(linker); key!(ar); - key!(pre_link_args, list); + key!(pre_link_args, link_args); key!(pre_link_objects_exe, list); key!(pre_link_objects_dll, list); - key!(late_link_args, list); + key!(late_link_args, link_args); key!(post_link_objects, list); - key!(post_link_args, list); + key!(post_link_args, link_args); key!(asm_args, list); key!(cpu); key!(features); @@ -734,6 +773,16 @@ impl ToJson for Target { d.insert(name.to_string(), self.options.$attr.to_json()); } } ); + (link_args - $attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + if default.$attr != self.options.$attr { + let obj = self.options.$attr + .iter() + .map(|(k, v)| (k.desc().to_owned(), v.clone())) + .collect::>(); + d.insert(name.to_string(), obj.to_json()); + } + } ); } target_val!(llvm_target); @@ -743,18 +792,18 @@ impl ToJson for Target { target_val!(target_os, "os"); target_val!(target_env, "env"); target_val!(target_vendor, "vendor"); - target_val!(arch); target_val!(data_layout); + target_val!(linker_flavor); target_option_val!(is_builtin); target_option_val!(linker); target_option_val!(ar); - target_option_val!(pre_link_args); + target_option_val!(link_args - pre_link_args); target_option_val!(pre_link_objects_exe); target_option_val!(pre_link_objects_dll); - target_option_val!(late_link_args); + target_option_val!(link_args - late_link_args); target_option_val!(post_link_objects); - target_option_val!(post_link_args); + target_option_val!(link_args - post_link_args); target_option_val!(asm_args); target_option_val!(cpu); target_option_val!(features); diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs index 57179a68afd8e..63245fcae767b 100644 --- a/src/librustc_back/target/netbsd_base.rs +++ b/src/librustc_back/target/netbsd_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, .. Default::default() } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 12b8e8bdc88fd..2df9b8e03ff53 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -8,10 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, @@ -19,16 +32,7 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, is_like_openbsd: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index 909c5488dcb70..55a5bfd1e6746 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); // see #36994 @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs index a692346ca0ffe..c22bc3b041a4e 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64le".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); // see #36994 @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index 284772c43319a..677d198b1a379 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); base.max_atomic_width = Some(32); // see #36994 @@ -27,6 +28,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_back/target/redox_base.rs index c5e1e107753ff..f26a86d4bdc0f 100644 --- a/src/librustc_back/target/redox_base.rs +++ b/src/librustc_back/target/redox_base.rs @@ -8,25 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use PanicStrategy; -use target::TargetOptions; +use {LinkerFlavor, PanicStrategy}; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { - TargetOptions { - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string() + ]); - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string() - ], + TargetOptions { + pre_link_args: args, executables: true, relocation_model: "static".to_string(), disable_redzone: true, diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index 671fb4f4319b3..cc8eb7c4e8424 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs index f627cc18f0b3d..1bd51ac62581f 100644 --- a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparc64_unknown_netbsd.rs b/src/librustc_back/target/sparc64_unknown_netbsd.rs index f30cebbc2d5a7..bc65a17ce6ea9 100644 --- a/src/librustc_back/target/sparc64_unknown_netbsd.rs +++ b/src/librustc_back/target/sparc64_unknown_netbsd.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "v9".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); Ok(Target { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs index c88e5a402f2f5..122b38968a9c0 100644 --- a/src/librustc_back/target/sparcv9_sun_solaris.rs +++ b/src/librustc_back/target/sparcv9_sun_solaris.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); // llvm calls this "v9" base.cpu = "v9".to_string(); base.max_atomic_width = Some(64); @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "solaris".to_string(), target_env: "".to_string(), target_vendor: "sun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/thumbv6m_none_eabi.rs b/src/librustc_back/target/thumbv6m_none_eabi.rs index 6c22f98538459..08bf145e5518a 100644 --- a/src/librustc_back/target/thumbv6m_none_eabi.rs +++ b/src/librustc_back/target/thumbv6m_none_eabi.rs @@ -10,6 +10,7 @@ // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them diff --git a/src/librustc_back/target/thumbv7em_none_eabi.rs b/src/librustc_back/target/thumbv7em_none_eabi.rs index ddad4e3624f3c..13f9cc5f65fb9 100644 --- a/src/librustc_back/target/thumbv7em_none_eabi.rs +++ b/src/librustc_back/target/thumbv7em_none_eabi.rs @@ -19,6 +19,7 @@ // To opt-in to hardware accelerated floating point operations, you can use, for example, // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(32), diff --git a/src/librustc_back/target/thumbv7em_none_eabihf.rs b/src/librustc_back/target/thumbv7em_none_eabihf.rs index a9fac48e8e5ac..929b6db6fb2c6 100644 --- a/src/librustc_back/target/thumbv7em_none_eabihf.rs +++ b/src/librustc_back/target/thumbv7em_none_eabihf.rs @@ -18,6 +18,7 @@ // // To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the diff --git a/src/librustc_back/target/thumbv7m_none_eabi.rs b/src/librustc_back/target/thumbv7m_none_eabi.rs index ed61dd0459b4d..8d46e7cb90760 100644 --- a/src/librustc_back/target/thumbv7m_none_eabi.rs +++ b/src/librustc_back/target/thumbv7m_none_eabi.rs @@ -10,6 +10,7 @@ // Targets the Cortex-M3 processor (ARMv7-M) +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(32), diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index b1967fa8f37a7..a51f59d6ff192 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -8,10 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions}; use super::emscripten_base::{cmd}; pub fn target() -> Result { + let mut post_link_args = LinkArgs::new(); + post_link_args.insert(LinkerFlavor::Gcc, + vec!["-s".to_string(), + "BINARYEN=1".to_string(), + "-s".to_string(), + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + let opts = TargetOptions { linker: cmd("emcc"), ar: cmd("emar"), @@ -26,8 +34,7 @@ pub fn target() -> Result { obj_is_bitcode: true, is_like_emscripten: true, max_atomic_width: Some(32), - post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(), - "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + post_link_args: post_link_args, target_family: Some("unix".to_string()), .. Default::default() }; @@ -40,6 +47,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "wasm32".to_string(), + linker_flavor: LinkerFlavor::Em, options: opts, }) } diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index db02e142fcc8e..9bde24a28dd9b 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -8,26 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { - TargetOptions { - // FIXME(#13846) this should be enabled for windows - function_sections: false, - linker: "gcc".to_string(), - dynamic_linking: true, - executables: true, - dll_prefix: "".to_string(), - dll_suffix: ".dll".to_string(), - exe_suffix: ".exe".to_string(), - staticlib_prefix: "".to_string(), - staticlib_suffix: ".lib".to_string(), - no_default_libraries: true, - target_family: Some("windows".to_string()), - is_like_windows: true, - allows_weak_linkage: false, - pre_link_args: vec![ + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert(LinkerFlavor::Gcc, vec![ // And here, we see obscure linker flags #45. On windows, it has been // found to be necessary to have this flag to compile liblibc. // @@ -64,7 +51,34 @@ pub fn opts() -> TargetOptions { // Do not use the standard system startup files or libraries when linking "-nostdlib".to_string(), - ], + ]); + + let mut late_link_args = LinkArgs::new(); + late_link_args.insert(LinkerFlavor::Gcc, vec![ + "-lmingwex".to_string(), + "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc + "-lmsvcrt".to_string(), + "-luser32".to_string(), + "-lkernel32".to_string(), + ]); + + TargetOptions { + // FIXME(#13846) this should be enabled for windows + function_sections: false, + linker: "gcc".to_string(), + dynamic_linking: true, + executables: true, + dll_prefix: "".to_string(), + dll_suffix: ".dll".to_string(), + exe_suffix: ".exe".to_string(), + staticlib_prefix: "".to_string(), + staticlib_suffix: ".lib".to_string(), + no_default_libraries: true, + target_family: Some("windows".to_string()), + is_like_windows: true, + allows_weak_linkage: false, + pre_link_args: pre_link_args, pre_link_objects_exe: vec![ "crt2.o".to_string(), // mingw C runtime initialization for executables "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs @@ -73,14 +87,7 @@ pub fn opts() -> TargetOptions { "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls "rsbegin.o".to_string(), ], - late_link_args: vec![ - "-lmingwex".to_string(), - "-lmingw32".to_string(), - "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc - "-lmsvcrt".to_string(), - "-luser32".to_string(), - "-lkernel32".to_string(), - ], + late_link_args: late_link_args, post_link_objects: vec![ "rsend.o".to_string() ], diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index efa215b419d70..421f59aea93bf 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Msvc, + vec!["/NOLOGO".to_string(), + "/NXCOMPAT".to_string()]); + TargetOptions { function_sections: true, linker: "link.exe".to_string(), @@ -56,10 +62,7 @@ pub fn opts() -> TargetOptions { target_family: Some("windows".to_string()), is_like_windows: true, is_like_msvc: true, - pre_link_args: vec![ - "/NOLOGO".to_string(), - "/NXCOMPAT".to_string(), - ], + pre_link_args: args, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index b3c1561dbcc0b..8fd1b80430f44 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -15,7 +16,7 @@ pub fn target() -> TargetResult { base.cpu = "core2".to_string(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-apple-darwin".to_string(), @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { target_os: "macos".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 7a58bb34ce7f6..bbd81fd86ff57 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(64), .. base diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 321585cd65eb3..10e88d88ee372 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); Ok(Target { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs index ea8909d213e80..b07031c4bf1a3 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -24,6 +25,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index 3313721439696..eea4389cfd64e 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); base.ar = "x86_64-rumprun-netbsd-ar".to_string(); base.max_atomic_width = Some(64); @@ -34,6 +35,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "rumprun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs index 8e4fd94e7bce4..fe8691f36950d 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_back/target/x86_64_sun_solaris.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "solaris".to_string(), target_env: "".to_string(), target_vendor: "sun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index eda16c29466b5..5f87fe177a98c 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-unknown-bitrig".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "bitrig".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index 194efb8fc2322..96f608409ffa7 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "dragonfly".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index b127bee163b86..500629a16808d 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-freebsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_fuchsia.rs b/src/librustc_back/target/x86_64_unknown_fuchsia.rs index 08fe17a556ecc..6e37896d4148b 100644 --- a/src/librustc_back/target/x86_64_unknown_fuchsia.rs +++ b/src/librustc_back/target/x86_64_unknown_fuchsia.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-fuchsia".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_back/target/x86_64_unknown_haiku.rs index 7cf0599037c1e..7fab9128b2952 100644 --- a/src/librustc_back/target/x86_64_unknown_haiku.rs +++ b/src/librustc_back/target/x86_64_unknown_haiku.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-unknown-haiku".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "haiku".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index f95bcb556e57f..f73055cebaa2e 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs index c3bf9dcca6ee4..38b9c0bace52b 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index 87a7c184644d5..6fe2e3fc08e23 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-netbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs index e9d645b0d38f2..b292b5fc1e4e4 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-openbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "openbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_redox.rs b/src/librustc_back/target/x86_64_unknown_redox.rs index cecac06b23527..a693e76099bda 100644 --- a/src/librustc_back/target/x86_64_unknown_redox.rs +++ b/src/librustc_back/target/x86_64_unknown_redox.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::redox_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-redox".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "redox".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index f300bf16145a7..6e34f551f5df7 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -422,3 +422,4 @@ impl Drop for OperandBundleDef { } } } +#[link(name = "ffi")] extern {} diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 12a1ffa276725..66380079a8b29 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -707,13 +707,16 @@ fn link_natively(sess: &Session, outputs: &OutputFilenames, tmpdir: &Path) { info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename); + let flavor = sess.linker_flavor(); // The invocations of cc share some flags across platforms let (pname, mut cmd, extra) = get_linker(sess); cmd.env("PATH", command_path(sess, extra)); let root = sess.target_filesearch(PathKind::Native).get_lib_path(); - cmd.args(&sess.target.target.options.pre_link_args); + if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { + cmd.args(args); + } let pre_link_objects = if crate_type == config::CrateTypeExecutable { &sess.target.target.options.pre_link_objects_exe @@ -739,11 +742,15 @@ fn link_natively(sess: &Session, objects, out_filename, outputs, trans); cmd = linker.finalize(); } - cmd.args(&sess.target.target.options.late_link_args); + if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + cmd.args(args); + } for obj in &sess.target.target.options.post_link_objects { cmd.arg(root.join(obj)); } - cmd.args(&sess.target.target.options.post_link_args); + if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { + cmd.args(args); + } if sess.opts.debugging_opts.print_link_args { println!("{:?}", &cmd); diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index a178d17a7c2d3..48e469e28ee31 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::collections::HashMap; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter}; @@ -22,6 +22,7 @@ use back::archive; use back::symbol_export::{self, ExportedSymbols}; use middle::dependency_format::Linkage; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; +use rustc_back::LinkerFlavor; use session::Session; use session::config::{self, CrateType, OptLevel, DebugInfoLevel}; use serialize::{json, Encoder}; @@ -45,25 +46,39 @@ impl<'a, 'tcx> LinkerInfo { pub fn to_linker(&'a self, cmd: Command, sess: &'a Session) -> Box { - if sess.target.target.options.is_like_msvc { - Box::new(MsvcLinker { - cmd: cmd, - sess: sess, - info: self - }) as Box - } else if sess.target.target.options.is_like_emscripten { - Box::new(EmLinker { - cmd: cmd, - sess: sess, - info: self - }) as Box - } else { - Box::new(GnuLinker { - cmd: cmd, - sess: sess, - info: self, - hinted_static: false, - }) as Box + match sess.linker_flavor() { + LinkerFlavor::Msvc => { + Box::new(MsvcLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box + } + LinkerFlavor::Em => { + Box::new(EmLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box + } + LinkerFlavor::Gcc => { + Box::new(GccLinker { + cmd: cmd, + sess: sess, + info: self, + hinted_static: false, + is_ld: false, + }) as Box + } + LinkerFlavor::Ld => { + Box::new(GccLinker { + cmd: cmd, + sess: sess, + info: self, + hinted_static: false, + is_ld: true, + }) as Box + } } } } @@ -100,14 +115,32 @@ pub trait Linker { fn finalize(&mut self) -> Command; } -pub struct GnuLinker<'a> { +pub struct GccLinker<'a> { cmd: Command, sess: &'a Session, info: &'a LinkerInfo, hinted_static: bool, // Keeps track of the current hinting mode. + // Link as ld + is_ld: bool, } -impl<'a> GnuLinker<'a> { +impl<'a> GccLinker<'a> { + /// Argument that must be passed *directly* to the linker + /// + /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used + fn linker_arg(&mut self, arg: S) -> &mut Self + where S: AsRef + { + if !self.is_ld { + let mut os = OsString::from("-Wl,"); + os.push(arg.as_ref()); + self.cmd.arg(os); + } else { + self.cmd.arg(arg); + } + self + } + fn takes_hints(&self) -> bool { !self.sess.target.target.options.is_like_osx } @@ -119,7 +152,7 @@ impl<'a> GnuLinker<'a> { fn hint_static(&mut self) { if !self.takes_hints() { return } if !self.hinted_static { - self.cmd.arg("-Wl,-Bstatic"); + self.linker_arg("-Bstatic"); self.hinted_static = true; } } @@ -127,13 +160,13 @@ impl<'a> GnuLinker<'a> { fn hint_dynamic(&mut self) { if !self.takes_hints() { return } if self.hinted_static { - self.cmd.arg("-Wl,-Bdynamic"); + self.linker_arg("-Bdynamic"); self.hinted_static = false; } } } -impl<'a> Linker for GnuLinker<'a> { +impl<'a> Linker for GccLinker<'a> { fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); } fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } @@ -164,27 +197,26 @@ impl<'a> Linker for GnuLinker<'a> { self.hint_static(); let target = &self.sess.target.target; if !target.options.is_like_osx { - self.cmd.arg("-Wl,--whole-archive") - .arg("-l").arg(lib) - .arg("-Wl,--no-whole-archive"); + self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib); + self.linker_arg("--no-whole-archive"); } else { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. - let mut v = OsString::from("-Wl,-force_load,"); + let mut v = OsString::from("-force_load,"); v.push(&archive::find_library(lib, search_path, &self.sess)); - self.cmd.arg(&v); + self.linker_arg(&v); } } fn link_whole_rlib(&mut self, lib: &Path) { self.hint_static(); if self.sess.target.target.options.is_like_osx { - let mut v = OsString::from("-Wl,-force_load,"); + let mut v = OsString::from("-force_load,"); v.push(lib); - self.cmd.arg(&v); + self.linker_arg(&v); } else { - self.cmd.arg("-Wl,--whole-archive").arg(lib) - .arg("-Wl,--no-whole-archive"); + self.linker_arg("--whole-archive").cmd.arg(lib); + self.linker_arg("--no-whole-archive"); } } @@ -204,10 +236,10 @@ impl<'a> Linker for GnuLinker<'a> { // for partial linking when using multiple codegen units (-r). So we // insert it here. if self.sess.target.target.options.is_like_osx { - self.cmd.arg("-Wl,-dead_strip"); + self.linker_arg("-dead_strip"); } else if self.sess.target.target.options.is_like_solaris { - self.cmd.arg("-Wl,-z"); - self.cmd.arg("-Wl,ignore"); + self.linker_arg("-z"); + self.linker_arg("ignore"); // If we're building a dylib, we don't use --gc-sections because LLVM // has already done the best it can do, and we also don't want to @@ -215,7 +247,7 @@ impl<'a> Linker for GnuLinker<'a> { // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. } else if !keep_metadata { - self.cmd.arg("-Wl,--gc-sections"); + self.linker_arg("--gc-sections"); } } @@ -226,7 +258,7 @@ impl<'a> Linker for GnuLinker<'a> { // need a numeric argument, but other linkers do. if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.cmd.arg("-Wl,-O1"); + self.linker_arg("-O1"); } } @@ -235,13 +267,16 @@ impl<'a> Linker for GnuLinker<'a> { } fn no_default_libraries(&mut self) { - self.cmd.arg("-nodefaultlibs"); + if !self.is_ld { + self.cmd.arg("-nodefaultlibs"); + } } fn build_dylib(&mut self, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.target.options.is_like_osx { - self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]); + self.cmd.arg("-dynamiclib"); + self.linker_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack // purely to support rustbuild right now, we should get a more @@ -249,9 +284,9 @@ impl<'a> Linker for GnuLinker<'a> { // the right `-Wl,-install_name` with an `@rpath` in it. if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { - let mut v = OsString::from("-Wl,-install_name,@rpath/"); + let mut v = OsString::from("-install_name,@rpath/"); v.push(out_filename.file_name().unwrap()); - self.cmd.arg(&v); + self.linker_arg(&v); } } else { self.cmd.arg("-shared"); @@ -307,11 +342,20 @@ impl<'a> Linker for GnuLinker<'a> { } if self.sess.target.target.options.is_like_osx { - arg.push("-Wl,-exported_symbols_list,"); + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("-exported_symbols_list,"); } else if self.sess.target.target.options.is_like_solaris { - arg.push("-Wl,-M,"); + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("-M,"); } else { - arg.push("-Wl,--version-script="); + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("--version-script="); } arg.push(&path); @@ -319,7 +363,7 @@ impl<'a> Linker for GnuLinker<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); + self.cmd.arg(&format!("--subsystem,{}", subsystem)); } fn finalize(&mut self) -> Command { diff --git a/src/test/run-make/target-specs/my-awesome-platform.json b/src/test/run-make/target-specs/my-awesome-platform.json index b7083c2776aec..14515ad7f00b9 100644 --- a/src/test/run-make/target-specs/my-awesome-platform.json +++ b/src/test/run-make/target-specs/my-awesome-platform.json @@ -1,5 +1,6 @@ { "data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128", + "linker-flavor": "gcc", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "32", diff --git a/src/test/run-make/target-specs/my-incomplete-platform.json b/src/test/run-make/target-specs/my-incomplete-platform.json index 053f2dd63358a..74787b28d2233 100644 --- a/src/test/run-make/target-specs/my-incomplete-platform.json +++ b/src/test/run-make/target-specs/my-incomplete-platform.json @@ -1,5 +1,6 @@ { "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32", + "linker-flavor": "gcc", "target-endian": "little", "target-pointer-width": "32", "arch": "x86", diff --git a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json index 688bbe46bfaf0..cfe152f9e8728 100644 --- a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json +++ b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json @@ -1,6 +1,7 @@ { "pre-link-args": ["-m64"], "data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128", + "linker-flavor": "gcc", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "64", From 95bb45431ade3995b5936f522de131453326f2c1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 20:39:10 -0500 Subject: [PATCH 567/662] remove workaround for rust-lang/rust#39880 committed by mistake --- src/librustc_llvm/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 6e34f551f5df7..f300bf16145a7 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -422,4 +422,3 @@ impl Drop for OperandBundleDef { } } } -#[link(name = "ffi")] extern {} From 2a177b7715043cffd27912dde2db07af562295c3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 22:36:30 -0500 Subject: [PATCH 568/662] add some documentation to the unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/linker-flavor.md | 61 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/doc/unstable-book/src/linker-flavor.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 20812de524add..65b448c9a78b2 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -106,6 +106,7 @@ - [link_llvm_intrinsics](link-llvm-intrinsics.md) - [linkage](linkage.md) - [linked_list_extras](linked-list-extras.md) +- [linker-flavor](linker-flavor.md) - [log_syntax](log-syntax.md) - [lookup_host](lookup-host.md) - [loop_break_value](loop-break-value.md) diff --git a/src/doc/unstable-book/src/linker-flavor.md b/src/doc/unstable-book/src/linker-flavor.md new file mode 100644 index 0000000000000..2e85116783494 --- /dev/null +++ b/src/doc/unstable-book/src/linker-flavor.md @@ -0,0 +1,61 @@ +# `linker-flavor` + +The tracking issue for this feature is: None + +------------------------ + +Every `rustc` target defaults to some linker. For example, Linux targets default +to gcc. In some cases, you may want to override the default; you can do that +with the unstable CLI argument: `-Z linker-flavor`. + +Here how you would use this flag to link a Rust binary for the +`thumbv7m-none-eabi` using LLD instead of GCC. + +``` text +$ xargo rustc --target thumbv7m-none-eabi -- \ + -C linker=ld.lld \ + -Z linker-flavor=ld \ + -Z print-link-args | tr ' ' '\n' +"ld.lld" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c.0.o" +"-o" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c" +"--gc-sections" +"-L" +"$PWD/target/thumbv7m-none-eabi/debug/deps" +"-L" +"$PWD/target/debug/deps" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"-Bstatic" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib" +"-Bdynamic" +``` + +Whereas the default is: + +``` +$ xargo rustc --target thumbv7m-none-eabi -- \ + -C link-arg=-nostartfiles \ + -Z print-link-args | tr ' ' '\n' +"arm-none-eabi-gcc" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9.0.o" +"-o" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9" +"-Wl,--gc-sections" +"-nodefaultlibs" +"-L" +"$PWD/target/thumbv7m-none-eabi/debug/deps" +"-L" +"$PWD/target/debug/deps" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"-Wl,-Bstatic" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib" +"-nostartfiles" +"-Wl,-Bdynamic" +``` From e280515499dd24dcfbfe9455806f328b879b243d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 10:51:36 -0500 Subject: [PATCH 569/662] hack: add a linker_flavor feature gate to make tidy accept `-Z linker-flavor` documentation --- src/doc/unstable-book/src/SUMMARY.md | 2 +- src/libsyntax/feature_gate.rs | 3 +++ src/test/compile-fail/feature-gate-linker-flavor.rs | 13 +++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/feature-gate-linker-flavor.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 65b448c9a78b2..e30848f20fdf6 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -106,7 +106,7 @@ - [link_llvm_intrinsics](link-llvm-intrinsics.md) - [linkage](linkage.md) - [linked_list_extras](linked-list-extras.md) -- [linker-flavor](linker-flavor.md) +- [linker_flavor](linker-flavor.md) - [log_syntax](log-syntax.md) - [lookup_host](lookup-host.md) - [loop_break_value](loop-break-value.md) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 550f1160bed85..2b3d3c0febc44 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -343,6 +343,9 @@ declare_features! ( // Used to preserve symbols (see llvm.used) (active, used, "1.18.0", Some(40289)), + + // Hack to document `-Z linker-flavor` in The Unstable Book + (active, linker_flavor, "1.18.0", Some(41142)), ); declare_features! ( diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs new file mode 100644 index 0000000000000..099d488376e7c --- /dev/null +++ b/src/test/compile-fail/feature-gate-linker-flavor.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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. + +#![linker_flavor] //~ ERROR the `#[linker_flavor]` attribute is + +fn main() {} From f7ffe5bd2499663026787f91f60e3e3ecf946a03 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 7 Apr 2017 18:04:15 +0200 Subject: [PATCH 570/662] Replace compare_exchange with swap --- src/libcore/sync/atomic.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index dd0069502dee7..a4050f271eb99 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -539,20 +539,15 @@ impl AtomicBool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done // with an 8-bit integer internally, which would set the upper 7 bits. - // So we just use fetch_xor or compare_exchange instead. + // So we just use fetch_xor or swap instead. if val { // !(x & true) == !x // We must invert the bool. self.fetch_xor(true, order) } else { // !(x & false) == true - // We must set the bool to true. Instead of delegating to swap or fetch_or, use - // compare_exchange instead in order to avoid unnecessary writes to memory, which - // might minimize cache-coherence traffic. - match self.compare_exchange(false, true, order, Ordering::Relaxed) { - Ok(_) => false, - Err(_) => true, - } + // We must set the bool to true. + self.swap(true, order) } } From bfc08c13ccf9a88159a634bf0a19bf271d341c48 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 7 Apr 2017 20:47:22 +0200 Subject: [PATCH 571/662] pub(restricted) didn't make it into 1.17 Gets shipped in 1.18 instead. --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 550f1160bed85..c68e2ae34687b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -408,7 +408,7 @@ declare_features! ( // Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719)), // pub(restricted) visibilities (RFC 1422) - (accepted, pub_restricted, "1.17.0", Some(32409)), + (accepted, pub_restricted, "1.18.0", Some(32409)), // The #![windows_subsystem] attribute (accepted, windows_subsystem, "1.18.0", Some(37499)), ); From bd4f3815eb3f6339f6f0a97894e8b1766df25ea0 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Fri, 7 Apr 2017 19:55:52 +0100 Subject: [PATCH 572/662] Disable errexit for sanity checking git repo --- src/ci/init_repo.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index c235681cddd0c..633b88dd2c42f 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -41,8 +41,10 @@ if [ ! -f "$cache_valid_file" ]; then rm -rf "$CACHE_DIR" mkdir "$CACHE_DIR" else + set +o errexit stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) - stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1 && echo $?) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1; echo $?) + set -o errexit if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then # Something is badly wrong - the cache valid file is here, but something # about the git repo is fishy. Nuke it all, just in case From 68909b0ec0d8738a8f1a0bb7a80998a246943471 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 5 Apr 2017 17:13:46 -0400 Subject: [PATCH 573/662] Add as_c_str. --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/as-c-str.md | 8 ++++++++ src/libstd/ffi/c_str.rs | 6 ++++++ 3 files changed, 15 insertions(+) create mode 100644 src/doc/unstable-book/src/as-c-str.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4e5..1f2ef3669b84e 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -12,6 +12,7 @@ - [alloc_system](alloc-system.md) - [allocator](allocator.md) - [allow_internal_unstable](allow-internal-unstable.md) +- [as_c_str](as-c-str.md) - [as_unsafe_cell](as-unsafe-cell.md) - [ascii_ctype](ascii-ctype.md) - [asm](asm.md) diff --git a/src/doc/unstable-book/src/as-c-str.md b/src/doc/unstable-book/src/as-c-str.md new file mode 100644 index 0000000000000..ed32eedb3481e --- /dev/null +++ b/src/doc/unstable-book/src/as-c-str.md @@ -0,0 +1,8 @@ +# `as_c_str` + +The tracking issue for this feature is: [#40380] + +[#40380]: https://github.com/rust-lang/rust/issues/40380 + +------------------------ + diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2d14bb66bf4f9..d157d52259d2e 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -324,6 +324,12 @@ impl CString { &self.inner } + /// Extracts a `CStr` slice containing the entire string. + #[unstable(feature = "as_c_str", issue = "40380")] + pub fn as_c_str(&self) -> &CStr { + &*self + } + /// Converts this `CString` into a boxed `CStr`. #[unstable(feature = "into_boxed_c_str", issue = "40380")] pub fn into_boxed_c_str(self) -> Box { From 9765fbc8130bb7dcd14e1ebc64c0b797840ca488 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Fri, 7 Apr 2017 16:42:56 -0400 Subject: [PATCH 574/662] fix build errors --- src/libstd/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b5a4cabafdce5..d6f7f58a97893 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -96,11 +96,12 @@ //! //! # Contributing changes to the documentation //! -//! Check out the rust contribution guidelines [here](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). +//! Check out the rust contribution guidelines [here]( +//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). //! The source for this documentation can be found on [Github](https://github.com/rust-lang). //! To contribute changes, make sure you read the guidelines first, then submit //! pull-requests for your suggested changes. -//! +//! //! Contributions are appreciated! If you see a part of the docs that can be //! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs. //! From 5c0c3e803d6070cc4d1ce0362e0ae3bae4962720 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 7 Apr 2017 17:16:52 -0700 Subject: [PATCH 575/662] bootstrap.py: fix armv7 detection This matches the logic that was in `./configure` before f8ca805422db8. --- src/bootstrap/bootstrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e7f..4b0491f8bd099 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -463,10 +463,10 @@ def build_triple(self): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype in {'armv6l', 'armv7l', 'armv8l'}: + elif cputype == 'armv6l': cputype = 'arm' ostype += 'eabihf' - elif cputype == 'armv7l': + elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' ostype += 'eabihf' elif cputype == 'aarch64': From 2b2eeda0831401935a45c70667cf4c3eaedafe7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 7 Apr 2017 16:08:07 -0700 Subject: [PATCH 576/662] Move tests from ui to cfail --- src/test/compile-fail/issue-35675.rs | 67 +++++++++++++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ------------ src/test/ui/did_you_mean/issue-35675.stderr | 74 --------------------- 3 files changed, 67 insertions(+), 118 deletions(-) create mode 100644 src/test/compile-fail/issue-35675.rs delete mode 100644 src/test/ui/did_you_mean/issue-35675.rs delete mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/test/compile-fail/issue-35675.rs b/src/test/compile-fail/issue-35675.rs new file mode 100644 index 0000000000000..f990c2c42fe14 --- /dev/null +++ b/src/test/compile-fail/issue-35675.rs @@ -0,0 +1,67 @@ +// Copyright 2017 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. + +enum Fruit { + Apple(i64), + //~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + //~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + Orange(i64), +} + +fn should_return_fruit() -> Apple { + //~^ ERROR cannot find type `Apple` in this scope + //~| NOTE not found in this scope + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn should_return_fruit_too() -> Fruit::Apple { + //~^ ERROR expected type, found variant `Fruit::Apple` + //~| NOTE not a type + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn foo() -> Ok { + //~^ ERROR expected type, found variant `Ok` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Ok(()) +} + +fn bar() -> Variant3 { + //~^ ERROR cannot find type `Variant3` in this scope + //~| NOTE not found in this scope +} + +fn qux() -> Some { + //~^ ERROR expected type, found variant `Some` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + //~^ HELP there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs deleted file mode 100644 index ff29f3ad4078b..0000000000000 --- a/src/test/ui/did_you_mean/issue-35675.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 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. - -enum Fruit { - Apple(i64), - Orange(i64), -} - -fn should_return_fruit() -> Apple { - Apple(5) -} - -fn should_return_fruit_too() -> Fruit::Apple { - Apple(5) -} - -fn foo() -> Ok { - Ok(()) -} - -fn bar() -> Variant3 { -} - -fn qux() -> Some { - Some(1) -} - -fn main() {} - -mod x { - enum Enum { - Variant1, - Variant2(), - Variant3(usize), - Variant4 {}, - } -} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr deleted file mode 100644 index 3d615785b25fa..0000000000000 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0412]: cannot find type `Apple` in this scope - --> $DIR/issue-35675.rs:16:29 - | -16 | fn should_return_fruit() -> Apple { - | ^^^^^ not found in this scope - | -help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? - --> $DIR/issue-35675.rs:12:5 - | -12 | Apple(i64), - | ^^^^^^^^^^ - -error[E0425]: cannot find function `Apple` in this scope - --> $DIR/issue-35675.rs:17:5 - | -17 | Apple(5) - | ^^^^^ not found in this scope - | - = help: possible candidate is found in another module, you can import it into scope: - `use Fruit::Apple;` - -error[E0573]: expected type, found variant `Fruit::Apple` - --> $DIR/issue-35675.rs:20:33 - | -20 | fn should_return_fruit_too() -> Fruit::Apple { - | ^^^^^^^^^^^^ not a type - | -help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? - --> $DIR/issue-35675.rs:12:5 - | -12 | Apple(i64), - | ^^^^^^^^^^ - -error[E0425]: cannot find function `Apple` in this scope - --> $DIR/issue-35675.rs:21:5 - | -21 | Apple(5) - | ^^^^^ not found in this scope - | - = help: possible candidate is found in another module, you can import it into scope: - `use Fruit::Apple;` - -error[E0573]: expected type, found variant `Ok` - --> $DIR/issue-35675.rs:24:13 - | -24 | fn foo() -> Ok { - | ^^ not a type - | - = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? - = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? - -error[E0412]: cannot find type `Variant3` in this scope - --> $DIR/issue-35675.rs:28:13 - | -28 | fn bar() -> Variant3 { - | ^^^^^^^^ not found in this scope - | -help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? - --> $DIR/issue-35675.rs:41:9 - | -41 | Variant3(usize), - | ^^^^^^^^^^^^^^^ - -error[E0573]: expected type, found variant `Some` - --> $DIR/issue-35675.rs:31:13 - | -31 | fn qux() -> Some { - | ^^^^ not a type - | - = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? - -error: aborting due to 7 previous errors - From 5d2f270395814564f674141a99ace77ea9a03352 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 8 Apr 2017 03:43:18 +0200 Subject: [PATCH 577/662] slice: Implement .rfind() for slice iterators Iter and IterMut Just like the forward case find, implement rfind explicitly --- src/libcore/slice/mod.rs | 13 +++++++++++++ src/libcore/tests/lib.rs | 1 + src/libcore/tests/slice.rs | 13 +++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6d598677c9ba4..87dfdfe57b65c 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1190,6 +1190,19 @@ macro_rules! iterator { } } } + + fn rfind(&mut self, mut predicate: F) -> Option + where F: FnMut(&Self::Item) -> bool, + { + self.rsearch_while(None, move |elt| { + if predicate(&elt) { + SearchWhile::Done(Some(elt)) + } else { + SearchWhile::Continue + } + }) + } + } // search_while is a generalization of the internal iteration methods. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index d92c378160d2e..528ab3bc84523 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(iter_rfind)] #![feature(libc)] #![feature(nonzero)] #![feature(rand)] diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index ec38345030fa5..15047204e50d6 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -225,6 +225,19 @@ fn get_unchecked_mut_range() { } } +#[test] +fn test_find_rfind() { + let v = [0, 1, 2, 3, 4, 5]; + let mut iter = v.iter(); + let mut i = v.len(); + while let Some(&elt) = iter.rfind(|_| true) { + i -= 1; + assert_eq!(elt, v[i]); + } + assert_eq!(i, 0); + assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3)); +} + #[test] fn sort_unstable() { let mut v = [0; 600]; From f76a3036ef2379e26f1a3777ba032f025f22d5cf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 21:47:58 -0500 Subject: [PATCH 578/662] fake the feature-gate-linker-flavor compile fail test as there's no way to generate a `#![feature(linker_flavor)]` error --- src/test/compile-fail/feature-gate-linker-flavor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs index 099d488376e7c..68679d7dac896 100644 --- a/src/test/compile-fail/feature-gate-linker-flavor.rs +++ b/src/test/compile-fail/feature-gate-linker-flavor.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![linker_flavor] //~ ERROR the `#[linker_flavor]` attribute is +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature fn main() {} From aeab73c9388effe1295cd9c844393613633f5f5b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 8 Apr 2017 17:53:16 +0300 Subject: [PATCH 579/662] Specify type libraries for llvm-config --ldflags This matters on systems where static libraries and dynamic libraries reside in different location --- src/librustc_llvm/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 7d5887e699fd7..a8def4bafd864 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -217,6 +217,9 @@ fn main() { // hack around this by replacing the host triple with the target and pray // that those -L directories are the same! let mut cmd = Command::new(&llvm_config); + if let Some(link_arg) = llvm_link_arg { + cmd.arg(link_arg); + } cmd.arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { if lib.starts_with("-LIBPATH:") { From f093d59c31bd2064328e24d0ec76e0d105fc32fc Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 8 Apr 2017 14:03:17 -0400 Subject: [PATCH 580/662] Address @parched's comments --- src/doc/unstable-book/src/compiler-barriers.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 9e137a5c4f878..827447f0bd510 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -22,8 +22,9 @@ compiler is allowed to do. Specifically, depending on the given ordering semantics, the compiler may be disallowed from moving reads or writes from before or after the call to the other side of the call to `compiler_barrier`. Note that it does **not** prevent the *hardware* -from doing such re-orderings -- for that, the `volatile_*` class of -functions, or full memory fences, need to be used. +from doing such re-ordering. This is not a problem in a single-threaded, +execution context, but when other threads may modify memory at the same +time, stronger synchronization primitives are required. ## Examples @@ -92,12 +93,6 @@ fn signal_handler() { } ``` -In more advanced cases (for example, if `IMPORTANT_VARIABLE` was an -`AtomicPtr` that starts as `NULL`), it may also be unsafe for the -compiler to hoist code using `IMPORTANT_VARIABLE` above the -`IS_READY.load`. In that case, a `compiler_barrier(Ordering::Acquire)` -should be placed at the top of the `if` to prevent this optimizations. - A deeper discussion of compiler barriers with various re-ordering semantics (such as `Ordering::SeqCst`) is beyond the scope of this text. Curious readers are encouraged to read the Linux kernel's discussion of From 28a232a59ac4ded4e6de9e9c06a17a801c5199dd Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 3 Apr 2017 23:32:59 -0400 Subject: [PATCH 581/662] Adding links around Sender/SyncSender/Receiver errors; Adding more documentation to channel() and sync_channel(); adding more links #29377 --- src/libstd/sync/mpsc/mod.rs | 134 ++++++++++++++++++++------------ src/libstd/sys_common/poison.rs | 4 +- 2 files changed, 87 insertions(+), 51 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 0da65a4f2e12f..852675edc0238 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -436,81 +436,97 @@ unsafe impl Send for SyncSender {} #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for SyncSender {} -/// An error returned from the [`send`] function on channels. +/// An error returned from the [`Sender::send`] or [`SyncSender::send`] +/// function on **channel**s. /// -/// A [`send`] operation can only fail if the receiving end of a channel is +/// A **send** operation can only fail if the receiving end of a channel is /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`Sender::send`]: struct.Sender.html#method.send +/// [`SyncSender::send`]: struct.SyncSender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); /// An error returned from the [`recv`] function on a [`Receiver`]. /// -/// The [`recv`] operation can only fail if the sending half of a channel is -/// disconnected, implying that no further messages will ever be received. +/// The [`recv`] operation can only fail if the sending half of a +/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further +/// messages will ever be received. /// -/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// [`recv`]: struct.Receiver.html#method.recv +/// [`Receiver`]: struct.Receiver.html +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; /// This enumeration is the list of the possible reasons that [`try_recv`] could -/// not return data when called. +/// not return data when called. This can occur with both a [`channel`] and +/// a [`sync_channel`]. /// -/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv +/// [`try_recv`]: struct.Receiver.html#method.try_recv +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { - /// This channel is currently empty, but the sender(s) have not yet + /// This **channel** is currently empty, but the **Sender**(s) have not yet /// disconnected, so data may yet become available. #[stable(feature = "rust1", since = "1.0.0")] Empty, - /// This channel's sending half has become disconnected, and there will - /// never be any more data received on this channel + /// The **channel**'s sending half has become disconnected, and there will + /// never be any more data received on it. #[stable(feature = "rust1", since = "1.0.0")] Disconnected, } -/// This enumeration is the list of possible errors that [`recv_timeout`] could -/// not return data when called. +/// This enumeration is the list of possible errors that made [`recv_timeout`] +/// unable to return data when called. This can occur with both a [`channel`] and +/// a [`sync_channel`]. /// -/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout +/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { - /// This channel is currently empty, but the sender(s) have not yet + /// This **channel** is currently empty, but the **Sender**(s) have not yet /// disconnected, so data may yet become available. #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Timeout, - /// This channel's sending half has become disconnected, and there will - /// never be any more data received on this channel + /// The **channel**'s sending half has become disconnected, and there will + /// never be any more data received on it. #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Disconnected, } /// This enumeration is the list of the possible error outcomes for the -/// [`SyncSender::try_send`] method. +/// [`try_send`] method. /// -/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send +/// [`try_send`]: struct.SyncSender.html#method.try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError { - /// The data could not be sent on the channel because it would require that + /// The data could not be sent on the [`sync_channel`] because it would require that /// the callee block to send the data. /// /// If this is a buffered channel, then the buffer is full at this time. If - /// this is not a buffered channel, then there is no receiver available to + /// this is not a buffered channel, then there is no [`Receiver`] available to /// acquire the data. + /// + /// [`sync_channel`]: fn.sync_channel.html + /// [`Receiver`]: struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] Full(#[stable(feature = "rust1", since = "1.0.0")] T), - /// This channel's receiving half has disconnected, so the data could not be + /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be /// sent. The data is returned back to the callee in this case. + /// + /// [`sync_channel`]: fn.sync_channel.html #[stable(feature = "rust1", since = "1.0.0")] Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T), } @@ -544,15 +560,27 @@ impl UnsafeFlavor for Receiver { } /// Creates a new asynchronous channel, returning the sender/receiver halves. -/// All data sent on the sender will become available on the receiver, and no -/// send will block the calling thread (this channel has an "infinite buffer"). +/// All data sent on the [`Sender`] will become available on the [`Receiver`] in +/// the same order as it was sent, and no [`send`] will block the calling thread +/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will +/// block after its buffer limit is reached). [`recv`] will block until a message +/// is available. +/// +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but +/// only one [`Receiver`] is supported. /// /// If the [`Receiver`] is disconnected while trying to [`send`] with the -/// [`Sender`], the [`send`] method will return an error. +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the +/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will +/// return a [`RecvError`]. /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// [`send`]: struct.Sender.html#method.send +/// [`recv`]: struct.Receiver.html#method.recv +/// [`Sender`]: struct.Sender.html +/// [`Receiver`]: struct.Receiver.html +/// [`sync_channel`]: fn.sync_channel.html +/// [`SendError`]: struct.SendError.html +/// [`RecvError`]: struct.RecvError.html /// /// # Examples /// @@ -560,20 +588,18 @@ impl UnsafeFlavor for Receiver { /// use std::sync::mpsc::channel; /// use std::thread; /// -/// // tx is the sending half (tx for transmission), and rx is the receiving -/// // half (rx for receiving). -/// let (tx, rx) = channel(); +/// let (sender, receiver) = channel(); /// /// // Spawn off an expensive computation /// thread::spawn(move|| { /// # fn expensive_computation() {} -/// tx.send(expensive_computation()).unwrap(); +/// sender.send(expensive_computation()).unwrap(); /// }); /// /// // Do some useful work for awhile /// /// // Let's see what that answer was -/// println!("{:?}", rx.recv().unwrap()); +/// println!("{:?}", receiver.recv().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn channel() -> (Sender, Receiver) { @@ -582,24 +608,32 @@ pub fn channel() -> (Sender, Receiver) { } /// Creates a new synchronous, bounded channel. -/// -/// Like asynchronous channels, the [`Receiver`] will block until a message -/// becomes available. These channels differ greatly in the semantics of the -/// sender from asynchronous channels, however. +/// All data sent on the [`SyncSender`] will become available on the [`Receiver`] +/// in the same order as it was sent. Like asynchronous [`channel`]s, the +/// [`Receiver`] will block until a message becomes available. `sync_channel` +/// differs greatly in the semantics of the sender, however. /// /// This channel has an internal buffer on which messages will be queued. /// `bound` specifies the buffer size. When the internal buffer becomes full, /// future sends will *block* waiting for the buffer to open up. Note that a /// buffer size of 0 is valid, in which case this becomes "rendezvous channel" -/// where each [`send`] will not return until a recv is paired with it. +/// where each [`send`] will not return until a [`recv`] is paired with it. +/// +/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple +/// times, but only one [`Receiver`] is supported. /// -/// Like asynchronous channels, if the [`Receiver`] is disconnected while -/// trying to [`send`] with the [`SyncSender`], the [`send`] method will -/// return an error. +/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying +/// to [`send`] with the [`SyncSender`], the [`send`] method will return a +/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying +/// to [`recv`], the [`recv`] method will return a [`RecvError`]. /// -/// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send -/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// [`channel`]: fn.channel.html +/// [`send`]: struct.SyncSender.html#method.send +/// [`recv`]: struct.Receiver.html#method.recv +/// [`SyncSender`]: struct.SyncSender.html +/// [`Receiver`]: struct.Receiver.html +/// [`SendError`]: struct.SendError.html +/// [`RecvError`]: struct.RecvError.html /// /// # Examples /// @@ -607,18 +641,18 @@ pub fn channel() -> (Sender, Receiver) { /// use std::sync::mpsc::sync_channel; /// use std::thread; /// -/// let (tx, rx) = sync_channel(1); +/// let (sender, receiver) = sync_channel(1); /// /// // this returns immediately -/// tx.send(1).unwrap(); +/// sender.send(1).unwrap(); /// /// thread::spawn(move|| { /// // this will block until the previous message has been received -/// tx.send(2).unwrap(); +/// sender.send(2).unwrap(); /// }); /// -/// assert_eq!(rx.recv().unwrap(), 1); -/// assert_eq!(rx.recv().unwrap(), 2); +/// assert_eq!(receiver.recv().unwrap(), 1); +/// assert_eq!(receiver.recv().unwrap(), 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index d9d13240fcc3a..0127a9eb75969 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -73,7 +73,9 @@ pub struct PoisonError { } /// An enumeration of possible errors which can occur while calling the -/// `try_lock` method. +/// [`try_lock`] method. +/// +/// [`try_lock`]: struct.Mutex.html#method.try_lock #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError { /// The lock could not be acquired because another thread failed while holding From 69797986879f12db067f5cd8fb89c193548b04f5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 7 Apr 2017 01:00:53 +0300 Subject: [PATCH 582/662] borrowck::mir::dataflow: ignore unwind edges of empty drops This avoids creating drop flags in many unnecessary situations. Fixes #41110. --- .../borrowck/mir/dataflow/mod.rs | 11 +- .../borrowck/mir/elaborate_drops.rs | 113 +++++++++++++----- src/librustc_borrowck/borrowck/mir/mod.rs | 35 +++++- src/test/mir-opt/issue-41110.rs | 53 ++++++++ 4 files changed, 174 insertions(+), 38 deletions(-) create mode 100644 src/test/mir-opt/issue-41110.rs diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 8b246105f6169..f0f082a2561cc 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -181,6 +181,7 @@ pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation { flow_state: DataflowState, + dead_unwinds: &'a IdxSet, mir: &'a Mir<'tcx>, } @@ -377,6 +378,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, + dead_unwinds: &'a IdxSet, denotation: D) -> Self { let bits_per_block = denotation.bits_per_block(); let usize_bits = mem::size_of::() * 8; @@ -397,6 +399,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> DataflowAnalysis { mir: mir, + dead_unwinds: dead_unwinds, flow_state: DataflowState { sets: AllSets { bits_per_block: bits_per_block, @@ -452,7 +455,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> ref target, value: _, location: _, unwind: Some(ref unwind) } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + if !self.dead_unwinds.contains(&bb) { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } } mir::TerminatorKind::SwitchInt { ref targets, .. } => { for target in targets { @@ -461,7 +466,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } mir::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { if let Some(ref unwind) = *cleanup { - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + if !self.dead_unwinds.contains(&bb) { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } } if let Some((ref dest_lval, ref dest_bb)) = *destination { // N.B.: This must be done *last*, after all other diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 88ec86cc95d61..713e656666271 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -11,8 +11,8 @@ use super::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; -use super::{drop_flag_effects_for_location, on_all_children_bits}; -use super::on_lookup_result_bits; +use super::{on_all_children_bits, on_all_drop_children_bits}; +use super::{drop_flag_effects_for_location, on_lookup_result_bits}; use super::MoveDataParamEnv; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; @@ -24,6 +24,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_mir::util::patch::MirPatch; use rustc_mir::util::elaborate_drops::{DropFlagState, elaborate_drop}; use rustc_mir::util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode}; +use syntax::ast; use syntax_pos::Span; use std::fmt; @@ -49,12 +50,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { move_data: move_data, param_env: param_env }; + let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env); let flow_inits = - super::do_dataflow(tcx, mir, id, &[], + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, MaybeInitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); let flow_uninits = - super::do_dataflow(tcx, mir, id, &[], + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, MaybeUninitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); @@ -74,6 +76,67 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { impl Pass for ElaborateDrops {} +/// Return the set of basic blocks whose unwind edges are known +/// to not be reachable, because they are `drop` terminators +/// that can't drop anything. +fn find_dead_unwinds<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + id: ast::NodeId, + env: &MoveDataParamEnv<'tcx>) + -> IdxSetBuf +{ + debug!("find_dead_unwinds({:?})", mir.span); + // We only need to do this pass once, because unwind edges can only + // reach cleanup blocks, which can't have unwind edges themselves. + let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); + let flow_inits = + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &env), + |bd, p| &bd.move_data().move_paths[p]); + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + match bb_data.terminator().kind { + TerminatorKind::Drop { ref location, unwind: Some(_), .. } | + TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => { + let mut init_data = InitializationData { + live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), + dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()), + }; + debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", + bb, bb_data, init_data.live); + for stmt in 0..bb_data.statements.len() { + let loc = Location { block: bb, statement_index: stmt }; + init_data.apply_location(tcx, mir, env, loc); + } + + let path = match env.move_data.rev_lookup.find(location) { + LookupResult::Exact(e) => e, + LookupResult::Parent(..) => { + debug!("find_dead_unwinds: has parent; skipping"); + continue + } + }; + + debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); + + let mut maybe_live = false; + on_all_drop_children_bits(tcx, mir, &env, path, |child| { + let (child_maybe_live, _) = init_data.state(child); + maybe_live |= child_maybe_live; + }); + + debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); + if !maybe_live { + dead_unwinds.add(&bb); + } + } + _ => {} + } + } + + dead_unwinds +} + struct InitializationData { live: IdxSetBuf, dead: IdxSetBuf @@ -144,17 +207,14 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { let mut some_live = false; let mut some_dead = false; let mut children_count = 0; - on_all_children_bits( - self.tcx(), self.mir(), self.ctxt.move_data(), - path, |child| { - if self.ctxt.path_needs_drop(child) { - let (live, dead) = self.init_data.state(child); - debug!("elaborate_drop: state({:?}) = {:?}", - child, (live, dead)); - some_live |= live; - some_dead |= dead; - children_count += 1; - } + on_all_drop_children_bits( + self.tcx(), self.mir(), self.ctxt.env, path, |child| { + let (live, dead) = self.init_data.state(child); + debug!("elaborate_drop: state({:?}) = {:?}", + child, (live, dead)); + some_live |= live; + some_dead |= dead; + children_count += 1; }); ((some_live, some_dead), children_count != 1) } @@ -276,15 +336,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.patch } - fn path_needs_drop(&self, path: MovePathIndex) -> bool - { - let lvalue = &self.move_data().move_paths[path].lvalue; - let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); - - self.tcx.type_needs_drop_given_env(ty, self.param_env()) - } - fn collect_drop_flags(&mut self) { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { @@ -318,14 +369,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } }; - on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - if self.path_needs_drop(child) { - let (maybe_live, maybe_dead) = init_data.state(child); - debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", - child, location, path, (maybe_live, maybe_dead)); - if maybe_live && maybe_dead { - self.create_drop_flag(child) - } + on_all_drop_children_bits(self.tcx, self.mir, self.env, path, |child| { + let (maybe_live, maybe_dead) = init_data.state(child); + debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", + child, location, path, (maybe_live, maybe_dead)); + if maybe_live && maybe_dead { + self.create_drop_flag(child) } }); } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 9237bb31f6bd7..dc01cbe5e7605 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -17,6 +17,7 @@ use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, L use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc_mir::util::elaborate_drops::DropFlagState; +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; mod abs_domain; pub mod elaborate_drops; @@ -64,14 +65,18 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt, let param_env = ty::ParameterEnvironment::for_item(tcx, id); let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; + let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let flow_inits = - do_dataflow(tcx, mir, id, attributes, MaybeInitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); let flow_uninits = - do_dataflow(tcx, mir, id, attributes, MaybeUninitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + MaybeUninitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); let flow_def_inits = - do_dataflow(tcx, mir, id, attributes, DefinitelyInitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + DefinitelyInitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { @@ -108,6 +113,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, node_id: ast::NodeId, attributes: &[ast::Attribute], + dead_unwinds: &IdxSet, bd: BD, p: P) -> DataflowResults @@ -137,7 +143,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: node_id, print_preflow_to: print_preflow_to, print_postflow_to: print_postflow_to, - flow_state: DataflowAnalysis::new(tcx, mir, bd), + flow_state: DataflowAnalysis::new(tcx, mir, dead_unwinds, bd), }; mbcx.dataflow(p); @@ -303,6 +309,27 @@ fn on_all_children_bits<'a, 'tcx, F>( on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child); } +fn on_all_drop_children_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + path: MovePathIndex, + mut each_child: F) + where F: FnMut(MovePathIndex) +{ + on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { + let lvalue = &ctxt.move_data.move_paths[path].lvalue; + let ty = lvalue.ty(mir, tcx).to_ty(tcx); + debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); + + if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) { + each_child(child); + } else { + debug!("on_all_drop_children_bits - skipping") + } + }) +} + fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs new file mode 100644 index 0000000000000..fec635b3abf60 --- /dev/null +++ b/src/test/mir-opt/issue-41110.rs @@ -0,0 +1,53 @@ +// Copyright 2017 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 don't emit multiple drop flags when they are not needed. + +fn main() { + let x = S.other(S.id()); +} + +pub fn test() { + let u = S; + let mut v = S; + drop(v); + v = u; +} + +struct S; +impl Drop for S { + fn drop(&mut self) { + } +} + +impl S { + fn id(self) -> Self { self } + fn other(self, s: Self) {} +} + +// END RUST SOURCE +// START rustc.node4.ElaborateDrops.after.mir +// let mut _2: S; +// let mut _3: (); +// let mut _4: S; +// let mut _5: S; +// let mut _6: bool; +// +// bb0: { +// END rustc.node4.ElaborateDrops.after.mir +// START rustc.node13.ElaborateDrops.after.mir +// let mut _2: (); +// let mut _4: (); +// let mut _5: S; +// let mut _6: S; +// let mut _7: bool; +// +// bb0: { +// END rustc.node13.ElaborateDrops.after.mir From d94f2c928c2c41dc0efd4122157e604788141b03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 8 Apr 2017 13:10:08 -0700 Subject: [PATCH 583/662] Update cargo submodules Brings in a fix for #40955 through rust-lang/cargo#3898. Closes #40955 --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 4729175045b41..c416fb60b11ec 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 +Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 From 536011d929ecbd1170baf34e09580e567c971f95 Mon Sep 17 00:00:00 2001 From: Shiz Date: Sat, 8 Apr 2017 20:36:00 +0200 Subject: [PATCH 584/662] Fix jemalloc support for musl Just like DragonFlyBSD, using the same symbols as the system allocator will result in a segmentation fault at runtime due to allocator mismatches. As such, prefix the jemalloc symbols instead. --- src/liballoc_jemalloc/build.rs | 2 +- src/liballoc_jemalloc/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index ae040a2390659..f3a0eebe6984d 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -129,7 +129,7 @@ fn main() { // should be good to go! cmd.arg("--with-jemalloc-prefix=je_"); cmd.arg("--disable-tls"); - } else if target.contains("dragonfly") { + } else if target.contains("dragonfly") || target.contains("musl") { cmd.arg("--with-jemalloc-prefix=je_"); } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index a7a67ef76d4f7..83cc1ef09c29c 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -35,23 +35,23 @@ mod imp { // request it as unprefixing cause segfaults (mismatches in allocators). extern "C" { #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_mallocx")] fn mallocx(size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_rallocx")] fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_xallocx")] fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_sdallocx")] fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_nallocx")] fn nallocx(size: size_t, flags: c_int) -> size_t; } From 49872b859ec71e53266a717f4ec865c88e2bdefe Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 Feb 2017 17:50:28 +0200 Subject: [PATCH 585/662] rustc: add a TyLayout helper for type-related layout queries. --- src/librustc/ty/layout.rs | 244 ++++++++++++++++++++++- src/librustc_trans/context.rs | 4 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- 3 files changed, 237 insertions(+), 13 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 571ef30b6b909..8d68eff925173 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -25,6 +25,7 @@ use std::cmp; use std::fmt; use std::i64; use std::iter; +use std::ops::Deref; /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. @@ -904,7 +905,8 @@ pub enum Layout { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, align: Align, - size: Size + element_size: Size, + count: u64 }, /// TyRawPtr or TyRef with a !Sized pointee. @@ -1087,25 +1089,35 @@ impl<'a, 'gcx, 'tcx> Layout { // Arrays and slices. ty::TyArray(element, count) => { let element = element.layout(infcx)?; + let element_size = element.size(dl); + // FIXME(eddyb) Don't use host `usize` for array lengths. + let usize_count: usize = count; + let count = usize_count as u64; + if element_size.checked_mul(count, dl).is_none() { + return Err(LayoutError::SizeOverflow(ty)); + } Array { sized: true, align: element.align(dl), - size: element.size(dl).checked_mul(count as u64, dl) - .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)? + element_size: element_size, + count: count } } ty::TySlice(element) => { + let element = element.layout(infcx)?; Array { sized: false, - align: element.layout(infcx)?.align(dl), - size: Size::from_bytes(0) + align: element.align(dl), + element_size: element.size(dl), + count: 0 } } ty::TyStr => { Array { sized: false, align: dl.i8_align, - size: Size::from_bytes(0) + element_size: Size::from_bytes(1), + count: 0 } } @@ -1447,15 +1459,23 @@ impl<'a, 'gcx, 'tcx> Layout { } Vector { element, count } => { - let elem_size = element.size(dl); - let vec_size = match elem_size.checked_mul(count, dl) { + let element_size = element.size(dl); + let vec_size = match element_size.checked_mul(count, dl) { Some(size) => size, None => bug!("Layout::size({:?}): {} * {} overflowed", - self, elem_size.bytes(), count) + self, element_size.bytes(), count) }; vec_size.abi_align(self.align(dl)) } + Array { element_size, count, .. } => { + match element_size.checked_mul(count, dl) { + Some(size) => size, + None => bug!("Layout::size({:?}): {} * {} overflowed", + self, element_size.bytes(), count) + } + } + FatPointer { metadata, .. } => { // Effectively a (ptr, meta) tuple. Pointer.size(dl).abi_align(metadata.align(dl)) @@ -1464,7 +1484,7 @@ impl<'a, 'gcx, 'tcx> Layout { } CEnum { discr, .. } => Int(discr).size(dl), - Array { size, .. } | General { size, .. } => size, + General { size, .. } => size, UntaggedUnion { ref variants } => variants.stride(), Univariant { ref variant, .. } | @@ -1513,6 +1533,59 @@ impl<'a, 'gcx, 'tcx> Layout { } } } + + pub fn field_offset(&self, + dl: &TargetDataLayout, + i: usize, + variant_index: Option) + -> Size { + match *self { + Scalar { .. } | + CEnum { .. } | + UntaggedUnion { .. } | + RawNullablePointer { .. } => { + Size::from_bytes(0) + } + + Vector { element, count } => { + let element_size = element.size(dl); + let i = i as u64; + assert!(i < count); + Size::from_bytes(element_size.bytes() * count) + } + + Array { element_size, count, .. } => { + let i = i as u64; + assert!(i < count); + Size::from_bytes(element_size.bytes() * count) + } + + FatPointer { metadata, .. } => { + // Effectively a (ptr, meta) tuple. + assert!(i < 2); + if i == 0 { + Size::from_bytes(0) + } else { + Pointer.size(dl).abi_align(metadata.align(dl)) + } + } + + Univariant { ref variant, .. } => variant.offsets[i], + + General { ref variants, .. } => { + let v = variant_index.expect("variant index required"); + variants[v].offsets[i + 1] + } + + StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { + if Some(nndiscr as usize) == variant_index { + nonnull.offsets[i] + } else { + Size::from_bytes(0) + } + } + } + } } /// Type size "skeleton", i.e. the only information determining a type's size. @@ -1658,3 +1731,154 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } } + +/// A pair of a type and its layout. Implements various +/// type traversal APIs (e.g. recursing into fields). +#[derive(Copy, Clone, Debug)] +pub struct TyLayout<'tcx> { + pub ty: Ty<'tcx>, + pub layout: &'tcx Layout, + pub variant_index: Option, +} + +impl<'tcx> Deref for TyLayout<'tcx> { + type Target = Layout; + fn deref(&self) -> &Layout { + self.layout + } +} + +impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { + pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>) + -> Result> { + let ty = normalize_associated_type(infcx, ty); + + Ok(TyLayout { + ty: ty, + layout: ty.layout(infcx)?, + variant_index: None + }) + } + + pub fn for_variant(&self, variant_index: usize) -> Self { + TyLayout { + variant_index: Some(variant_index), + ..*self + } + } + + pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size { + self.layout.field_offset(dl, i, self.variant_index) + } + + pub fn field_count(&self) -> usize { + // Handle enum/union through the type rather than Layout. + if let ty::TyAdt(def, _) = self.ty.sty { + let v = self.variant_index.unwrap_or(0); + if def.variants.is_empty() { + assert_eq!(v, 0); + return 0; + } else { + return def.variants[v].fields.len(); + } + } + + match *self.layout { + Scalar { .. } => { + bug!("TyLayout::field_count({:?}): not applicable", self) + } + + // Handled above (the TyAdt case). + CEnum { .. } | + General { .. } | + UntaggedUnion { .. } | + RawNullablePointer { .. } | + StructWrappedNullablePointer { .. } => bug!(), + + FatPointer { .. } => 2, + + Vector { count, .. } | + Array { count, .. } => { + let usize_count = count as usize; + assert_eq!(usize_count as u64, count); + usize_count + } + + Univariant { ref variant, .. } => variant.offsets.len(), + } + } + + pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> { + let ptr_field_type = |pointee: Ty<'gcx>| { + let slice = |element: Ty<'gcx>| { + assert!(i < 2); + if i == 0 { + tcx.mk_mut_ptr(element) + } else { + tcx.types.usize + } + }; + match tcx.struct_tail(pointee).sty { + ty::TySlice(element) => slice(element), + ty::TyStr => slice(tcx.types.u8), + ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()), + _ => bug!("TyLayout::field_type({:?}): not applicable", self) + } + }; + + match self.ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyFnPtr(_) | + ty::TyNever | + ty::TyFnDef(..) | + ty::TyDynamic(..) => { + bug!("TyLayout::field_type({:?}): not applicable", self) + } + + // Potentially-fat pointers. + ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + ptr_field_type(pointee) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_field_type(self.ty.boxed_ty()) + } + + // Arrays and slices. + ty::TyArray(element, _) | + ty::TySlice(element) => element, + ty::TyStr => tcx.types.u8, + + // Tuples and closures. + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyTuple(tys, _) => tys[i], + + // SIMD vector types. + ty::TyAdt(def, ..) if def.repr.simd => { + self.ty.simd_type(tcx) + } + + // ADTs. + ty::TyAdt(def, substs) => { + def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs) + } + + ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | + ty::TyInfer(_) | ty::TyError => { + bug!("TyLayout::field_type: unexpected type `{}`", self.ty) + } + } + } + + pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize) + -> Result> { + TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i)) + } +} diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index afb94f546abe8..3649216eaa85e 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -828,9 +828,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { TypeOfDepthLock(self.local()) } - pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout { + pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> { self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { - ty.layout(&infcx).unwrap_or_else(|e| { + ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| { match e { ty::layout::LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 049178a2575f3..93798e7bd3330 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1564,7 +1564,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, enum_llvm_type, EnumMDF(EnumMemberDescriptionFactory { enum_type: enum_type, - type_rep: type_rep, + type_rep: type_rep.layout, discriminant_type_metadata: discriminant_type_metadata, containing_scope: containing_scope, file_metadata: file_metadata, From c977daf97cd7aa8b964b9b89e7ebd2da26022b2a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 2 Mar 2017 05:35:25 +0200 Subject: [PATCH 586/662] rustc_trans: avoid sizing_type_of everywhere possible. --- src/librustc_trans/abi.rs | 12 +++--------- src/librustc_trans/adt.rs | 20 ++++++-------------- src/librustc_trans/base.rs | 10 ++++------ src/librustc_trans/common.rs | 6 ++---- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/glue.rs | 21 +++++++-------------- src/librustc_trans/intrinsic.rs | 14 +++++++------- src/librustc_trans/meth.rs | 9 ++------- src/librustc_trans/mir/block.rs | 4 ++-- src/librustc_trans/mir/constant.rs | 17 ++++++----------- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/type_of.rs | 14 ++++++++++---- 14 files changed, 53 insertions(+), 82 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 453f65eb762f8..550f337d9b1c8 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -439,14 +439,10 @@ impl FnType { match ret_ty.sty { // These are not really pointers but pairs, (pointer, len) ty::TyRef(_, ty::TypeAndMut { ty, .. }) => { - let llty = type_of::sizing_type_of(ccx, ty); - let llsz = llsize_of_alloc(ccx, llty); - ret.attrs.set_dereferenceable(llsz); + ret.attrs.set_dereferenceable(ccx.size_of(ty)); } ty::TyAdt(def, _) if def.is_box() => { - let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty()); - let llsz = llsize_of_alloc(ccx, llty); - ret.attrs.set_dereferenceable(llsz); + ret.attrs.set_dereferenceable(ccx.size_of(ret_ty.boxed_ty())); } _ => {} } @@ -517,9 +513,7 @@ impl FnType { args.push(info); } else { if let Some(inner) = rust_ptr_attrs(ty, &mut arg) { - let llty = type_of::sizing_type_of(ccx, inner); - let llsz = llsize_of_alloc(ccx, llty); - arg.attrs.set_dereferenceable(llsz); + arg.attrs.set_dereferenceable(ccx.size_of(inner)); } args.push(arg); } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 5c1ced573402e..fb7ddd2bf4200 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -47,7 +47,7 @@ use std; use llvm::{ValueRef, True, IntEQ, IntNE}; use rustc::ty::layout; -use rustc::ty::{self, Ty, AdtKind}; +use rustc::ty::{self, Ty}; use common::*; use builder::Builder; use base; @@ -285,11 +285,6 @@ pub fn trans_get_discr<'a, 'tcx>( cast_to: Option, range_assert: bool ) -> ValueRef { - let (def, substs) = match t.sty { - ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs), - _ => bug!("{} is not an enum", t) - }; - debug!("trans_get_discr t: {:?}", t); let l = bcx.ccx.layout_of(t); @@ -297,19 +292,17 @@ pub fn trans_get_discr<'a, 'tcx>( layout::CEnum { discr, min, max, .. } => { load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert) } - layout::General { discr, .. } => { + layout::General { discr, ref variants, .. } => { let ptr = bcx.struct_gep(scrutinee, 0); load_discr(bcx, discr, ptr, alignment, - 0, def.variants.len() as u64 - 1, + 0, variants.len() as u64 - 1, range_assert) } layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0), layout::RawNullablePointer { nndiscr, .. } => { let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; - let llptrty = type_of::sizing_type_of(bcx.ccx, - monomorphize::field_ty(bcx.tcx(), substs, - &def.variants[nndiscr as usize].fields[0])); - bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty)) + let discr = bcx.load(scrutinee, alignment.to_align()); + bcx.icmp(cmp, discr, C_null(val_ty(discr))) } layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment) @@ -383,9 +376,8 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu assert_eq!(to, Disr(0)); } layout::RawNullablePointer { nndiscr, .. } => { - let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0]; if to.0 != nndiscr { - let llptrty = type_of::sizing_type_of(bcx.ccx, nnty); + let llptrty = val_ty(val).element_type(); bcx.store(C_null(llptrty), val, None); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index d204703b77598..0b6d9cfd96fa4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -59,7 +59,6 @@ use context::{SharedCrateContext, CrateContextList}; use debuginfo; use declare; use machine; -use machine::llsize_of; use meth; use mir; use monomorphize::{self, Instance}; @@ -534,14 +533,13 @@ pub fn memcpy_ty<'a, 'tcx>( ) { let ccx = bcx.ccx; - if type_is_zero_size(ccx, t) { + let size = ccx.size_of(t); + if size == 0 { return; } - let llty = type_of::type_of(ccx, t); - let llsz = llsize_of(ccx, llty); - let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t)); - call_memcpy(bcx, dst, src, llsz, llalign as u32); + let align = align.unwrap_or_else(|| ccx.align_of(t)); + call_memcpy(bcx, dst, src, C_uint(ccx, size), align); } pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index a0906bb02f5a3..cd96353636852 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -125,10 +125,8 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) /// Identify types which have size zero at runtime. pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - use machine::llsize_of_alloc; - use type_of::sizing_type_of; - let llty = sizing_type_of(ccx, ty); - llsize_of_alloc(ccx, llty) == 0 + let layout = ccx.layout_of(ty); + !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0 } /* diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index daf1a1ba95f9a..6b6fa538dc03b 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -255,7 +255,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.statics_to_rauw().borrow_mut().push((g, new_g)); new_g }; - llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty)); + llvm::LLVMSetAlignment(g, ccx.align_of(ty)); llvm::LLVMSetInitializer(g, v); // As an optimization, all shared statics which do not have interior diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 93798e7bd3330..f1e1a3bb22136 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1772,7 +1772,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, let var_name = CString::new(var_name).unwrap(); let linkage_name = CString::new(linkage_name).unwrap(); - let global_align = type_of::align_of(cx, variable_type); + let global_align = cx.align_of(variable_type); unsafe { llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 8e86b50b3f7dd..1b7cf26853bc1 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -449,7 +449,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, LocalVariable | CapturedVariable => (0, DW_TAG_auto_variable) }; - let align = ::type_of::align_of(cx, variable_type); + let align = cx.align_of(variable_type); let name = CString::new(variable_name.as_str().as_bytes()).unwrap(); match (variable_access, &[][..]) { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 41a9ab2842dcd..c2aa6c829415f 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -19,10 +19,8 @@ use llvm::{ValueRef}; use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; use common::*; -use machine::*; use meth; use monomorphize; -use type_of::{sizing_type_of, align_of}; use value::Value; use builder::Builder; @@ -69,9 +67,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf debug!("calculate size of DST: {}; with lost info: {:?}", t, Value(info)); if bcx.ccx.shared().type_is_sized(t) { - let sizing_type = sizing_type_of(bcx.ccx, t); - let size = llsize_of_alloc(bcx.ccx, sizing_type); - let align = align_of(bcx.ccx, t); + let size = bcx.ccx.size_of(t); + let align = bcx.ccx.align_of(t); debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}", t, Value(info), size, align); let size = C_uint(bcx.ccx, size); @@ -82,9 +79,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf ty::TyAdt(def, substs) => { let ccx = bcx.ccx; // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized, - // and it also rounds up to alignment, which we want to avoid, - // as the unsized field's alignment could be smaller. + // Don't use size_of because it also rounds up to alignment, which we + // want to avoid, as the unsized field's alignment could be smaller. assert!(!t.is_simd()); let layout = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); @@ -154,14 +150,11 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf (meth::SIZE.get_usize(bcx, info), meth::ALIGN.get_usize(bcx, info)) } ty::TySlice(_) | ty::TyStr => { - let unit_ty = t.sequence_element_type(bcx.tcx()); + let unit = t.sequence_element_type(bcx.tcx()); // The info in this case is the length of the str, so the size is that // times the unit size. - let llunit_ty = sizing_type_of(bcx.ccx, unit_ty); - let unit_align = llalign_of_min(bcx.ccx, llunit_ty); - let unit_size = llsize_of_alloc(bcx.ccx, llunit_ty); - (bcx.mul(info, C_uint(bcx.ccx, unit_size)), - C_uint(bcx.ccx, unit_align)) + (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))), + C_uint(bcx.ccx, bcx.ccx.align_of(unit))) } _ => bug!("Unexpected unsized type, found {}", t) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 762bf8592ffcc..5e7d612d17f82 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -151,7 +151,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "min_align_of" => { let tp_ty = substs.type_at(0); - C_uint(ccx, type_of::align_of(ccx, tp_ty)) + C_uint(ccx, ccx.align_of(tp_ty)) } "min_align_of_val" => { let tp_ty = substs.type_at(0); @@ -160,7 +160,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llalign } else { - C_uint(ccx, type_of::align_of(ccx, tp_ty)) + C_uint(ccx, ccx.align_of(tp_ty)) } } "pref_align_of" => { @@ -234,7 +234,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } let load = bcx.volatile_load(ptr); unsafe { - llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty)); + llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty)); } to_immediate(bcx, load, tp_ty) }, @@ -252,7 +252,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to()); let store = bcx.volatile_store(val, ptr); unsafe { - llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty)); + llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty)); } } C_nil(ccx) @@ -634,7 +634,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 { if let Some(ty) = fn_ty.ret.cast { let ptr = bcx.pointercast(llresult, ty.ptr_to()); - bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty))); + bcx.store(llval, ptr, Some(ccx.align_of(ret_ty))); } else { store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty); } @@ -651,7 +651,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, -> ValueRef { let ccx = bcx.ccx; let lltp_ty = type_of::type_of(ccx, tp_ty); - let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32); + let align = C_i32(ccx, ccx.align_of(tp_ty) as i32); let size = machine::llsize_of(ccx, lltp_ty); let int_size = machine::llbitsize_of_real(ccx, ccx.int_type()); @@ -685,7 +685,7 @@ fn memset_intrinsic<'a, 'tcx>( count: ValueRef ) -> ValueRef { let ccx = bcx.ccx; - let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32); + let align = C_i32(ccx, ccx.align_of(ty) as i32); let lltp_ty = type_of::type_of(ccx, ty); let size = machine::llsize_of(ccx, lltp_ty); let dst = bcx.pointercast(dst, Type::i8p(ccx)); diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 75ab407614050..f5f924178589a 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -17,7 +17,6 @@ use consts; use machine; use monomorphize; use type_::Type; -use type_of::*; use value::Value; use rustc::ty; @@ -80,14 +79,10 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Not in the cache. Build it. let nullptr = C_null(Type::nil(ccx).ptr_to()); - let size_ty = sizing_type_of(ccx, ty); - let size = machine::llsize_of_alloc(ccx, size_ty); - let align = align_of(ccx, ty); - let mut components: Vec<_> = [ callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)), - C_uint(ccx, size), - C_uint(ccx, align) + C_uint(ccx, ccx.size_of(ty)), + C_uint(ccx, ccx.align_of(ty)) ].iter().cloned().collect(); if let Some(trait_ref) = trait_ref { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d69f31a45048d..84ae8143b3013 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -24,8 +24,8 @@ use consts; use machine::llalign_of_min; use meth; use monomorphize; +use type_of; use tvec; -use type_of::{self, align_of}; use type_::Type; use rustc_data_structures::indexed_vec::IndexVec; @@ -910,7 +910,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to()); let in_type = val.ty; let out_type = dst.ty.to_ty(bcx.tcx());; - let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type)); + let llalign = cmp::min(bcx.ccx.align_of(in_type), bcx.ccx.align_of(out_type)); self.store_operand(bcx, cast_ptr, Some(llalign), val); } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index dbd928194c032..bd58178b07425 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -148,7 +148,7 @@ impl<'tcx> Const<'tcx> { } else { // Otherwise, or if the value is not immediate, we create // a constant LLVM global and cast its address if necessary. - let align = type_of::align_of(ccx, self.ty); + let align = ccx.align_of(self.ty); let ptr = consts::addr_of(ccx, self.llval, align, "const"); OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned) }; @@ -717,7 +717,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { Base::Value(llval) => { // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug) let align = if self.ccx.shared().type_is_sized(ty) { - type_of::align_of(self.ccx, ty) + self.ccx.align_of(ty) } else { self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign }; @@ -1022,25 +1022,20 @@ fn trans_const<'a, 'tcx>( C_vector(vals) } layout::RawNullablePointer { nndiscr, .. } => { - let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0]; if variant_index as u64 == nndiscr { assert_eq!(vals.len(), 1); vals[0] } else { - C_null(type_of::sizing_type_of(ccx, nnty)) + C_null(type_of::type_of(ccx, t)) } } layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { if variant_index as u64 == nndiscr { C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false) } else { - let fields = adt::compute_fields(ccx, t, nndiscr as usize, false); - let vals = fields.iter().map(|&ty| { - // Always use null even if it's not the `discrfield`th - // field; see #8506. - C_null(type_of::sizing_type_of(ccx, ty)) - }).collect::>(); - C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false) + // Always use null even if it's not the `discrfield`th + // field; see #8506. + C_null(type_of::type_of(ccx, t)) } } _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index d487aa6cd5be6..12633720ef87f 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -438,7 +438,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); let llty = type_of::type_of(bcx.ccx, content_ty); let llsize = machine::llsize_of(bcx.ccx, llty); - let align = type_of::align_of(bcx.ccx, content_ty); + let align = bcx.ccx.align_of(content_ty); let llalign = C_uint(bcx.ccx, align); let llty_ptr = llty.ptr_to(); let box_ty = bcx.tcx().mk_box(content_ty); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index a5722e6e520d0..b195429711d15 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -322,10 +322,16 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> llty } -pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) - -> machine::llalign { - let layout = cx.layout_of(t); - layout.align(&cx.tcx().data_layout).abi() as machine::llalign +impl<'a, 'tcx> CrateContext<'a, 'tcx> { + pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign { + let layout = self.layout_of(ty); + layout.align(&self.tcx().data_layout).abi() as machine::llalign + } + + pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize { + let layout = self.layout_of(ty); + layout.size(&self.tcx().data_layout).bytes() as machine::llsize + } } fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String { From 43b227f3bdea473c69cb5568adfedfbbb18ff929 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 10 Mar 2017 06:25:51 +0200 Subject: [PATCH 587/662] rustc: add some abstractions to ty::layout for a more concise API. --- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/ty/layout.rs | 140 +++++++++++++++++------ src/librustc_lint/types.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 5 +- src/librustc_trans/base.rs | 12 +- src/librustc_trans/common.rs | 6 +- src/librustc_trans/context.rs | 61 ++++++++-- src/librustc_trans/debuginfo/metadata.rs | 5 +- src/librustc_trans/glue.rs | 3 +- src/librustc_trans/mir/block.rs | 3 +- src/librustc_trans/mir/constant.rs | 6 +- src/librustc_trans/mir/lvalue.rs | 3 +- src/librustc_trans/mir/mod.rs | 3 +- src/librustc_trans/mir/operand.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/type_of.rs | 11 +- 17 files changed, 188 insertions(+), 80 deletions(-) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c9722adc9510c..8dc298b9c2a17 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { let from = unpack_option_like(self.infcx.tcx.global_tcx(), from); match (&from.sty, sk_to) { (&ty::TyFnDef(..), SizeSkeleton::Known(size_to)) - if size_to == Pointer.size(&self.infcx.tcx.data_layout) => { + if size_to == Pointer.size(self.infcx) => { struct_span_err!(self.infcx.tcx.sess, span, E0591, "`{}` is zero-sized and can't be transmuted to `{}`", from, to) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 8d68eff925173..54e5de3909086 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -202,6 +202,16 @@ impl TargetDataLayout { } } +pub trait HasDataLayout: Copy { + fn data_layout(&self) -> &TargetDataLayout; +} + +impl<'a> HasDataLayout for &'a TargetDataLayout { + fn data_layout(&self) -> &TargetDataLayout { + self + } +} + /// Endianness of the target, which must match cfg(target-endian). #[derive(Copy, Clone)] pub enum Endian { @@ -242,7 +252,9 @@ impl Size { Size::from_bytes((self.bytes() + mask) & !mask) } - pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option { + pub fn checked_add(self, offset: Size, cx: C) -> Option { + let dl = cx.data_layout(); + // Each Size is less than dl.obj_size_bound(), so the sum is // also less than 1 << 62 (and therefore can't overflow). let bytes = self.bytes() + offset.bytes(); @@ -254,7 +266,9 @@ impl Size { } } - pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option { + pub fn checked_mul(self, count: u64, cx: C) -> Option { + let dl = cx.data_layout(); + // Each Size is less than dl.obj_size_bound(), so the sum is // also less than 1 << 62 (and therefore can't overflow). match self.bytes().checked_mul(count) { @@ -354,7 +368,9 @@ impl Integer { } } - pub fn align(&self, dl: &TargetDataLayout)-> Align { + pub fn align(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match *self { I1 => dl.i1_align, I8 => dl.i8_align, @@ -408,7 +424,9 @@ impl Integer { } /// Find the smallest integer with the given alignment. - pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option { + pub fn for_abi_align(cx: C, align: Align) -> Option { + let dl = cx.data_layout(); + let wanted = align.abi(); for &candidate in &[I8, I16, I32, I64] { let ty = Int(candidate); @@ -420,7 +438,9 @@ impl Integer { } /// Get the Integer type from an attr::IntType. - pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer { + pub fn from_attr(cx: C, ity: attr::IntType) -> Integer { + let dl = cx.data_layout(); + match ity { attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8, attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16, @@ -450,7 +470,7 @@ impl Integer { let min_default = I8; if let Some(ity) = repr.int { - let discr = Integer::from_attr(&tcx.data_layout, ity); + let discr = Integer::from_attr(tcx, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; if discr < fit { bug!("Integer::repr_discr: `#[repr]` hint too small for \ @@ -491,7 +511,9 @@ pub enum Primitive { } impl Primitive { - pub fn size(self, dl: &TargetDataLayout) -> Size { + pub fn size(self, cx: C) -> Size { + let dl = cx.data_layout(); + match self { Int(I1) | Int(I8) => Size::from_bits(8), Int(I16) => Size::from_bits(16), @@ -502,7 +524,9 @@ impl Primitive { } } - pub fn align(self, dl: &TargetDataLayout) -> Align { + pub fn align(self, cx: C) -> Align { + let dl = cx.data_layout(); + match self { Int(I1) => dl.i1_align, Int(I8) => dl.i8_align, @@ -682,8 +706,8 @@ impl<'a, 'gcx, 'tcx> Struct { } /// Determine whether a structure would be zero-sized, given its fields. - pub fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) - -> Result> + fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) + -> Result> where I: Iterator>> { for field in fields { let field = field?; @@ -831,7 +855,7 @@ pub struct Union { } impl<'a, 'gcx, 'tcx> Union { - pub fn new(dl: &TargetDataLayout, packed: bool) -> Union { + fn new(dl: &TargetDataLayout, packed: bool) -> Union { Union { align: if packed { dl.i8_align } else { dl.aggregate_align }, min_size: Size::from_bytes(0), @@ -840,10 +864,10 @@ impl<'a, 'gcx, 'tcx> Union { } /// Extend the Struct with more fields. - pub fn extend(&mut self, dl: &TargetDataLayout, - fields: I, - scapegoat: Ty<'gcx>) - -> Result<(), LayoutError<'gcx>> + fn extend(&mut self, dl: &TargetDataLayout, + fields: I, + scapegoat: Ty<'gcx>) + -> Result<(), LayoutError<'gcx>> where I: Iterator>> { for (index, field) in fields.enumerate() { let field = field?; @@ -1452,7 +1476,9 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn size(&self, dl: &TargetDataLayout) -> Size { + pub fn size(&self, cx: C) -> Size { + let dl = cx.data_layout(); + match *self { Scalar { value, .. } | RawNullablePointer { value, .. } => { value.size(dl) @@ -1494,7 +1520,9 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn align(&self, dl: &TargetDataLayout) -> Align { + pub fn align(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match *self { Scalar { value, .. } | RawNullablePointer { value, .. } => { value.align(dl) @@ -1534,11 +1562,13 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn field_offset(&self, - dl: &TargetDataLayout, - i: usize, - variant_index: Option) - -> Size { + pub fn field_offset(&self, + cx: C, + i: usize, + variant_index: Option) + -> Size { + let dl = cx.data_layout(); + match *self { Scalar { .. } | CEnum { .. } | @@ -1617,7 +1647,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { // First try computing a static layout. let err = match ty.layout(infcx) { Ok(layout) => { - return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout))); + return Ok(SizeSkeleton::Known(layout.size(tcx))); } Err(err) => err }; @@ -1748,18 +1778,55 @@ impl<'tcx> Deref for TyLayout<'tcx> { } } -impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { - pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>) - -> Result> { - let ty = normalize_associated_type(infcx, ty); +pub trait HasTyCtxt<'tcx>: HasDataLayout { + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; +} + +impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.data_layout + } +} + +impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { + self.global_tcx() + } +} + +impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { + self.tcx.global_tcx() + } +} + +pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { + type TyLayout; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; +} + +impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { + type TyLayout = Result, LayoutError<'gcx>>; + + fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { + let ty = normalize_associated_type(self, ty); Ok(TyLayout { ty: ty, - layout: ty.layout(infcx)?, + layout: ty.layout(self)?, variant_index: None }) } +} +impl<'a, 'tcx> TyLayout<'tcx> { pub fn for_variant(&self, variant_index: usize) -> Self { TyLayout { variant_index: Some(variant_index), @@ -1767,8 +1834,8 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { } } - pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size { - self.layout.field_offset(dl, i, self.variant_index) + pub fn field_offset(&self, cx: C, i: usize) -> Size { + self.layout.field_offset(cx, i, self.variant_index) } pub fn field_count(&self) -> usize { @@ -1808,9 +1875,11 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { } } - pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> { - let ptr_field_type = |pointee: Ty<'gcx>| { - let slice = |element: Ty<'gcx>| { + pub fn field_type>(&self, cx: C, i: usize) -> Ty<'tcx> { + let tcx = cx.tcx(); + + let ptr_field_type = |pointee: Ty<'tcx>| { + let slice = |element: Ty<'tcx>| { assert!(i < 2); if i == 0 { tcx.mk_mut_ptr(element) @@ -1877,8 +1946,7 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { } } - pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize) - -> Result> { - TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i)) + pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { + cx.layout_of(self.field_type(cx, i)) } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 529afe0215e53..2318bb81affe6 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -733,7 +733,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { - let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes(); + let discr_size = Primitive::Int(discr).size(cx.tcx).bytes(); debug!("enum `{}` is {} bytes large with layout:\n{:#?}", t, size.bytes(), layout); diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 550f337d9b1c8..b26dd8eed7876 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -35,13 +35,13 @@ use type_of; use rustc::hir; use rustc::ty::{self, Ty}; +use rustc::ty::layout::{Layout, LayoutTyper}; use libc::c_uint; use std::cmp; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; -use rustc::ty::layout::Layout; #[derive(Clone, Copy, PartialEq, Debug)] enum ArgKind { diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index fb7ddd2bf4200..b15acfb591caa 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -46,8 +46,8 @@ use super::Disr; use std; use llvm::{ValueRef, True, IntEQ, IntNE}; -use rustc::ty::layout; use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, LayoutTyper}; use common::*; use builder::Builder; use base; @@ -246,9 +246,8 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type { assert_eq!(size%align, 0); assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align); let align_units = size/align; - let dl = &cx.tcx().data_layout; let layout_align = layout::Align::from_bytes(align, align).unwrap(); - if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) { + if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) { Type::array(&Type::from_integer(cx, ity), align_units) } else { Type::array(&Type::vector(&Type::i32(cx), align/4), diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0b6d9cfd96fa4..574b345218be9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1295,8 +1295,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // (delay format until we actually need it) let record = |kind, opt_discr_size, variants| { let type_desc = format!("{:?}", ty); - let overall_size = layout.size(&tcx.data_layout); - let align = layout.align(&tcx.data_layout); + let overall_size = layout.size(tcx); + let align = layout.align(tcx); tcx.sess.code_stats.borrow_mut().record_type_size(kind, type_desc, align, @@ -1332,8 +1332,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { session::FieldInfo { name: field_name.to_string(), offset: offset.bytes(), - size: field_layout.size(&tcx.data_layout).bytes(), - align: field_layout.align(&tcx.data_layout).abi(), + size: field_layout.size(tcx).bytes(), + align: field_layout.align(tcx).abi(), } } } @@ -1343,8 +1343,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { session::VariantInfo { name: Some(name.to_string()), kind: session::SizeKind::Exact, - align: value.align(&tcx.data_layout).abi(), - size: value.size(&tcx.data_layout).bytes(), + align: value.align(tcx).abi(), + size: value.size(tcx).bytes(), fields: vec![], } }; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index cd96353636852..5d58c93538922 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -27,7 +27,7 @@ use monomorphize; use type_::Type; use value::Value; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::ty::subst::{Subst, Substs}; use rustc::hir; @@ -63,7 +63,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - Layout::UntaggedUnion { .. } | Layout::RawNullablePointer { .. } | Layout::StructWrappedNullablePointer { .. } => { - !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0 + !layout.is_unsized() && layout.size(ccx).bytes() == 0 } } } @@ -126,7 +126,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) /// Identify types which have size zero at runtime. pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { let layout = ccx.layout_of(ty); - !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0 + !layout.is_unsized() && layout.size(ccx).bytes() == 0 } /* diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 3649216eaa85e..98fbb64fd5540 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -28,6 +28,7 @@ use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{LayoutTyper, TyLayout}; use session::config::NoDebugInfo; use session::Session; use session::config; @@ -828,18 +829,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { TypeOfDepthLock(self.local()) } - pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> { - self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { - ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| { - match e { - ty::layout::LayoutError::SizeOverflow(_) => - self.sess().fatal(&e.to_string()), - _ => bug!("failed to get layout for `{}`: {}", ty, e) - } - }) - }) - } - pub fn check_overflow(&self) -> bool { self.shared.check_overflow } @@ -951,6 +940,54 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } } +impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> { + fn data_layout(&self) -> &ty::layout::TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } +} + +impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> { + fn data_layout(&self) -> &ty::layout::TargetDataLayout { + &self.shared.tcx.data_layout + } +} + +impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.shared.tcx + } +} + +impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { + type TyLayout = TyLayout<'tcx>; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { + infcx.layout_of(ty).unwrap_or_else(|e| { + match e { + ty::layout::LayoutError::SizeOverflow(_) => + self.sess().fatal(&e.to_string()), + _ => bug!("failed to get layout for `{}`: {}", ty, e) + } + }) + }) + } +} + +impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { + type TyLayout = TyLayout<'tcx>; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + self.shared.layout_of(ty) + } +} + pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index f1e1a3bb22136..ccb693aa41f4c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -35,7 +35,8 @@ use rustc_data_structures::ToHex; use {type_of, machine, monomorphize}; use common::{self, CrateContext}; use type_::Type; -use rustc::ty::{self, AdtKind, Ty, layout}; +use rustc::ty::{self, AdtKind, Ty}; +use rustc::ty::layout::{self, LayoutTyper}; use session::config; use util::nodemap::FxHashMap; use util::common::path2cstr; @@ -900,7 +901,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { let offsets = match *layout { layout::Univariant { ref variant, .. } => &variant.offsets, layout::Vector { element, count } => { - let element_size = element.size(&cx.tcx().data_layout).bytes(); + let element_size = element.size(cx).bytes(); tmp = (0..count). map(|i| layout::Size::from_bytes(i*element_size)) .collect::>(); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index c2aa6c829415f..59876a7f2a201 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -18,6 +18,7 @@ use llvm; use llvm::{ValueRef}; use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::LayoutTyper; use common::*; use meth; use monomorphize; @@ -47,7 +48,7 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx> if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { let layout = t.layout(&infcx).unwrap(); - if layout.size(&scx.tcx().data_layout).bytes() == 0 { + if layout.size(scx).bytes() == 0 { // `Box` does not allocate. false } else { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 84ae8143b3013..18893ce4ea9a6 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -12,7 +12,8 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; use rustc::middle::const_val::ConstInt; -use rustc::ty::{self, layout, TypeFoldable}; +use rustc::ty::{self, TypeFoldable}; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; use abi::{Abi, FnType, ArgType}; use base::{self, Lifetime}; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index bd58178b07425..4d5b691c86ebb 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -18,7 +18,8 @@ use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::mir; use rustc::mir::tcx::LvalueTy; -use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::{Kind, Substs, Subst}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -979,7 +980,6 @@ fn trans_const<'a, 'tcx>( vals: &[ValueRef] ) -> ValueRef { let l = ccx.layout_of(t); - let dl = &ccx.tcx().data_layout; let variant_index = match *kind { mir::AggregateKind::Adt(_, index, _, _) => index, _ => 0, @@ -1002,7 +1002,7 @@ fn trans_const<'a, 'tcx>( let mut vals_with_discr = vec![lldiscr]; vals_with_discr.extend_from_slice(vals); let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]); - let needed_padding = l.size(dl).bytes() - variant.stride().bytes(); + let needed_padding = l.size(ccx).bytes() - variant.stride().bytes(); if needed_padding > 0 { contents.push(padding(ccx, needed_padding)); } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index dd8c1d0e1f031..fc889604ab88e 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -9,7 +9,8 @@ // except according to those terms. use llvm::ValueRef; -use rustc::ty::{self, layout, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 21bbbea77d442..cc957a4d25873 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,7 +11,8 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, layout}; +use rustc::ty; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index da24c03fdc2a0..771a88238b2b7 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -10,7 +10,7 @@ use llvm::ValueRef; use rustc::ty::{self, Ty}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 12633720ef87f..8f7cb914c4735 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef}; use rustc::ty::{self, Ty}; use rustc::ty::cast::{CastTy, IntTy}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::mir::tcx::LvalueTy; use rustc::mir; use middle::lang_items::ExchangeMallocFnLangItem; diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b195429711d15..c459191561dd6 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -13,6 +13,7 @@ use adt; use common::*; use machine; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::LayoutTyper; use trans_item::DefPathBasedNames; use type_::Type; @@ -117,14 +118,14 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ return llsizingty; } - let r = layout.size(&cx.tcx().data_layout).bytes(); + let r = layout.size(cx).bytes(); let l = machine::llsize_of_alloc(cx, llsizingty); if r != l { bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", r, l, t, layout); } - let r = layout.align(&cx.tcx().data_layout).abi(); + let r = layout.align(cx).abi(); let l = machine::llalign_of_min(cx, llsizingty) as u64; if r != l { bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", @@ -324,13 +325,11 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> impl<'a, 'tcx> CrateContext<'a, 'tcx> { pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign { - let layout = self.layout_of(ty); - layout.align(&self.tcx().data_layout).abi() as machine::llalign + self.layout_of(ty).align(self).abi() as machine::llalign } pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize { - let layout = self.layout_of(ty); - layout.size(&self.tcx().data_layout).bytes() as machine::llsize + self.layout_of(ty).size(self).bytes() as machine::llsize } } From 2fed2a2395f3265eaa740ed5c555f4225c555ddf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 8 Apr 2017 15:51:18 -0500 Subject: [PATCH 588/662] this code block is text not Rust code --- src/doc/unstable-book/src/linker-flavor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/linker-flavor.md b/src/doc/unstable-book/src/linker-flavor.md index 2e85116783494..39659602e015c 100644 --- a/src/doc/unstable-book/src/linker-flavor.md +++ b/src/doc/unstable-book/src/linker-flavor.md @@ -36,7 +36,7 @@ $ xargo rustc --target thumbv7m-none-eabi -- \ Whereas the default is: -``` +``` text $ xargo rustc --target thumbv7m-none-eabi -- \ -C link-arg=-nostartfiles \ -Z print-link-args | tr ' ' '\n' From f0636b61c7f84962a609e831760db9d77f4f5e14 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 10 Mar 2017 06:25:57 +0200 Subject: [PATCH 589/662] rustc_trans: use ty::layout for ABI computation instead of LLVM types. --- src/librustc_trans/abi.rs | 585 +++++++++++++++++-------- src/librustc_trans/adt.rs | 24 +- src/librustc_trans/cabi_aarch64.rs | 178 +++----- src/librustc_trans/cabi_arm.rs | 155 ++----- src/librustc_trans/cabi_asmjs.rs | 35 +- src/librustc_trans/cabi_mips.rs | 88 +--- src/librustc_trans/cabi_mips64.rs | 88 +--- src/librustc_trans/cabi_msp430.rs | 21 +- src/librustc_trans/cabi_nvptx.rs | 21 +- src/librustc_trans/cabi_nvptx64.rs | 21 +- src/librustc_trans/cabi_powerpc.rs | 93 +--- src/librustc_trans/cabi_powerpc64.rs | 180 ++------ src/librustc_trans/cabi_s390x.rs | 140 ++---- src/librustc_trans/cabi_sparc.rs | 90 +--- src/librustc_trans/cabi_sparc64.rs | 181 +++----- src/librustc_trans/cabi_x86.rs | 37 +- src/librustc_trans/cabi_x86_64.rs | 512 ++++++++-------------- src/librustc_trans/cabi_x86_win64.rs | 45 +- src/librustc_trans/mir/block.rs | 28 +- src/librustc_trans/mir/mod.rs | 19 +- src/librustc_trans/type_of.rs | 119 +---- src/test/codegen/function-arguments.rs | 4 +- 22 files changed, 992 insertions(+), 1672 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index b26dd8eed7876..7be80a757ca01 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace}; +use llvm::{self, ValueRef, AttributePlace}; use base; use builder::Builder; use common::{type_is_fat_ptr, C_uint}; @@ -29,16 +29,17 @@ use cabi_sparc; use cabi_sparc64; use cabi_nvptx; use cabi_nvptx64; -use machine::{llalign_of_min, llsize_of, llsize_of_alloc}; +use machine::llalign_of_min; use type_::Type; use type_of; use rustc::hir; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{Layout, LayoutTyper}; +use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size}; use libc::c_uint; use std::cmp; +use std::iter; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; @@ -132,33 +133,293 @@ impl ArgAttributes { } } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RegKind { + Integer, + Float, + Vector +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Reg { + pub kind: RegKind, + pub size: Size, +} + +macro_rules! reg_ctor { + ($name:ident, $kind:ident, $bits:expr) => { + pub fn $name() -> Reg { + Reg { + kind: RegKind::$kind, + size: Size::from_bits($bits) + } + } + } +} + +impl Reg { + reg_ctor!(i8, Integer, 8); + reg_ctor!(i16, Integer, 16); + reg_ctor!(i32, Integer, 32); + reg_ctor!(i64, Integer, 64); + + reg_ctor!(f32, Float, 32); + reg_ctor!(f64, Float, 64); +} + +impl Reg { + fn llvm_type(&self, ccx: &CrateContext) -> Type { + match self.kind { + RegKind::Integer => Type::ix(ccx, self.size.bits()), + RegKind::Float => { + match self.size.bits() { + 32 => Type::f32(ccx), + 64 => Type::f64(ccx), + _ => bug!("unsupported float: {:?}", self) + } + } + RegKind::Vector => { + Type::vector(&Type::i8(ccx), self.size.bytes()) + } + } + } +} + +/// An argument passed entirely registers with the +/// same kind (e.g. HFA / HVA on PPC64 and AArch64). +#[derive(Copy, Clone)] +pub struct Uniform { + pub unit: Reg, + + /// The total size of the argument, which can be: + /// * equal to `unit.size` (one scalar/vector) + /// * a multiple of `unit.size` (an array of scalar/vectors) + /// * if `unit.kind` is `Integer`, the last element + /// can be shorter, i.e. `{ i64, i64, i32 }` for + /// 64-bit integers with a total size of 20 bytes + pub total: Size, +} + +impl From for Uniform { + fn from(unit: Reg) -> Uniform { + Uniform { + unit, + total: unit.size + } + } +} + +impl Uniform { + fn llvm_type(&self, ccx: &CrateContext) -> Type { + let llunit = self.unit.llvm_type(ccx); + + if self.total <= self.unit.size { + return llunit; + } + + let count = self.total.bytes() / self.unit.size.bytes(); + let rem_bytes = self.total.bytes() % self.unit.size.bytes(); + + if rem_bytes == 0 { + return Type::array(&llunit, count); + } + + // Only integers can be really split further. + assert_eq!(self.unit.kind, RegKind::Integer); + + let args: Vec<_> = (0..count).map(|_| llunit) + .chain(iter::once(Type::ix(ccx, rem_bytes * 8))) + .collect(); + + Type::struct_(ccx, &args, false) + } +} + +pub trait LayoutExt<'tcx> { + fn is_aggregate(&self) -> bool; + fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option; +} + +impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { + fn is_aggregate(&self) -> bool { + match *self.layout { + Layout::Scalar { .. } | + Layout::RawNullablePointer { .. } | + Layout::CEnum { .. } | + Layout::Vector { .. } => false, + + Layout::Array { .. } | + Layout::FatPointer { .. } | + Layout::Univariant { .. } | + Layout::UntaggedUnion { .. } | + Layout::General { .. } | + Layout::StructWrappedNullablePointer { .. } => true + } + } + + fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option { + match *self.layout { + // The primitives for this algorithm. + Layout::Scalar { value, .. } | + Layout::RawNullablePointer { value, .. } => { + let kind = match value { + layout::Int(_) | + layout::Pointer => RegKind::Integer, + layout::F32 | + layout::F64 => RegKind::Float + }; + Some(Reg { + kind, + size: self.size(ccx) + }) + } + + Layout::CEnum { .. } => { + Some(Reg { + kind: RegKind::Integer, + size: self.size(ccx) + }) + } + + Layout::Vector { .. } => { + Some(Reg { + kind: RegKind::Integer, + size: self.size(ccx) + }) + } + + Layout::Array { count, .. } => { + if count > 0 { + self.field(ccx, 0).homogenous_aggregate(ccx) + } else { + None + } + } + + Layout::Univariant { ref variant, .. } => { + let mut unaligned_offset = Size::from_bytes(0); + let mut result = None; + + for i in 0..self.field_count() { + if unaligned_offset != variant.offsets[i] { + return None; + } + + let field = self.field(ccx, i); + match (result, field.homogenous_aggregate(ccx)) { + // The field itself must be a homogenous aggregate. + (_, None) => return None, + // If this is the first field, record the unit. + (None, Some(unit)) => { + result = Some(unit); + } + // For all following fields, the unit must be the same. + (Some(prev_unit), Some(unit)) => { + if prev_unit != unit { + return None; + } + } + } + + // Keep track of the offset (without padding). + let size = field.size(ccx); + match unaligned_offset.checked_add(size, ccx) { + Some(offset) => unaligned_offset = offset, + None => return None + } + } + + // There needs to be no padding. + if unaligned_offset != self.size(ccx) { + None + } else { + result + } + } + + Layout::UntaggedUnion { .. } => { + let mut max = Size::from_bytes(0); + let mut result = None; + + for i in 0..self.field_count() { + let field = self.field(ccx, i); + match (result, field.homogenous_aggregate(ccx)) { + // The field itself must be a homogenous aggregate. + (_, None) => return None, + // If this is the first field, record the unit. + (None, Some(unit)) => { + result = Some(unit); + } + // For all following fields, the unit must be the same. + (Some(prev_unit), Some(unit)) => { + if prev_unit != unit { + return None; + } + } + } + + // Keep track of the offset (without padding). + let size = field.size(ccx); + if size > max { + max = size; + } + } + + // There needs to be no padding. + if max != self.size(ccx) { + None + } else { + result + } + } + + // Rust-specific types, which we can ignore for C ABIs. + Layout::FatPointer { .. } | + Layout::General { .. } | + Layout::StructWrappedNullablePointer { .. } => None + } + } +} + +pub enum CastTarget { + Uniform(Uniform), + Pair(Reg, Reg) +} + +impl From for CastTarget { + fn from(unit: Reg) -> CastTarget { + CastTarget::Uniform(Uniform::from(unit)) + } +} + +impl From for CastTarget { + fn from(uniform: Uniform) -> CastTarget { + CastTarget::Uniform(uniform) + } +} + +impl CastTarget { + fn llvm_type(&self, ccx: &CrateContext) -> Type { + match *self { + CastTarget::Uniform(u) => u.llvm_type(ccx), + CastTarget::Pair(a, b) => { + Type::struct_(ccx, &[ + a.llvm_type(ccx), + b.llvm_type(ccx) + ], false) + } + } + } +} /// Information about how a specific C type /// should be passed to or returned from a function /// /// This is borrowed from clang's ABIInfo.h #[derive(Clone, Copy, Debug)] -pub struct ArgType { +pub struct ArgType<'tcx> { kind: ArgKind, - /// Original LLVM type - pub original_ty: Type, - /// Sizing LLVM type (pointers are opaque). - /// Unlike original_ty, this is guaranteed to be complete. - /// - /// For example, while we're computing the function pointer type in - /// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`. - /// The field type will likely end up being `void(%Foo)*`, but we cannot - /// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`, - /// until `%Foo` is completed by having all of its field types inserted, - /// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers - /// with opaque ones, resulting in `{i8*}` for `Foo`. - /// ABI-specific logic can then look at the size, alignment and fields of - /// `{i8*}` in order to determine how the argument will be passed. - /// Only later will `original_ty` aka `%Foo` be used in the LLVM function - /// pointer type, without ever having introspected it. - pub ty: Type, - /// Signedness for integer types, None for other types - pub signedness: Option, + pub layout: TyLayout<'tcx>, /// Coerced LLVM Type pub cast: Option, /// Dummy argument, which is emitted before the real argument @@ -167,26 +428,24 @@ pub struct ArgType { pub attrs: ArgAttributes } -impl ArgType { - fn new(original_ty: Type, ty: Type) -> ArgType { +impl<'a, 'tcx> ArgType<'tcx> { + fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> { ArgType { kind: ArgKind::Direct, - original_ty: original_ty, - ty: ty, - signedness: None, + layout: layout, cast: None, pad: None, attrs: ArgAttributes::default() } } - pub fn make_indirect(&mut self, ccx: &CrateContext) { + pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) { assert_eq!(self.kind, ArgKind::Direct); // Wipe old attributes, likely not valid through indirection. self.attrs = ArgAttributes::default(); - let llarg_sz = llsize_of_alloc(ccx, self.ty); + let llarg_sz = self.layout.size(ccx).bytes(); // For non-immediate arguments the callee gets its own copy of // the value on the stack, so there are no aliases. It's also @@ -205,17 +464,44 @@ impl ArgType { pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness - if let Some(signed) = self.signedness { - if self.ty.int_width() < bits { - self.attrs.set(if signed { - ArgAttribute::SExt - } else { - ArgAttribute::ZExt - }); + let (i, signed) = match *self.layout { + Layout::Scalar { value, .. } => { + match value { + layout::Int(i) => { + if self.layout.ty.is_integral() { + (i, self.layout.ty.is_signed()) + } else { + return; + } + } + _ => return + } } + + // Rust enum types that map onto C enums also need to follow + // the target ABI zero-/sign-extension rules. + Layout::CEnum { discr, signed, .. } => (discr, signed), + + _ => return + }; + + if i.size().bits() < bits { + self.attrs.set(if signed { + ArgAttribute::SExt + } else { + ArgAttribute::ZExt + }); } } + pub fn cast_to>(&mut self, ccx: &CrateContext, target: T) { + self.cast = Some(target.into().llvm_type(ccx)); + } + + pub fn pad_with(&mut self, ccx: &CrateContext, reg: Reg) { + self.pad = Some(reg.llvm_type(ccx)); + } + pub fn is_indirect(&self) -> bool { self.kind == ArgKind::Indirect } @@ -224,18 +510,24 @@ impl ArgType { self.kind == ArgKind::Ignore } + /// Get the LLVM type for an lvalue of the original Rust type of + /// this argument/return, i.e. the result of `type_of::type_of`. + pub fn memory_ty(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { + type_of::type_of(ccx, self.layout.ty) + } + /// Store a direct/indirect value described by this ArgType into a /// lvalue for the original Rust type of this argument/return. /// Can be used for both storing formal arguments into Rust variables /// or results of call/invoke instructions into their destinations. - pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) { + pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) { if self.is_ignore() { return; } let ccx = bcx.ccx; if self.is_indirect() { - let llsz = llsize_of(ccx, self.ty); - let llalign = llalign_of_min(ccx, self.ty); + let llsz = C_uint(ccx, self.layout.size(ccx).bytes()); + let llalign = self.layout.align(ccx).abi(); base::call_memcpy(bcx, dst, val, llsz, llalign as u32); } else if let Some(ty) = self.cast { // FIXME(eddyb): Figure out when the simpler Store is safe, clang @@ -243,8 +535,8 @@ impl ArgType { let can_store_through_cast_ptr = false; if can_store_through_cast_ptr { let cast_dst = bcx.pointercast(dst, ty.ptr_to()); - let llalign = llalign_of_min(ccx, self.ty); - bcx.store(val, cast_dst, Some(llalign)); + let llalign = self.layout.align(ccx).abi(); + bcx.store(val, cast_dst, Some(llalign as u32)); } else { // The actual return type is a struct, but the ABI // adaptation code has cast it into some scalar type. The @@ -271,21 +563,21 @@ impl ArgType { base::call_memcpy(bcx, bcx.pointercast(dst, Type::i8p(ccx)), bcx.pointercast(llscratch, Type::i8p(ccx)), - C_uint(ccx, llsize_of_alloc(ccx, self.ty)), - cmp::min(llalign_of_min(ccx, self.ty), - llalign_of_min(ccx, ty)) as u32); + C_uint(ccx, self.layout.size(ccx).bytes()), + cmp::min(self.layout.align(ccx).abi() as u32, + llalign_of_min(ccx, ty))); base::Lifetime::End.call(bcx, llscratch); } } else { - if self.original_ty == Type::i1(ccx) { + if self.layout.ty == ccx.tcx().types.bool { val = bcx.zext(val, Type::i8(ccx)); } bcx.store(val, dst, None); } } - pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) { + pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: ValueRef) { if self.pad.is_some() { *idx += 1; } @@ -304,30 +596,30 @@ impl ArgType { /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM #[derive(Clone, Debug)] -pub struct FnType { +pub struct FnType<'tcx> { /// The LLVM types of each argument. - pub args: Vec, + pub args: Vec>, /// LLVM return type. - pub ret: ArgType, + pub ret: ArgType<'tcx>, pub variadic: bool, pub cconv: llvm::CallConv } -impl FnType { - pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { +impl<'a, 'tcx> FnType<'tcx> { + pub fn new(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); fn_ty.adjust_for_abi(ccx, sig); fn_ty } - pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { + pub fn new_vtable(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); // Don't pass the vtable, it's not an argument of the virtual fn. fn_ty.args[1].ignore(); @@ -335,9 +627,9 @@ impl FnType { fn_ty } - fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { + pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { use self::Abi::*; let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | @@ -394,23 +686,11 @@ impl FnType { }; let arg_of = |ty: Ty<'tcx>, is_return: bool| { + let mut arg = ArgType::new(ccx.layout_of(ty)); if ty.is_bool() { - let llty = Type::i1(ccx); - let mut arg = ArgType::new(llty, llty); arg.attrs.set(ArgAttribute::ZExt); - arg } else { - let mut arg = ArgType::new(type_of::type_of(ccx, ty), - type_of::sizing_type_of(ccx, ty)); - if ty.is_integral() { - arg.signedness = Some(ty.is_signed()); - } - // Rust enum types that map onto C enums also need to follow - // the target ABI zero-/sign-extension rules. - if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) { - arg.signedness = Some(signed); - } - if llsize_of_alloc(ccx, arg.ty) == 0 { + if arg.layout.size(ccx).bytes() == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. // The same is true for s390x-unknown-linux-gnu. @@ -419,8 +699,8 @@ impl FnType { arg.ignore(); } } - arg } + arg }; let ret_ty = sig.output(); @@ -491,13 +771,9 @@ impl FnType { for ty in inputs.iter().chain(extra_args.iter()) { let mut arg = arg_of(ty, false); - if type_is_fat_ptr(ccx, ty) { - let original_tys = arg.original_ty.field_types(); - let sizing_tys = arg.ty.field_types(); - assert_eq!((original_tys.len(), sizing_tys.len()), (2, 2)); - - let mut data = ArgType::new(original_tys[0], sizing_tys[0]); - let mut info = ArgType::new(original_tys[1], sizing_tys[1]); + if let ty::layout::FatPointer { .. } = *arg.layout { + let mut data = ArgType::new(arg.layout.field(ccx, 0)); + let mut info = ArgType::new(arg.layout.field(ccx, 1)); if let Some(inner) = rust_ptr_attrs(ty, &mut data) { data.attrs.set(ArgAttribute::NonNull); @@ -527,43 +803,51 @@ impl FnType { } } - fn adjust_for_abi<'a, 'tcx>(&mut self, - ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>) { + fn adjust_for_abi(&mut self, + ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>) { let abi = sig.abi; if abi == Abi::Unadjusted { return } if abi == Abi::Rust || abi == Abi::RustCall || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType| { - let mut llty = arg.ty; - - // Replace newtypes with their inner-most type. - while llty.kind() == llvm::TypeKind::Struct { - let inner = llty.field_types(); - if inner.len() != 1 { - break; - } - llty = inner[0]; + let fixup = |arg: &mut ArgType<'tcx>| { + if !arg.layout.is_aggregate() { + return; } - if !llty.is_aggregate() { - // Scalars and vectors, always immediate. - if llty != arg.ty { + let size = arg.layout.size(ccx); + + if let Some(unit) = arg.layout.homogenous_aggregate(ccx) { + // Replace newtypes with their inner-most type. + if unit.size == size { // Needs a cast as we've unpacked a newtype. - arg.cast = Some(llty); + arg.cast_to(ccx, unit); + return; + } + + // Pairs of floats. + if unit.kind == RegKind::Float { + if unit.size.checked_mul(2, ccx) == Some(size) { + // FIXME(eddyb) This should be using Uniform instead of a pair, + // but the resulting [2 x float/double] breaks emscripten. + // See https://github.com/kripken/emscripten-fastcomp/issues/178. + arg.cast_to(ccx, CastTarget::Pair(unit, unit)); + return; + } } - return; } - let size = llsize_of_alloc(ccx, llty); - if size > llsize_of_alloc(ccx, ccx.int_type()) { + if size > layout::Pointer.size(ccx) { arg.make_indirect(ccx); - } else if size > 0 { + } else { // We want to pass small aggregates as immediates, but using // a LLVM aggregate type for this leads to bad optimizations, // so we pick an appropriately sized integer type instead. - arg.cast = Some(Type::ix(ccx, size * 8)); + arg.cast_to(ccx, Reg { + kind: RegKind::Integer, + size + }); } }; // Fat pointers are returned by-value. @@ -599,14 +883,7 @@ impl FnType { cabi_x86_64::compute_abi_info(ccx, self); }, "aarch64" => cabi_aarch64::compute_abi_info(ccx, self), - "arm" => { - let flavor = if ccx.sess().target.target.target_os == "ios" { - cabi_arm::Flavor::Ios - } else { - cabi_arm::Flavor::General - }; - cabi_arm::compute_abi_info(ccx, self, flavor); - }, + "arm" => cabi_arm::compute_abi_info(ccx, self), "mips" => cabi_mips::compute_abi_info(ccx, self), "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), @@ -627,16 +904,18 @@ impl FnType { } } - pub fn llvm_type(&self, ccx: &CrateContext) -> Type { + pub fn llvm_type(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { let mut llargument_tys = Vec::new(); let llreturn_ty = if self.ret.is_ignore() { Type::void(ccx) } else if self.ret.is_indirect() { - llargument_tys.push(self.ret.original_ty.ptr_to()); + llargument_tys.push(self.ret.memory_ty(ccx).ptr_to()); Type::void(ccx) } else { - self.ret.cast.unwrap_or(self.ret.original_ty) + self.ret.cast.unwrap_or_else(|| { + type_of::immediate_type_of(ccx, self.ret.layout.ty) + }) }; for arg in &self.args { @@ -649,9 +928,11 @@ impl FnType { } let llarg_ty = if arg.is_indirect() { - arg.original_ty.ptr_to() + arg.memory_ty(ccx).ptr_to() } else { - arg.cast.unwrap_or(arg.original_ty) + arg.cast.unwrap_or_else(|| { + type_of::immediate_type_of(ccx, arg.layout.ty) + }) }; llargument_tys.push(llarg_ty); @@ -699,72 +980,6 @@ impl FnType { } } -pub fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type, pointer: usize) -> usize { - let a = ty_align(ty, pointer); - return align_up_to(off, a); -} - -pub fn ty_align(ty: Type, pointer: usize) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => pointer, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt, pointer) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ty_align(elt, pointer) * len - } - _ => bug!("ty_align: unhandled type") - } -} - -pub fn ty_size(ty: Type, pointer: usize) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => pointer, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| { - align(s, *t, pointer) + ty_size(*t, pointer) - }); - align(size, ty, pointer) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, pointer); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, pointer); - len * eltsz - }, - _ => bug!("ty_size: unhandled type") - } +pub fn align_up_to(off: u64, a: u64) -> u64 { + (off + a - 1) / a * a } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index b15acfb591caa..0fe180253b5b8 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -95,15 +95,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { generic_type_of(cx, t, None, false, false) } - -// Pass dst=true if the type you are passing is a DST. Yes, we could figure -// this out, but if you call this on an unsized type without realising it, you -// are going to get the wrong type (it will not include the unsized parts of it). -pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, dst: bool) -> Type { - generic_type_of(cx, t, None, true, dst) -} - pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: &str) -> Type { generic_type_of(cx, t, Some(name), false, false) @@ -149,7 +140,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; let nnty = monomorphize::field_ty(cx.tcx(), substs, &def.variants[nndiscr as usize].fields[0]); - type_of::sizing_type_of(cx, nnty) + if let layout::Scalar { value: layout::Pointer, .. } = *cx.layout_of(nnty) { + Type::i8p(cx) + } else { + type_of::type_of(cx, nnty) + } } layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { let fields = compute_fields(cx, t, nndiscr as usize, false); @@ -181,10 +176,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - layout::Vector { element, count } => { - let elem_ty = Type::from_primitive(cx, element); - Type::vector(&elem_ty, count) - } layout::UntaggedUnion { ref variants, .. }=> { // Use alignment-sized ints to fill all the union storage. let size = variants.stride().bytes(); @@ -258,11 +249,10 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type { fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec>, variant: &layout::Struct, - sizing: bool, dst: bool) -> Vec { + sizing: bool, _dst: bool) -> Vec { let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]); if sizing { - fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty)) - .map(|ty| type_of::sizing_type_of(cx, ty)).collect() + bug!() } else { fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect() } diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_trans/cabi_aarch64.rs index 59a84439950ba..c8c5af714d92a 100644 --- a/src/librustc_trans/cabi_aarch64.rs +++ b/src/librustc_trans/cabi_aarch64.rs @@ -8,163 +8,99 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{self, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; -use type_::Type; - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) -} - -fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { - fn check_array(ty: Type) -> Option<(Type, u64)> { - let len = ty.array_length() as u64; - if len == 0 { - return None - } - let elt = ty.element_type(); - - // if our element is an HFA/HVA, so are we; multiply members by our len - is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) - } - - fn check_struct(ty: Type) -> Option<(Type, u64)> { - let str_tys = ty.field_types(); - if str_tys.len() == 0 { - return None - } - - let mut prev_base_ty = None; - let mut members = 0; - for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { - match (prev_base_ty, opt_homog_agg) { - // field isn't itself an HFA, so we aren't either - (_, None) => return None, - - // first field - store its type and number of members - (None, Some((field_ty, field_members))) => { - prev_base_ty = Some(field_ty); - members = field_members; - }, - // 2nd or later field - give up if it's a different type; otherwise incr. members - (Some(prev_ty), Some((field_ty, field_members))) => { - if prev_ty != field_ty { - return None; - } - members += field_members; - } - } - } - - // Because of previous checks, we know prev_base_ty is Some(...) because - // 1. str_tys has at least one element; and - // 2. prev_base_ty was filled in (or we would've returned early) - let (base_ty, members) = (prev_base_ty.unwrap(), members); +fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogenous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); - // Ensure there is no padding. - if ty_size(ty) == ty_size(base_ty) * (members as usize) { - Some((base_ty, members)) - } else { - None + // Ensure we have at most four uniquely addressable members. + if size > unit.size.checked_mul(4, ccx).unwrap() { + return None; } - } - let homog_agg = match ty.kind() { - Float => Some((ty, 1)), - Double => Some((ty, 1)), - Array => check_array(ty), - Struct => check_struct(ty), - Vector => match ty_size(ty) { - 4|8 => Some((ty, 1)), - _ => None - }, - _ => None - }; + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 64 || size.bits() == 128 + }; - // Ensure we have at most four uniquely addressable members - homog_agg.and_then(|(base_ty, members)| { - if members > 0 && members <= 4 { - Some((base_ty, members)) + if valid_unit { + Some(Uniform { + unit, + total: size + }) } else { None } }) } -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { - ret.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); return; } - let size = ty_size(ret.ty); - if size <= 16 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - ret.cast = Some(llty); + + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { - arg.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); return; } - let size = ty_size(arg.ty); - if size <= 16 { - let llty = if size == 0 { - Type::array(&Type::i64(ccx), 0) - } else if size == 1 { - Type::i8(ccx) - } else if size == 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = arg.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - arg.cast = Some(llty); + + arg.cast_to(ccx, Uniform { + unit, + total: size + }); return; } arg.make_indirect(ccx); } -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - } -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs index 85b26074bae6d..7a91cad511d6d 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_trans/cabi_arm.rs @@ -8,156 +8,53 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{self, align_up_to, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; -use std::cmp; - -pub enum Flavor { - General, - Ios -} - -type TyAlignFn = fn(ty: Type) -> usize; - -fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize { - let a = align_fn(ty); - return align_up_to(off, a); -} - -fn general_ty_align(ty: Type) -> usize { - abi::ty_align(ty, 4) -} - -// For more information see: -// ARMv7 -// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual -// /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html -// ARMv6 -// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual -// /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html -fn ios_ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8), - Pointer => 4, - Float => 4, - Double => 4, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ios_ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ios_ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } -} - -fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter() - .fold(0, |s, t| { - align(s, *t, align_fn) + ty_size(*t, align_fn) - }); - align(size, ty, align_fn) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, align_fn); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, align_fn); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; } - let size = ty_size(ret.ty, align_fn); - if size <= 4 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 32 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() } else { - Type::i32(ccx) + Reg::i32() }; - ret.cast = Some(llty); + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; } - let align = align_fn(arg.ty); - let size = ty_size(arg.ty, align_fn); - let llty = if align <= 4 { - Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64) - } else { - Type::array(&Type::i64(ccx), ((size + 7) / 8) as u64) - }; - arg.cast = Some(llty); + let align = arg.layout.align(ccx).abi(); + let total = arg.layout.size(ccx); + arg.cast_to(ccx, Uniform { + unit: if align <= 4 { Reg::i32() } else { Reg::i64() }, + total + }); } -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - } -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { - let align_fn = match flavor { - Flavor::General => general_ty_align as TyAlignFn, - Flavor::Ios => ios_ty_align as TyAlignFn, - }; - +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { - classify_ret_ty(ccx, &mut fty.ret, align_fn); + classify_ret_ty(ccx, &mut fty.ret); } for arg in &mut fty.args { if arg.is_ignore() { continue; } - classify_arg_ty(ccx, arg, align_fn); + classify_arg_ty(ccx, arg); } } diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_trans/cabi_asmjs.rs index f410627400c34..f05dda8bce21a 100644 --- a/src/librustc_trans/cabi_asmjs.rs +++ b/src/librustc_trans/cabi_asmjs.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use llvm::{Struct, Array}; -use abi::{FnType, ArgType, ArgAttribute}; +use abi::{FnType, ArgType, ArgAttribute, LayoutExt, Uniform}; use context::CrateContext; // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128 @@ -19,31 +16,31 @@ use context::CrateContext; // See the https://github.com/kripken/emscripten-fastcomp-clang repository. // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions. -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - match ret.ty.kind() { - Struct => { - let field_types = ret.ty.field_types(); - if field_types.len() == 1 { - ret.cast = Some(field_types[0]); - } else { - ret.make_indirect(ccx); +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() { + if let Some(unit) = ret.layout.homogenous_aggregate(ccx) { + let size = ret.layout.size(ccx); + if unit.size == size { + ret.cast_to(ccx, Uniform { + unit, + total: size + }); + return; } } - Array => { - ret.make_indirect(ccx); - } - _ => {} + + ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.is_aggregate() { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() { arg.make_indirect(ccx); arg.attrs.set(ArgAttribute::ByVal); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_trans/cabi_mips.rs index 25fe53e7ef40f..b7b60859d4a04 100644 --- a/src/librustc_trans/cabi_mips.rs +++ b/src/librustc_trans/cabi_mips.rs @@ -8,94 +8,40 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use libc::c_uint; use std::cmp; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, ArgType, FnType}; +use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; - -fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 4) -} -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 4) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i32(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i32()); + } } else { arg.extend_integer_width_to(32); } -} - -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); - let mut args = Vec::new(); - - let mut n = size / 32; - while n > 0 { - args.push(int_ty); - n -= 1; - } - let r = size % 32; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); - } - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs index e6b500c88dc7a..dff75e628de10 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_trans/cabi_mips64.rs @@ -8,94 +8,40 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use libc::c_uint; use std::cmp; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, ArgType, FnType}; +use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; - -fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 8) -} -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i64(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i64()); + } } else { arg.extend_integer_width_to(64); } -} - -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i64(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i64(ccx); - let mut args = Vec::new(); - - let mut n = size / 64; - while n > 0 { - args.push(int_ty); - n -= 1; - } - let r = size % 64; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); - } - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_trans/cabi_msp430.rs index aa90bb7ab753a..546bb5ad9b44e 100644 --- a/src/librustc_trans/cabi_msp430.rs +++ b/src/librustc_trans/cabi_msp430.rs @@ -11,17 +11,8 @@ // Reference: MSP430 Embedded Application Binary Interface // http://www.ti.com/lit/an/slaa534/slaa534.pdf -#![allow(non_upper_case_globals)] - -use llvm::Struct; - -use abi::{self, ArgType, FnType}; +use abi::{ArgType, FnType, LayoutExt}; use context::CrateContext; -use type_::Type; - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 2) -} // 3.5 Structures or Unions Passed and Returned by Reference // @@ -29,23 +20,23 @@ fn ty_size(ty: Type) -> usize { // returned by reference. To pass a structure or union by reference, the caller // places its address in the appropriate location: either in a register or on // the stack, according to its position in the argument list. (..)" -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 { ret.make_indirect(ccx); } else { ret.extend_integer_width_to(16); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 { arg.make_indirect(ccx); } else { arg.extend_integer_width_to(16); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_nvptx.rs b/src/librustc_trans/cabi_nvptx.rs index 5ece19f764a8a..3873752b25470 100644 --- a/src/librustc_trans/cabi_nvptx.rs +++ b/src/librustc_trans/cabi_nvptx.rs @@ -11,35 +11,26 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -#![allow(non_upper_case_globals)] - -use llvm::Struct; - -use abi::{self, ArgType, FnType}; +use abi::{ArgType, FnType, LayoutExt}; use context::CrateContext; -use type_::Type; - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 4) -} -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 { ret.make_indirect(ccx); } else { ret.extend_integer_width_to(32); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 { arg.make_indirect(ccx); } else { arg.extend_integer_width_to(32); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_nvptx64.rs b/src/librustc_trans/cabi_nvptx64.rs index 880c6cfd7a8ac..24bf4920c16c1 100644 --- a/src/librustc_trans/cabi_nvptx64.rs +++ b/src/librustc_trans/cabi_nvptx64.rs @@ -11,35 +11,26 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -#![allow(non_upper_case_globals)] - -use llvm::Struct; - -use abi::{self, ArgType, FnType}; +use abi::{ArgType, FnType, LayoutExt}; use context::CrateContext; -use type_::Type; - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) -} -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 { ret.make_indirect(ccx); } else { ret.extend_integer_width_to(64); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 { arg.make_indirect(ccx); } else { arg.extend_integer_width_to(64); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index 4e1d7a9337827..f951ac76391f6 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -8,100 +8,41 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::c_uint; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, FnType, ArgType}; +use abi::{align_up_to, FnType, ArgType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; use std::cmp; -fn ty_align(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_align(ty, 4) - } -} - -fn ty_size(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_size(ty, 4) - } -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i32(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i32()); + } } else { arg.extend_integer_width_to(32); } -} - -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double => true, - _ => false - }; -} -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); - let mut args = Vec::new(); - - let mut n = size / 32; - while n > 0 { - args.push(int_ty); - n -= 1; - } - - let r = size % 32; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); - } - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs index cdc7c1fd1afb3..c4f8d0b4b9637 100644 --- a/src/librustc_trans/cabi_powerpc64.rs +++ b/src/librustc_trans/cabi_powerpc64.rs @@ -8,100 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: The PowerPC64 ABI needs to zero or sign extend function -// call parameters, but compute_abi_info() is passed LLVM types -// which have no sign information. -// +// FIXME: // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array}; -use abi::{self, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; -use type_::Type; - -fn ty_size(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_size(ty, 8) - } -} - -fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { - fn check_array(ty: Type) -> Option<(Type, u64)> { - let len = ty.array_length() as u64; - if len == 0 { - return None - } - let elt = ty.element_type(); - - // if our element is an HFA/HVA, so are we; multiply members by our len - is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) - } - fn check_struct(ty: Type) -> Option<(Type, u64)> { - let str_tys = ty.field_types(); - if str_tys.len() == 0 { - return None - } +fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogenous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); - let mut prev_base_ty = None; - let mut members = 0; - for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { - match (prev_base_ty, opt_homog_agg) { - // field isn't itself an HFA, so we aren't either - (_, None) => return None, - - // first field - store its type and number of members - (None, Some((field_ty, field_members))) => { - prev_base_ty = Some(field_ty); - members = field_members; - }, - - // 2nd or later field - give up if it's a different type; otherwise incr. members - (Some(prev_ty), Some((field_ty, field_members))) => { - if prev_ty != field_ty { - return None; - } - members += field_members; - } - } + // Ensure we have at most eight uniquely addressable members. + if size > unit.size.checked_mul(8, ccx).unwrap() { + return None; } - // Because of previous checks, we know prev_base_ty is Some(...) because - // 1. str_tys has at least one element; and - // 2. prev_base_ty was filled in (or we would've returned early) - let (base_ty, members) = (prev_base_ty.unwrap(), members); - - // Ensure there is no padding. - if ty_size(ty) == ty_size(base_ty) * (members as usize) { - Some((base_ty, members)) - } else { - None - } - } + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 128 + }; - let homog_agg = match ty.kind() { - Float => Some((ty, 1)), - Double => Some((ty, 1)), - Array => check_array(ty), - Struct => check_struct(ty), - _ => None - }; - - // Ensure we have at most eight uniquely addressable members - homog_agg.and_then(|(base_ty, members)| { - if members > 0 && members <= 8 { - Some((base_ty, members)) + if valid_unit { + Some(Uniform { + unit, + total: size + }) } else { None } }) } -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); return; } @@ -111,78 +53,52 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { ret.make_indirect(ccx); } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { - ret.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); return; } - let size = ty_size(ret.ty); - if size <= 16 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - ret.cast = Some(llty); + + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { - arg.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); return; } - arg.cast = Some(struct_ty(ccx, arg.ty)); -} - -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double => true, - _ => false - } -} - -fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec { - let long_ty = Type::i64(ccx); - let mut args = Vec::new(); - - let mut n = size / 64; - while n > 0 { - args.push(long_ty); - n -= 1; - } - - let r = size % 64; - if r > 0 { - args.push(Type::ix(ccx, r as u64)); - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_long(ccx, size), false) + let total = arg.layout.size(ccx); + arg.cast_to(ccx, Uniform { + unit: Reg::i64(), + total + }); } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs index 5a666c6083d16..fedebea3f4c99 100644 --- a/src/librustc_trans/cabi_s390x.rs +++ b/src/librustc_trans/cabi_s390x.rs @@ -11,130 +11,60 @@ // FIXME: The assumes we're using the non-vector ABI, i.e. compiling // for a pre-z13 machine or using -mno-vx. -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{align_up_to, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg}; use context::CrateContext; -use type_::Type; -use std::cmp; +use rustc::ty::layout::{self, Layout, TyLayout}; -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - -fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - Vector => ty_size(ty), - _ => bug!("ty_align: unhandled type") - } -} - -fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() && ret.layout.size(ccx).bits() <= 64 { ret.extend_integer_width_to(64); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct { - fn is_single_fp_element(tys: &[Type]) -> bool { - if tys.len() != 1 { - return false; - } - match tys[0].kind() { - Float | Double => true, - Struct => is_single_fp_element(&tys[0].field_types()), - _ => false - } - } - - if is_single_fp_element(&arg.ty.field_types()) { - match ty_size(arg.ty) { - 4 => arg.cast = Some(Type::f32(ccx)), - 8 => arg.cast = Some(Type::f64(ccx)), - _ => arg.make_indirect(ccx) - } - } else { - match ty_size(arg.ty) { - 1 => arg.cast = Some(Type::i8(ccx)), - 2 => arg.cast = Some(Type::i16(ccx)), - 4 => arg.cast = Some(Type::i32(ccx)), - 8 => arg.cast = Some(Type::i64(ccx)), - _ => arg.make_indirect(ccx) +fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + layout: TyLayout<'tcx>) -> bool { + match *layout { + Layout::Scalar { value: layout::F32, .. } | + Layout::Scalar { value: layout::F64, .. } => true, + Layout::Univariant { .. } => { + if layout.field_count() == 1 { + is_single_fp_element(ccx, layout.field(ccx, 0)) + } else { + false } } - return; + _ => false } +} - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + let size = arg.layout.size(ccx); + if !arg.layout.is_aggregate() && size.bits() <= 64 { arg.extend_integer_width_to(64); - } else { - arg.make_indirect(ccx); + return; } -} -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double => ty_size(ty) <= 8, - _ => false + if is_single_fp_element(ccx, arg.layout) { + match size.bytes() { + 4 => arg.cast_to(ccx, Reg::f32()), + 8 => arg.cast_to(ccx, Reg::f64()), + _ => arg.make_indirect(ccx) + } + } else { + match size.bytes() { + 1 => arg.cast_to(ccx, Reg::i8()), + 2 => arg.cast_to(ccx, Reg::i16()), + 4 => arg.cast_to(ccx, Reg::i32()), + 8 => arg.cast_to(ccx, Reg::i64()), + _ => arg.make_indirect(ccx) + } } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_sparc.rs b/src/librustc_trans/cabi_sparc.rs index 25fe53e7ef40f..c17901e1adebc 100644 --- a/src/librustc_trans/cabi_sparc.rs +++ b/src/librustc_trans/cabi_sparc.rs @@ -8,94 +8,40 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use libc::c_uint; use std::cmp; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, ArgType, FnType}; +use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; - -fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 4) -} -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 4) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); - } else { - arg.extend_integer_width_to(32); - } -} - -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); - let mut args = Vec::new(); - let mut n = size / 32; - while n > 0 { - args.push(int_ty); - n -= 1; - } - - let r = size % 32; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i32(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i32()); } + } else { + arg.extend_integer_width_to(32) } - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_sparc64.rs b/src/librustc_trans/cabi_sparc64.rs index e675cca33d1be..b75fa97f948ec 100644 --- a/src/librustc_trans/cabi_sparc64.rs +++ b/src/librustc_trans/cabi_sparc64.rs @@ -10,170 +10,89 @@ // FIXME: This needs an audit for correctness and completeness. -use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array}; -use abi::{self, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_size(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_size(ty, 8) - } -} - -fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { - fn check_array(ty: Type) -> Option<(Type, u64)> { - let len = ty.array_length() as u64; - if len == 0 { - return None - } - let elt = ty.element_type(); - - // if our element is an HFA/HVA, so are we; multiply members by our len - is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) - } - - fn check_struct(ty: Type) -> Option<(Type, u64)> { - let str_tys = ty.field_types(); - if str_tys.len() == 0 { - return None - } - - let mut prev_base_ty = None; - let mut members = 0; - for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { - match (prev_base_ty, opt_homog_agg) { - // field isn't itself an HFA, so we aren't either - (_, None) => return None, +fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogenous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); - // first field - store its type and number of members - (None, Some((field_ty, field_members))) => { - prev_base_ty = Some(field_ty); - members = field_members; - }, - - // 2nd or later field - give up if it's a different type; otherwise incr. members - (Some(prev_ty), Some((field_ty, field_members))) => { - if prev_ty != field_ty { - return None; - } - members += field_members; - } - } + // Ensure we have at most eight uniquely addressable members. + if size > unit.size.checked_mul(8, ccx).unwrap() { + return None; } - // Because of previous checks, we know prev_base_ty is Some(...) because - // 1. str_tys has at least one element; and - // 2. prev_base_ty was filled in (or we would've returned early) - let (base_ty, members) = (prev_base_ty.unwrap(), members); - - // Ensure there is no padding. - if ty_size(ty) == ty_size(base_ty) * (members as usize) { - Some((base_ty, members)) - } else { - None - } - } - - let homog_agg = match ty.kind() { - Float => Some((ty, 1)), - Double => Some((ty, 1)), - Array => check_array(ty), - Struct => check_struct(ty), - _ => None - }; + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 128 + }; - // Ensure we have at most eight uniquely addressable members - homog_agg.and_then(|(base_ty, members)| { - if members > 0 && members <= 8 { - Some((base_ty, members)) + if valid_unit { + Some(Uniform { + unit, + total: size + }) } else { None } }) } -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); return; } - // don't return aggregates in registers - ret.make_indirect(ccx); - - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { - ret.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); return; } - let size = ty_size(ret.ty); - if size <= 16 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - ret.cast = Some(llty); + + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } + + // don't return aggregates in registers + ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { - arg.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); return; } - arg.cast = Some(struct_ty(ccx, arg.ty)); -} - -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double => true, - _ => false - } -} - -fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec { - let long_ty = Type::i64(ccx); - let mut args = Vec::new(); - - let mut n = size / 64; - while n > 0 { - args.push(long_ty); - n -= 1; - } - - let r = size % 64; - if r > 0 { - args.push(Type::ix(ccx, r as u64)); - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_long(ccx, size), false) + let total = arg.layout.size(ccx); + arg.cast_to(ccx, Uniform { + unit: Reg::i64(), + total + }); } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index fea005f3d77da..9f5520dabe334 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::*; -use abi::{ArgAttribute, FnType}; -use type_::Type; -use super::common::*; -use super::machine::*; +use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind}; +use common::CrateContext; #[derive(PartialEq)] pub enum Flavor { @@ -20,9 +17,11 @@ pub enum Flavor { Fastcall } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + fty: &mut FnType<'tcx>, + flavor: Flavor) { if !fty.ret.is_ignore() { - if fty.ret.ty.kind() == Struct { + if fty.ret.layout.is_aggregate() { // Returning a structure. Most often, this will use // a hidden first argument. On some platforms, though, // small structs are returned as integers. @@ -33,11 +32,12 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { let t = &ccx.sess().target.target; if t.options.is_like_osx || t.options.is_like_windows || t.options.is_like_openbsd { - match llsize_of_alloc(ccx, fty.ret.ty) { - 1 => fty.ret.cast = Some(Type::i8(ccx)), - 2 => fty.ret.cast = Some(Type::i16(ccx)), - 4 => fty.ret.cast = Some(Type::i32(ccx)), - 8 => fty.ret.cast = Some(Type::i64(ccx)), + let size = fty.ret.layout.size(ccx); + match size.bytes() { + 1 => fty.ret.cast_to(ccx, Reg::i8()), + 2 => fty.ret.cast_to(ccx, Reg::i16()), + 4 => fty.ret.cast_to(ccx, Reg::i32()), + 8 => fty.ret.cast_to(ccx, Reg::i64()), _ => fty.ret.make_indirect(ccx) } } else { @@ -50,7 +50,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { for arg in &mut fty.args { if arg.is_ignore() { continue; } - if arg.ty.kind() == Struct { + if arg.layout.is_aggregate() { arg.make_indirect(ccx); arg.attrs.set(ArgAttribute::ByVal); } else { @@ -73,12 +73,15 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { for arg in &mut fty.args { if arg.is_ignore() || arg.is_indirect() { continue; } - if arg.ty.kind() == Float { + // At this point we know this must be a primitive of sorts. + let unit = arg.layout.homogenous_aggregate(ccx).unwrap(); + let size = arg.layout.size(ccx); + assert_eq!(unit.size, size); + if unit.kind == RegKind::Float { continue; } - let size = llbitsize_of_real(ccx, arg.ty); - let size_in_regs = (size + 31) / 32; + let size_in_regs = (size.bits() + 31) / 32; if size_in_regs == 0 { continue; @@ -90,7 +93,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { free_regs -= size_in_regs; - if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) { + if size.bits() <= 32 && unit.kind == RegKind::Integer { arg.attrs.set(ArgAttribute::InReg); } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 7f2fdbf000b65..cbe170d85834c 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -11,388 +11,250 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp -#![allow(non_upper_case_globals)] -use self::RegClass::*; - -use llvm::{Integer, Pointer, Float, Double}; -use llvm::{Struct, Array, Vector}; -use abi::{self, ArgType, ArgAttribute, FnType}; +use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind}; use context::CrateContext; -use type_::Type; - -#[derive(Clone, Copy, PartialEq)] -enum RegClass { - NoClass, - Int, - SSEFs, - SSEFv, - SSEDs, - SSEDv, - SSEInt(/* bitwidth */ u64), - /// Data that can appear in the upper half of an SSE register. - SSEUp, - X87, - X87Up, - ComplexX87, - Memory -} - -trait TypeMethods { - fn is_reg_ty(&self) -> bool; -} - -impl TypeMethods for Type { - fn is_reg_ty(&self) -> bool { - match self.kind() { - Integer | Pointer | Float | Double => true, - _ => false - } - } -} - -impl RegClass { - fn is_sse(&self) -> bool { - match *self { - SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true, - _ => false - } - } -} - -trait ClassList { - fn is_pass_byval(&self) -> bool; - fn is_ret_bysret(&self) -> bool; -} - -impl ClassList for [RegClass] { - fn is_pass_byval(&self) -> bool { - if self.is_empty() { return false; } - - let class = self[0]; - class == Memory - || class == X87 - || class == ComplexX87 - } - fn is_ret_bysret(&self) -> bool { - if self.is_empty() { return false; } +use rustc::ty::layout::{self, Layout, TyLayout, Size}; - self[0] == Memory - } +#[derive(Clone, Copy, PartialEq, Debug)] +enum Class { + None, + Int, + Sse, + SseUp } -fn classify_ty(ty: Type) -> Vec { - fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return (off + a - 1) / a * a; - } - - fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 8) - } - - fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) - } - - fn all_mem(cls: &mut [RegClass]) { - for elt in cls { - *elt = Memory; - } - } - - fn unify(cls: &mut [RegClass], - i: usize, - newv: RegClass) { - if cls[i] == newv { return } +#[derive(Clone, Copy, Debug)] +struct Memory; - let to_write = match (cls[i], newv) { - (NoClass, _) => newv, - (_, NoClass) => return, +// Currently supported vector size (AVX). +const LARGEST_VECTOR_SIZE: usize = 256; +const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64; - (Memory, _) | - (_, Memory) => Memory, +fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>) + -> Result<[Class; MAX_EIGHTBYTES], Memory> { + fn unify(cls: &mut [Class], + off: u64, + c: Class) { + let i = (off / 8) as usize; + let to_write = match (cls[i], c) { + (Class::None, _) => c, + (_, Class::None) => return, - (Int, _) | - (_, Int) => Int, + (Class::Int, _) | + (_, Class::Int) => Class::Int, - (X87, _) | - (X87Up, _) | - (ComplexX87, _) | - (_, X87) | - (_, X87Up) | - (_, ComplexX87) => Memory, + (Class::Sse, _) | + (_, Class::Sse) => Class::Sse, - (SSEFv, SSEUp) | - (SSEFs, SSEUp) | - (SSEDv, SSEUp) | - (SSEDs, SSEUp) | - (SSEInt(_), SSEUp) => return, - - (..) => newv + (Class::SseUp, Class::SseUp) => Class::SseUp }; cls[i] = to_write; } - fn classify_struct(tys: &[Type], - cls: &mut [RegClass], - i: usize, - off: usize, - packed: bool) { - let mut field_off = off; - for ty in tys { - if !packed { - field_off = align(field_off, *ty); + fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + layout: TyLayout<'tcx>, + cls: &mut [Class], + off: u64) + -> Result<(), Memory> { + if off % layout.align(ccx).abi() != 0 { + if layout.size(ccx).bytes() > 0 { + return Err(Memory); } - classify(*ty, cls, i, field_off); - field_off += ty_size(*ty); + return Ok(()); } - } - fn classify(ty: Type, - cls: &mut [RegClass], ix: usize, - off: usize) { - let t_align = ty_align(ty); - let t_size = ty_size(ty); - - let misalign = off % t_align; - if misalign != 0 { - let mut i = off / 8; - let e = (off + t_size + 7) / 8; - while i < e { - unify(cls, ix + i, Memory); - i += 1; + match *layout { + Layout::Scalar { value, .. } | + Layout::RawNullablePointer { value, .. } => { + let reg = match value { + layout::Int(_) | + layout::Pointer => Class::Int, + layout::F32 | + layout::F64 => Class::Sse + }; + unify(cls, off, reg); } - return; - } - match ty.kind() { - Integer | - Pointer => { - unify(cls, ix + off / 8, Int); + Layout::CEnum { .. } => { + unify(cls, off, Class::Int); } - Float => { - if off % 8 == 4 { - unify(cls, ix + off / 8, SSEFv); - } else { - unify(cls, ix + off / 8, SSEFs); + + Layout::Vector { element, count } => { + unify(cls, off, Class::Sse); + + // everything after the first one is the upper + // half of a register. + let eltsz = element.size(ccx).bytes(); + for i in 1..count { + unify(cls, off + i * eltsz, Class::SseUp); } } - Double => { - unify(cls, ix + off / 8, SSEDs); - } - Struct => { - classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed()); - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - let mut i = 0; - while i < len { - classify(elt, cls, ix, off + i * eltsz); - i += 1; + + Layout::Array { count, .. } => { + if count > 0 { + let elt = layout.field(ccx, 0); + let eltsz = elt.size(ccx).bytes(); + for i in 0..count { + classify(ccx, elt, cls, off + i * eltsz)?; + } } } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - let mut reg = match elt.kind() { - Integer => SSEInt(elt.int_width()), - Float => SSEFv, - Double => SSEDv, - _ => bug!("classify: unhandled vector element type") - }; - let mut i = 0; - while i < len { - unify(cls, ix + (off + i * eltsz) / 8, reg); + Layout::Univariant { ref variant, .. } => { + for i in 0..layout.field_count() { + let field_off = off + variant.offsets[i].bytes(); + classify(ccx, layout.field(ccx, i), cls, field_off)?; + } + } - // everything after the first one is the upper - // half of a register. - reg = SSEUp; - i += 1; + Layout::UntaggedUnion { .. } => { + for i in 0..layout.field_count() { + classify(ccx, layout.field(ccx, i), cls, off)?; } } - _ => bug!("classify: unhandled type") + + Layout::FatPointer { .. } | + Layout::General { .. } | + Layout::StructWrappedNullablePointer { .. } => return Err(Memory) } + + Ok(()) + } + + let n = ((arg.layout.size(ccx).bytes() + 7) / 8) as usize; + if n > MAX_EIGHTBYTES { + return Err(Memory); } - fn fixup(ty: Type, cls: &mut [RegClass]) { + let mut cls = [Class::None; MAX_EIGHTBYTES]; + classify(ccx, arg.layout, &mut cls, 0)?; + if n > 2 { + if cls[0] != Class::Sse { + return Err(Memory); + } + if cls[1..n].iter().any(|&c| c != Class::SseUp) { + return Err(Memory); + } + } else { let mut i = 0; - let ty_kind = ty.kind(); - let e = cls.len(); - if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) { - if cls[i].is_sse() { + while i < n { + if cls[i] == Class::SseUp { + cls[i] = Class::Sse; + } else if cls[i] == Class::Sse { i += 1; - while i < e { - if cls[i] != SSEUp { - all_mem(cls); - return; - } - i += 1; - } + while i != n && cls[i] == Class::SseUp { i += 1; } } else { - all_mem(cls); - return - } - } else { - while i < e { - if cls[i] == Memory { - all_mem(cls); - return; - } - if cls[i] == X87Up { - // for darwin - // cls[i] = SSEDs; - all_mem(cls); - return; - } - if cls[i] == SSEUp { - cls[i] = SSEDv; - } else if cls[i].is_sse() { - i += 1; - while i != e && cls[i] == SSEUp { i += 1; } - } else if cls[i] == X87 { - i += 1; - while i != e && cls[i] == X87Up { i += 1; } - } else { - i += 1; - } + i += 1; } } } - let words = (ty_size(ty) + 7) / 8; - let mut cls = vec![NoClass; words]; - if words > 4 { - all_mem(&mut cls); - return cls; - } - classify(ty, &mut cls, 0, 0); - fixup(ty, &mut cls); - return cls; + Ok(cls) } -fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type { - fn llvec_len(cls: &[RegClass]) -> usize { - let mut len = 1; - for c in cls { - if *c != SSEUp { - break; - } - len += 1; - } - return len; +fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option { + if *i >= cls.len() { + return None; } - let mut tys = Vec::new(); - let mut i = 0; - let e = cls.len(); - while i < e { - match cls[i] { - Int => { - tys.push(Type::i64(ccx)); - } - SSEFv | SSEDv | SSEInt(_) => { - let (elts_per_word, elt_ty) = match cls[i] { - SSEFv => (2, Type::f32(ccx)), - SSEDv => (1, Type::f64(ccx)), - SSEInt(bits) => { - assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64, - "llreg_ty: unsupported SSEInt width {}", bits); - (64 / bits, Type::ix(ccx, bits)) + match cls[*i] { + Class::None => None, + Class::Int => { + *i += 1; + Some(match size { + 1 => Reg::i8(), + 2 => Reg::i16(), + 3 | + 4 => Reg::i32(), + _ => Reg::i64() + }) + } + Class::Sse => { + let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count(); + *i += vec_len; + Some(match size { + 4 => Reg::f32(), + 8 => Reg::f64(), + _ => { + Reg { + kind: RegKind::Vector, + size: Size::from_bytes(vec_len as u64 * 8) } - _ => bug!(), - }; - let vec_len = llvec_len(&cls[i + 1..]); - let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word); - tys.push(vec_ty); - i += vec_len; - continue; - } - SSEFs => { - tys.push(Type::f32(ccx)); - } - SSEDs => { - tys.push(Type::f64(ccx)); - } - _ => bug!("llregtype: unhandled class") + } + }) } - i += 1; + c => bug!("reg_component: unhandled class {:?}", c) } - if tys.len() == 1 && tys[0].kind() == Vector { - // if the type contains only a vector, pass it as that vector. - tys[0] +} + +fn cast_target(cls: &[Class], size: u64) -> CastTarget { + let mut i = 0; + let lo = reg_component(cls, &mut i, size).unwrap(); + let offset = i as u64 * 8; + let target = if size <= offset { + CastTarget::from(lo) } else { - Type::struct_(ccx, &tys, false) - } + let hi = reg_component(cls, &mut i, size - offset).unwrap(); + CastTarget::Pair(lo, hi) + }; + assert_eq!(reg_component(cls, &mut i, 0), None); + target } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - fn x86_64_ty(ccx: &CrateContext, - arg: &mut ArgType, - is_mem_cls: F, - ind_attr: Option) - where F: FnOnce(&[RegClass]) -> bool - { - if !arg.ty.is_reg_ty() { - let cls = classify_ty(arg.ty); - if is_mem_cls(&cls) { - arg.make_indirect(ccx); - if let Some(attr) = ind_attr { - arg.attrs.set(attr); +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { + let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 + let mut sse_regs = 8; // XMM0-7 + + let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| { + let cls = classify_arg(ccx, arg); + + let mut needed_int = 0; + let mut needed_sse = 0; + let in_mem = match cls { + Err(Memory) => true, + Ok(ref cls) if is_arg => { + for &c in cls { + match c { + Class::Int => needed_int += 1, + Class::Sse => needed_sse += 1, + _ => {} + } } - } else { - arg.cast = Some(llreg_ty(ccx, &cls)); + arg.layout.is_aggregate() && + (int_regs < needed_int || sse_regs < needed_sse) } - } else { - arg.extend_integer_width_to(32); - } - } + Ok(_) => false + }; - let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 - let mut sse_regs = 8; // XMM0-7 + if in_mem { + // `sret` / `byval` parameter thus one less integer register available + int_regs -= 1; - if !fty.ret.is_ignore() { - x86_64_ty(ccx, &mut fty.ret, |cls| { - if cls.is_ret_bysret() { - // `sret` parameter thus one less register available - int_regs -= 1; - true + arg.make_indirect(ccx); + if is_arg { + arg.attrs.set(ArgAttribute::ByVal); + } + } else { + // split into sized chunks passed individually + int_regs -= needed_int; + sse_regs -= needed_sse; + + if arg.layout.is_aggregate() { + let size = arg.layout.size(ccx).bytes(); + arg.cast_to(ccx, cast_target(cls.as_ref().unwrap(), size)) } else { - false + arg.extend_integer_width_to(32); } - }, None); + } + }; + + if !fty.ret.is_ignore() { + x86_64_ty(&mut fty.ret, false); } for arg in &mut fty.args { if arg.is_ignore() { continue; } - x86_64_ty(ccx, arg, |cls| { - let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize; - let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize; - let in_mem = cls.is_pass_byval() || - int_regs < needed_int || - sse_regs < needed_sse; - if in_mem { - // `byval` parameter thus one less integer register available - int_regs -= 1; - } else { - // split into sized chunks passed individually - int_regs -= needed_int; - sse_regs -= needed_sse; - } - in_mem - }, Some(ArgAttribute::ByVal)); - - // An integer, pointer, double or float parameter - // thus the above closure passed to `x86_64_ty` won't - // get called. - match arg.ty.kind() { - Integer | Pointer => int_regs -= 1, - Double | Float => sse_regs -= 1, - _ => {} - } + x86_64_ty(arg, true); } } diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs index a849f38247380..39e728d4e4f9b 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_trans/cabi_x86_win64.rs @@ -8,30 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::*; -use super::common::*; -use super::machine::*; -use abi::{ArgType, FnType}; -use type_::Type; +use abi::{ArgType, FnType, LayoutExt, Reg}; +use common::CrateContext; + +use rustc::ty::layout::Layout; // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - let fixup = |a: &mut ArgType| { - match a.ty.kind() { - Struct => match llsize_of_alloc(ccx, a.ty) { - 1 => a.cast = Some(Type::i8(ccx)), - 2 => a.cast = Some(Type::i16(ccx)), - 4 => a.cast = Some(Type::i32(ccx)), - 8 => a.cast = Some(Type::i64(ccx)), - _ => a.make_indirect(ccx) - }, - Integer => match llsize_of_alloc(ccx, a.ty) { - 1 ... 8 => a.extend_integer_width_to(32), - 16 => a.make_indirect(ccx), - _ => bug!(), - }, - _ => (), +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { + let fixup = |a: &mut ArgType<'tcx>| { + let size = a.layout.size(ccx); + if a.layout.is_aggregate() { + match size.bits() { + 8 => a.cast_to(ccx, Reg::i8()), + 16 => a.cast_to(ccx, Reg::i16()), + 32 => a.cast_to(ccx, Reg::i32()), + 64 => a.cast_to(ccx, Reg::i64()), + _ => a.make_indirect(ccx) + }; + } else { + if let Layout::Vector { .. } = *a.layout { + // FIXME(eddyb) there should be a size cap here + // (probably what clang calls "illegal vectors"). + } else if size.bytes() > 8 { + a.make_indirect(ccx); + } else { + a.extend_integer_width_to(32); + } } }; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 18893ce4ea9a6..caec4789eddce 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let llslot = match op.val { Immediate(_) | Pair(..) => { - let llscratch = bcx.alloca(ret.original_ty, "ret"); + let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret"); self.store_operand(&bcx, llscratch, None, op); llscratch } @@ -190,7 +190,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let load = bcx.load( bcx.pointercast(llslot, cast_ty.ptr_to()), - Some(llalign_of_min(bcx.ccx, ret.ty))); + Some(ret.layout.align(bcx.ccx).abi() as u32)); load } else { let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER)); @@ -516,7 +516,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { (llargs[0], &llargs[1..]) } ReturnDest::Nothing => { - (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..]) + (C_undef(fn_ty.ret.memory_ty(bcx.ccx).ptr_to()), &llargs[..]) } ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => (dst, &llargs[..]), @@ -535,7 +535,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Ref(dst, Alignment::AbiAligned), ty: sig.output(), }; - self.store_return(&bcx, ret_dest, fn_ty.ret, op); + self.store_return(&bcx, ret_dest, &fn_ty.ret, op); } if let Some((_, target)) = *destination { @@ -574,7 +574,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Immediate(invokeret), ty: sig.output(), }; - self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op); + self.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op); } } else { let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle); @@ -584,7 +584,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Immediate(llret), ty: sig.output(), }; - self.store_return(&bcx, ret_dest, fn_ty.ret, op); + self.store_return(&bcx, ret_dest, &fn_ty.ret, op); funclet_br(self, bcx, target); } else { bcx.unreachable(); @@ -598,7 +598,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx: &Builder<'a, 'tcx>, op: OperandRef<'tcx>, llargs: &mut Vec, - fn_ty: &FnType, + fn_ty: &FnType<'tcx>, next_idx: &mut usize, llfn: &mut Option, def: &Option>) { @@ -641,7 +641,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => { if arg.is_indirect() || arg.cast.is_some() { - let llscratch = bcx.alloca(arg.original_ty, "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); self.store_operand(bcx, llscratch, None, op); (llscratch, Alignment::AbiAligned, true) } else { @@ -653,7 +653,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't // have scary latent bugs around. - let llscratch = bcx.alloca(arg.original_ty, "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1)); (llscratch, Alignment::AbiAligned, true) } @@ -662,13 +662,13 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if arg.original_ty == Type::i1(bcx.ccx) { + if arg.layout.ty == bcx.tcx().types.bool { // We store bools as i8 so we need to truncate to i1. llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None); - llval = bcx.trunc(llval, arg.original_ty); + llval = bcx.trunc(llval, Type::i1(bcx.ccx)); } else if let Some(ty) = arg.cast { llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()), - align.min_with(llalign_of_min(bcx.ccx, arg.ty))); + align.min_with(arg.layout.align(bcx.ccx).abi() as u32)); } else { llval = bcx.load(llval, align.to_align()); } @@ -681,7 +681,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx: &Builder<'a, 'tcx>, operand: &mir::Operand<'tcx>, llargs: &mut Vec, - fn_ty: &FnType, + fn_ty: &FnType<'tcx>, next_idx: &mut usize, llfn: &mut Option, def: &Option>) { @@ -920,7 +920,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { fn store_return(&mut self, bcx: &Builder<'a, 'tcx>, dest: ReturnDest, - ret_ty: ArgType, + ret_ty: &ArgType<'tcx>, op: OperandRef<'tcx>) { use self::ReturnDest::*; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index cc957a4d25873..c8d15d28708f4 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -53,7 +53,7 @@ pub struct MirContext<'a, 'tcx:'a> { ccx: &'a CrateContext<'a, 'tcx>, - fn_ty: FnType, + fn_ty: FnType<'tcx>, /// When unwinding is initiated, we have to store this personality /// value somewhere so that we can load it and re-use it in the @@ -455,6 +455,23 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, assert_eq!((meta.cast, meta.pad), (None, None)); let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint); llarg_idx += 1; + + // FIXME(eddyb) As we can't perfectly represent the data and/or + // vtable pointer in a fat pointers in Rust's typesystem, and + // because we split fat pointers into two ArgType's, they're + // not the right type so we have to cast them for now. + let pointee = match arg_ty.sty { + ty::TyRef(_, ty::TypeAndMut{ty, ..}) | + ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => ty, + ty::TyAdt(def, _) if def.is_box() => arg_ty.boxed_ty(), + _ => bug!() + }; + let data_llty = type_of::in_memory_type_of(bcx.ccx, pointee); + let meta_llty = type_of::unsized_info_ty(bcx.ccx, pointee); + + let llarg = bcx.pointercast(llarg, data_llty.ptr_to()); + let llmeta = bcx.pointercast(llmeta, meta_llty); + OperandValue::Pair(llarg, llmeta) } else { OperandValue::Immediate(llarg) diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index c459191561dd6..d4ab6b0782855 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -19,122 +19,6 @@ use type_::Type; use syntax::ast; - -// A "sizing type" is an LLVM type, the size and alignment of which are -// guaranteed to be equivalent to what you would get out of `type_of()`. It's -// useful because: -// -// (1) It may be cheaper to compute the sizing type than the full type if all -// you're interested in is the size and/or alignment; -// -// (2) It won't make any recursive calls to determine the structure of the -// type behind pointers. This can help prevent infinite loops for -// recursive types. For example, enum types rely on this behavior. - -pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - if let Some(t) = cx.llsizingtypes().borrow().get(&t).cloned() { - return t; - } - - debug!("sizing_type_of {:?}", t); - let _recursion_lock = cx.enter_type_of(t); - - let ptr_sizing_ty = |ty: Ty<'tcx>| { - if cx.shared().type_is_sized(ty) { - Type::i8p(cx) - } else { - Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false) - } - }; - let llsizingty = match t.sty { - _ if !cx.shared().type_is_sized(t) => { - Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false) - } - - ty::TyBool => Type::bool(cx), - ty::TyChar => Type::char(cx), - ty::TyInt(t) => Type::int_from_ty(cx, t), - ty::TyUint(t) => Type::uint_from_ty(cx, t), - ty::TyFloat(t) => Type::float_from_ty(cx, t), - ty::TyNever => Type::nil(cx), - - ty::TyRef(_, ty::TypeAndMut{ty, ..}) | - ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { - ptr_sizing_ty(ty) - } - ty::TyAdt(def, _) if def.is_box() => { - ptr_sizing_ty(t.boxed_ty()) - } - - ty::TyFnDef(..) => Type::nil(cx), - ty::TyFnPtr(_) => Type::i8p(cx), - - ty::TyArray(ty, size) => { - let llty = sizing_type_of(cx, ty); - let size = size as u64; - Type::array(&llty, size) - } - - ty::TyTuple(ref tys, _) if tys.is_empty() => { - Type::nil(cx) - } - - ty::TyAdt(..) if t.is_simd() => { - let e = t.simd_type(cx.tcx()); - if !e.is_machine() { - cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - t, e)) - } - let llet = type_of(cx, e); - let n = t.simd_size(cx.tcx()) as u64; - Type::vector(&llet, n) - } - - ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => { - adt::sizing_type_of(cx, t, false) - } - - ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | - ty::TyAnon(..) | ty::TyError => { - bug!("fictitious type {:?} in sizing_type_of()", t) - } - ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!() - }; - - debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty); - - cx.llsizingtypes().borrow_mut().insert(t, llsizingty); - - // FIXME(eddyb) Temporary sanity check for ty::layout. - let layout = cx.layout_of(t); - if !cx.shared().type_is_sized(t) { - if !layout.is_unsized() { - bug!("layout should be unsized for type `{}` / {:#?}", - t, layout); - } - - // Unsized types get turned into a fat pointer for LLVM. - return llsizingty; - } - - let r = layout.size(cx).bytes(); - let l = machine::llsize_of_alloc(cx, llsizingty); - if r != l { - bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", - r, l, t, layout); - } - - let r = layout.align(cx).abi(); - let l = machine::llalign_of_min(cx, llsizingty) as u64; - if r != l { - bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", - r, l, t, layout); - } - - llsizingty -} - pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { match ty.sty { ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) | @@ -148,7 +32,7 @@ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> } } -fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { +pub fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { let unsized_part = ccx.tcx().struct_tail(ty); match unsized_part.sty { ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => { @@ -197,7 +81,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. /// For the LLVM type of a value as a whole, see `type_of`. -/// NB: If you update this, be sure to update `sizing_type_of()` as well. pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { // Check the cache. if let Some(&llty) = cx.lltypes().borrow().get(&t) { diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 76313b158ab11..bc84ac49da985 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -121,13 +121,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { fn str(_: &[u8]) { } -// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly) +// CHECK: @trait_borrow({}* nonnull, {}* noalias nonnull readonly) // FIXME #25759 This should also have `nocapture` #[no_mangle] fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly) +// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly) #[no_mangle] fn trait_box(_: Box) { } From f6e566185eaa4675cf2791ee69e63eb20ea01edb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 23:35:09 +0200 Subject: [PATCH 590/662] Implement Manually Drop --- src/libcore/mem.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f5cf3724d0711..f4a19af02a661 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -736,3 +736,99 @@ pub fn discriminant(v: &T) -> Discriminant { } } + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// # #![feature(manually_drop)] +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +#[unstable(feature = "manually_drop", issue = "40673")] +#[allow(unions_with_drop_fields)] +pub union ManuallyDrop{ value: T } + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + #[unstable(feature = "manually_drop", issue = "40673")] + pub fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + #[unstable(feature = "manually_drop", issue = "40673")] + pub fn into_inner(self) -> T { + unsafe { + self.value + } + } + + /// Manually drops the contained value. + /// + /// # Unsafety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + #[unstable(feature = "manually_drop", issue = "40673")] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::Deref for ManuallyDrop { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::DerefMut for ManuallyDrop { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::fmt::Debug for ManuallyDrop { + fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { + unsafe { + fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() + } + } +} From 38713126dd8502e283aa8ec7c6b678a4c43f8c3b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 19:11:51 +0200 Subject: [PATCH 591/662] Move away from the ad-hoc NoDrop unions --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 12 ++------ src/libcore/slice/sort.rs | 30 ++++++++---------- src/librustc_data_structures/array_vec.rs | 37 +++++------------------ src/librustc_data_structures/lib.rs | 1 + 5 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f6..b474bd5d91af1 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -44,6 +44,7 @@ #![feature(heap_api)] #![feature(inclusive_range)] #![feature(lang_items)] +#![feature(manually_drop)] #![feature(nonzero)] #![feature(pattern)] #![feature(placement_in)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6cff315a6ccd9..3069adb12e92c 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1558,7 +1558,7 @@ fn insert_head(v: &mut [T], is_less: &mut F) // performance than with the 2nd method. // // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let mut tmp = NoDrop { value: ptr::read(&v[0]) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); // Intermediate state of the insertion process is always tracked by `hole`, which // serves two purposes: @@ -1571,13 +1571,13 @@ fn insert_head(v: &mut [T], is_less: &mut F) // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it // initially held exactly once. let mut hole = InsertionHole { - src: &mut tmp.value, + src: &mut *tmp, dest: &mut v[1], }; ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); for i in 2..v.len() { - if !is_less(&v[i], &tmp.value) { + if !is_less(&v[i], &*tmp) { break; } ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); @@ -1587,12 +1587,6 @@ fn insert_head(v: &mut [T], is_less: &mut F) } } - // Holds a value, but never drops it. - #[allow(unions_with_drop_fields)] - union NoDrop { - value: T - } - // When dropped, copies from `src` into `dest`. struct InsertionHole { src: *mut T, diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 7065fdb79fc40..6f9f2915dfe10 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -20,12 +20,6 @@ use cmp; use mem; use ptr; -/// Holds a value, but never drops it. -#[allow(unions_with_drop_fields)] -union NoDrop { - value: T -} - /// When dropped, copies from `src` into `dest`. struct CopyOnDrop { src: *mut T, @@ -49,15 +43,15 @@ fn shift_head(v: &mut [T], is_less: &mut F) // Read the first element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(1), }; ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); for i in 2..len { - if !is_less(v.get_unchecked(i), &tmp.value) { + if !is_less(v.get_unchecked(i), &*tmp) { break; } @@ -81,15 +75,15 @@ fn shift_tail(v: &mut [T], is_less: &mut F) // Read the last element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(len - 2), }; ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1); for i in (0..len-2).rev() { - if !is_less(&tmp.value, v.get_unchecked(i)) { + if !is_less(&*tmp, v.get_unchecked(i)) { break; } @@ -403,12 +397,12 @@ fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Find the first pair of out-of-order elements. let mut l = 0; @@ -452,12 +446,12 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Now partition the slice. let mut l = 0; diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 29fbcb70756ba..adb2219722602 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -20,10 +20,11 @@ use std::fmt; use std::mem; use std::collections::range::RangeArgument; use std::collections::Bound::{Excluded, Included, Unbounded}; +use std::mem::ManuallyDrop; pub unsafe trait Array { type Element; - type PartialStorage: Default + Unsize<[ManuallyDrop]>; + type PartialStorage: Unsize<[ManuallyDrop]>; const LEN: usize; } @@ -66,7 +67,7 @@ impl ArrayVec { pub fn new() -> Self { ArrayVec { count: 0, - values: Default::default(), + values: unsafe { ::std::mem::uninitialized() }, } } @@ -81,7 +82,7 @@ impl ArrayVec { /// Panics when the stack vector is full. pub fn push(&mut self, el: A::Element) { let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count] = ManuallyDrop { value: el }; + arr[self.count] = ManuallyDrop::new(el); self.count += 1; } @@ -90,8 +91,8 @@ impl ArrayVec { let arr = &mut self.values as &mut [ManuallyDrop<_>]; self.count -= 1; unsafe { - let value = ptr::read(&arr[self.count]); - Some(value.value) + let value = ptr::read(&*arr[self.count]); + Some(value) } } else { None @@ -210,7 +211,7 @@ impl Iterator for Iter { fn next(&mut self) -> Option { let arr = &self.store as &[ManuallyDrop<_>]; unsafe { - self.indices.next().map(|i| ptr::read(&arr[i]).value) + self.indices.next().map(|i| ptr::read(&*arr[i])) } } @@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value }) + self.iter.next().map(|elt| unsafe { ptr::read(&**elt) }) } fn size_hint(&self) -> (usize, Option) { @@ -295,25 +296,3 @@ impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { self.iter_mut() } } - -// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. -#[allow(unions_with_drop_fields)] -pub union ManuallyDrop { - value: T, - #[allow(dead_code)] - empty: (), -} - -impl ManuallyDrop { - fn new() -> ManuallyDrop { - ManuallyDrop { - empty: () - } - } -} - -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new() - } -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index c1735b4a4ec9a..72c533a74618b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -39,6 +39,7 @@ #![feature(conservative_impl_trait)] #![feature(discriminant_value)] #![feature(specialization)] +#![feature(manually_drop)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] From c94b3f1266779c595e28111e39f47e5e14a34ef2 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:13:31 +0300 Subject: [PATCH 592/662] Replace the `forget` intrinsic with ManuallyDrop less intrinsics = better life --- src/libcore/intrinsics.rs | 3 --- src/libcore/mem.rs | 7 ++++++- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 1 - 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e0a4707ff665f..b028763158512 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -691,9 +691,6 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; - /// Moves a value out of scope without running drop glue. - pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f4a19af02a661..52ccaa417bc5f 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -171,7 +171,7 @@ pub use intrinsics::transmute; #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { - unsafe { intrinsics::forget(t) } + ManuallyDrop::new(t); } /// Returns the size of a type in bytes. @@ -780,12 +780,14 @@ pub union ManuallyDrop{ value: T } impl ManuallyDrop { /// Wrap a value to be manually dropped. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub fn new(value: T) -> ManuallyDrop { ManuallyDrop { value: value } } /// Extract the value from the ManuallyDrop container. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub fn into_inner(self) -> T { unsafe { self.value @@ -800,6 +802,7 @@ impl ManuallyDrop { /// now represents uninitialized data. It is up to the user of this method to ensure the /// uninitialized data is not actually used. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub unsafe fn drop(slot: &mut ManuallyDrop) { ptr::drop_in_place(&mut slot.value) } @@ -808,6 +811,7 @@ impl ManuallyDrop { #[unstable(feature = "manually_drop", issue = "40673")] impl ::ops::Deref for ManuallyDrop { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { unsafe { &self.value @@ -817,6 +821,7 @@ impl ::ops::Deref for ManuallyDrop { #[unstable(feature = "manually_drop", issue = "40673")] impl ::ops::DerefMut for ManuallyDrop { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut self.value diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5e7d612d17f82..0cbc103994ad9 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -188,7 +188,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, C_nil(ccx) } // Effectively no-ops - "uninit" | "forget" => { + "uninit" => { C_nil(ccx) } "needs_drop" => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 2861fd288326b..cd58fcd4806da 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -124,7 +124,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), - "forget" => (1, vec![ param(0) ], tcx.mk_nil()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, From 486345551c09612aa87155304a20e6b8de492939 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:15:59 +0300 Subject: [PATCH 593/662] into_inner to associated function --- src/libcore/mem.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 52ccaa417bc5f..7be927b28ed7e 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -779,6 +779,14 @@ pub union ManuallyDrop{ value: T } impl ManuallyDrop { /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` #[unstable(feature = "manually_drop", issue = "40673")] #[inline] pub fn new(value: T) -> ManuallyDrop { @@ -786,11 +794,20 @@ impl ManuallyDrop { } /// Extract the value from the ManuallyDrop container. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); + /// ``` #[unstable(feature = "manually_drop", issue = "40673")] #[inline] - pub fn into_inner(self) -> T { + pub fn into_inner(slot: ManuallyDrop) -> T { unsafe { - self.value + slot.value } } From c337b99f4cb0968481a03195d25358b484d7db22 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:16:17 +0300 Subject: [PATCH 594/662] Fix test failures --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/manually-drop.md | 0 src/test/compile-fail/forget-init-unsafe.rs | 3 +-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/manually-drop.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index d86766bac02a2..90499f3ce8590 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -113,6 +113,7 @@ - [loop_break_value](loop-break-value.md) - [macro_reexport](macro-reexport.md) - [main](main.md) +- [manually_drop](manually-drop.md) - [map_entry_recover_keys](map-entry-recover-keys.md) - [mpsc_select](mpsc-select.md) - [n16](n16.md) diff --git a/src/doc/unstable-book/src/manually-drop.md b/src/doc/unstable-book/src/manually-drop.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/test/compile-fail/forget-init-unsafe.rs b/src/test/compile-fail/forget-init-unsafe.rs index 521f122f8af0b..48c9fda31e8c8 100644 --- a/src/test/compile-fail/forget-init-unsafe.rs +++ b/src/test/compile-fail/forget-init-unsafe.rs @@ -10,10 +10,9 @@ #![feature(core_intrinsics)] -use std::intrinsics::{init, forget}; +use std::intrinsics::{init}; // Test that the `forget` and `init` intrinsics are really unsafe pub fn main() { let stuff = init::(); //~ ERROR call to unsafe function requires unsafe - forget(stuff); //~ ERROR call to unsafe function requires unsafe } From d4aecf52dba643bf938a572d506995c5cad4602e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 9 Apr 2017 18:31:59 +0200 Subject: [PATCH 595/662] Fix block code headers parsing --- src/librustdoc/html/markdown.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1e687d63f5875..dca873a85d813 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -471,20 +471,26 @@ impl LangString { for token in tokens { match token { "" => {}, - "should_panic" => { data.should_panic = true; seen_rust_tags = true; }, - "no_run" => { data.no_run = true; seen_rust_tags = true; }, - "ignore" => { data.ignore = true; seen_rust_tags = true; }, - "rust" => { data.rust = true; seen_rust_tags = true; }, - "test_harness" => { data.test_harness = true; seen_rust_tags = true; }, + "should_panic" => { + data.should_panic = true; + seen_rust_tags = seen_other_tags == false; + } + "no_run" => { data.no_run = true; seen_rust_tags = seen_other_tags == false; } + "ignore" => { data.ignore = true; seen_rust_tags = seen_other_tags == false; } + "rust" => { data.rust = true; seen_rust_tags = true; } + "test_harness" => { + data.test_harness = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; data.no_run = true; } x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { if let Ok(_) = x[1..].parse::() { data.error_codes.push(x.to_owned()); - seen_rust_tags = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; } else { seen_other_tags = true; } @@ -670,9 +676,10 @@ mod tests { t("test_harness", false, false, false, true, true, false, Vec::new()); t("compile_fail", false, true, false, true, false, true, Vec::new()); t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); - t("{.sh .should_panic}", true, false, false, true, false, false, Vec::new()); + t("{.sh .should_panic}", true, false, false, false, false, false, Vec::new()); t("{.example .rust}", false, false, false, true, false, false, Vec::new()); t("{.test_harness .rust}", false, false, false, true, true, false, Vec::new()); + t("text, no_run", false, true, false, false, false, false, Vec::new()); } #[test] From f789d896cbb8b5622d07cf45261b11ebfee73e37 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 19 Mar 2017 11:46:56 -0400 Subject: [PATCH 596/662] Print tidy errors to stderr, prefix with 'tidy error: ', handle 'bad' state. --- src/tools/tidy/src/bins.rs | 3 +-- src/tools/tidy/src/cargo.rs | 5 ++--- src/tools/tidy/src/errors.rs | 5 ++--- src/tools/tidy/src/features.rs | 9 +++------ src/tools/tidy/src/main.rs | 9 +++++++++ src/tools/tidy/src/pal.rs | 3 +-- src/tools/tidy/src/style.rs | 6 ++---- src/tools/tidy/src/unstable_book.rs | 31 +++++++++++++---------------- 8 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index ef93b0858b02f..11d5dbe736e81 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -62,8 +62,7 @@ pub fn check(path: &Path, bad: &mut bool) { }); let path_bytes = rel_path.as_os_str().as_bytes(); if output.status.success() && output.stdout.starts_with(path_bytes) { - println!("binary checked into source: {}", file.display()); - *bad = true; + tidy_error!(bad, "binary checked into source: {}", file.display()); } } }) diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index 053f0bbe3b81d..c8c6cb0ee6b41 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -100,9 +100,8 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { } if !librs.contains(&format!("extern crate {}", krate)) { - println!("{} doesn't have `extern crate {}`, but Cargo.toml \ - depends on it", libfile.display(), krate); - *bad = true; + tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \ + depends on it", libfile.display(), krate); } } } diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs index 3a70e54ff9745..5bf7c894cda66 100644 --- a/src/tools/tidy/src/errors.rs +++ b/src/tools/tidy/src/errors.rs @@ -79,11 +79,10 @@ pub fn check(path: &Path, bad: &mut bool) { continue } - println!("duplicate error code: {}", code); + tidy_error!(bad, "duplicate error code: {}", code); for &(ref file, line_num, ref line) in entries.iter() { - println!("{}:{}: {}", file.display(), line_num, line); + tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line); } - *bad = true; } if !*bad { diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index e1fdc19c27d25..ad0d2fa0b3635 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -77,8 +77,7 @@ pub fn check(path: &Path, bad: &mut bool) { for (i, line) in contents.lines().enumerate() { let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; + tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; let gate_test_str = "gate-test-"; @@ -126,8 +125,7 @@ pub fn check(path: &Path, bad: &mut bool) { } if gate_untested.len() > 0 { - println!("Found {} features without a gate test.", gate_untested.len()); - *bad = true; + tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len()); } if *bad { @@ -221,8 +219,7 @@ pub fn collect_lib_features(base_src_path: &Path, for (i, line) in contents.lines().enumerate() { let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; + tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; let level = if line.contains("[unstable(") { Status::Unstable diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index d0e8cf9c343dc..dee37341051ed 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -34,6 +34,15 @@ macro_rules! t { }) } +macro_rules! tidy_error { + ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ + use std::io::Write; + *$bad = true; + write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr"); + writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr"); + }); +} + mod bins; mod style; mod errors; diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 3808c05c6b939..cb323bd1d28ce 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -126,8 +126,7 @@ fn check_cfgs(contents: &mut String, file: &Path, Ok(_) => unreachable!(), Err(i) => i + 1 }; - println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg); - *bad = true; + tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg); }; for (idx, cfg) in cfgs.into_iter() { diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2233f8c352974..081390eb93ca4 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -112,8 +112,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_length = contents.contains("ignore-tidy-linelength"); for (i, line) in contents.split("\n").enumerate() { let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; + tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; if !skip_length && line.chars().count() > COLS && !long_line_is_ok(line) { @@ -138,8 +137,7 @@ pub fn check(path: &Path, bad: &mut bool) { } } if !licenseck(file, &contents) { - println!("{}: incorrect license", file.display()); - *bad = true; + tidy_error!(bad, "{}: incorrect license", file.display()); } }) } diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index c10e31077944f..2d3d9e80257f9 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -10,7 +10,7 @@ use std::collections::HashSet; use std::fs; -use std::io::{self, BufRead, Write}; +use std::io::{self, BufRead}; use std::path; use features::{collect_lang_features, collect_lib_features, Status}; @@ -110,29 +110,26 @@ pub fn check(path: &path::Path, bad: &mut bool) { // Check for Unstable Book section names with no corresponding SUMMARY.md link for feature_name in &unstable_book_section_file_names - &unstable_book_links { - *bad = true; - writeln!(io::stderr(), - "The Unstable Book section '{}' needs to have a link in SUMMARY.md", - feature_name) - .expect("could not write to stderr") + tidy_error!( + bad, + "The Unstable Book section '{}' needs to have a link in SUMMARY.md", + feature_name); } // Check for unstable features that don't have Unstable Book sections for feature_name in &unstable_feature_names - &unstable_book_section_file_names { - *bad = true; - writeln!(io::stderr(), - "Unstable feature '{}' needs to have a section in The Unstable Book", - feature_name) - .expect("could not write to stderr") + tidy_error!( + bad, + "Unstable feature '{}' needs to have a section in The Unstable Book", + feature_name); } // Check for Unstable Book sections that don't have a corresponding unstable feature for feature_name in &unstable_book_section_file_names - &unstable_feature_names { - *bad = true; - writeln!(io::stderr(), - "The Unstable Book has a section '{}' which doesn't correspond \ - to an unstable feature", - feature_name) - .expect("could not write to stderr") + tidy_error!( + bad, + "The Unstable Book has a section '{}' which doesn't correspond \ + to an unstable feature", + feature_name) } } From 7da12c8541c1977757f8f0e2368d3e5ef817de84 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Mar 2017 13:06:53 +1300 Subject: [PATCH 597/662] Add the RLS as a submodule --- .gitmodules | 4 ++++ rls | 1 + 2 files changed, 5 insertions(+) create mode 160000 rls diff --git a/.gitmodules b/.gitmodules index 3533f0df5d1ce..4f29cef85700e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,7 @@ [submodule "book"] path = src/doc/book url = https://github.com/rust-lang/book.git +[submodule "rls"] + path = rls + url = https://github.com/rust-lang-nursery/rls.git + diff --git a/rls b/rls new file mode 160000 index 0000000000000..e24fc84bfc4b3 --- /dev/null +++ b/rls @@ -0,0 +1 @@ +Subproject commit e24fc84bfc4b3360a3d65d9adeab0f701140094d From c55325e0f7252d67bda60695497751b63f51931d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 17 Mar 2017 09:52:12 +1300 Subject: [PATCH 598/662] Build an RLS package as part of the dist target --- src/bootstrap/dist.rs | 93 ++++++++++++++++++++++++++++++++++++++++++- src/bootstrap/lib.rs | 15 +++++++ src/bootstrap/step.rs | 11 +++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6472b1a928caf..d2c9e248e03a8 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -393,6 +393,7 @@ pub fn rust_src(build: &Build) { "man", "src", "cargo", + "rls", ]; let filter_fn = move |path: &Path| { @@ -593,6 +594,43 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { build.run(&mut cmd); } +pub fn rls(build: &Build, stage: u32, target: &str) { + println!("Dist RLS stage{} ({})", stage, target); + let compiler = Compiler::new(stage, &build.config.build); + + let src = build.src.join("rls"); + let release_num = build.rls_release_num(); + let name = format!("rls-{}", build.package_vers(&release_num)); + + let tmp = tmpdir(build); + let image = tmp.join("rls-image"); + drop(fs::remove_dir_all(&image)); + t!(fs::create_dir_all(&image)); + + // Prepare the image directory + let rls = build.cargo_out(&compiler, Mode::Tool, target) + .join(exe("rls", target)); + install(&rls, &image.join("bin"), 0o755); + let doc = image.join("share/doc/rls"); + install(&src.join("README.md"), &doc, 0o644); + install(&src.join("LICENSE-MIT"), &doc, 0o644); + install(&src.join("LICENSE-APACHE"), &doc, 0o644); + + // Generate the installer tarball + let mut cmd = Command::new("sh"); + cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=RLS-ready-to-serve.") + .arg(format!("--image-dir={}", sanitize_sh(&image))) + .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) + .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--component-name=rls") + .arg("--legacy-manifest-dirs=rustlib,cargo"); + build.run(&mut cmd); +} + /// Creates a combined installer for the specified target in the provided stage. pub fn extended(build: &Build, stage: u32, target: &str) { println!("Dist extended stage{} ({})", stage, target); @@ -604,6 +642,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let cargo_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "cargo"), target)); + let rls_installer = dist.join(format!("{}.tar.gz", + pkgname(build, "rls"))); + let analysis_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rust-analysis"), + target)); let docs_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-docs"), target)); @@ -631,9 +674,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - let mut input_tarballs = format!("{},{},{},{}", + let mut input_tarballs = format!("{},{},{},{},{},{}", sanitize_sh(&rustc_installer), sanitize_sh(&cargo_installer), + sanitize_sh(&rls_installer), + sanitize_sh(&analysis_installer), sanitize_sh(&docs_installer), sanitize_sh(&std_installer)); if target.contains("pc-windows-gnu") { @@ -675,6 +720,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&pkg); t!(fs::create_dir_all(pkg.join("rustc"))); t!(fs::create_dir_all(pkg.join("cargo"))); + t!(fs::create_dir_all(pkg.join("rls"))); + t!(fs::create_dir_all(pkg.join("rust-analysis"))); t!(fs::create_dir_all(pkg.join("rust-docs"))); t!(fs::create_dir_all(pkg.join("rust-std"))); @@ -682,6 +729,10 @@ pub fn extended(build: &Build, stage: u32, target: &str) { &pkg.join("rustc")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)), &pkg.join("cargo")); + cp_r(&work.join(pkgname(build, "rls")), + &pkg.join("rls")); + cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)), + &pkg.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)), &pkg.join("rust-docs")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)), @@ -689,6 +740,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755); + install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755); + install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755); @@ -702,6 +755,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { }; pkgbuild("rustc"); pkgbuild("cargo"); + pkgbuild("rls"); + pkgbuild("rust-analysis"); pkgbuild("rust-docs"); pkgbuild("rust-std"); @@ -727,6 +782,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&exe); t!(fs::create_dir_all(exe.join("rustc"))); t!(fs::create_dir_all(exe.join("cargo"))); + t!(fs::create_dir_all(exe.join("rls"))); + t!(fs::create_dir_all(exe.join("rust-analysis"))); t!(fs::create_dir_all(exe.join("rust-docs"))); t!(fs::create_dir_all(exe.join("rust-std"))); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)) @@ -735,6 +792,12 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)) .join("cargo"), &exe.join("cargo")); + cp_r(&work.join(pkgname(build, "rls")) + .join("rls"), + &exe.join("rls")); + cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)) + .join("rust-analysis"), + &exe.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)) .join("rust-docs"), &exe.join("rust-docs")); @@ -744,6 +807,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { t!(fs::remove_file(exe.join("rustc/manifest.in"))); t!(fs::remove_file(exe.join("cargo/manifest.in"))); + t!(fs::remove_file(exe.join("rls/manifest.in"))); + t!(fs::remove_file(exe.join("rust-analysis/manifest.in"))); t!(fs::remove_file(exe.join("rust-docs/manifest.in"))); t!(fs::remove_file(exe.join("rust-std/manifest.in"))); @@ -800,6 +865,26 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-var").arg("var.DocsDir") .arg("-out").arg(exe.join("DocsGroup.wxs")) .arg("-t").arg(etc.join("msi/squash-components.xsl"))); + build.run(Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rls") + .args(&heat_flags) + .arg("-cg").arg("RlsGroup") + .arg("-dr").arg("Rls") + .arg("-var").arg("var.RlsDir") + .arg("-out").arg(exe.join("RlsGroup.wxs")) + .arg("-t").arg(etc.join("msi/squash-components.xsl"))); + build.run(Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-analysis") + .args(&heat_flags) + .arg("-cg").arg("AnalysisGroup") + .arg("-dr").arg("Analysis") + .arg("-var").arg("var.AnalysisDir") + .arg("-out").arg(exe.join("AnalysisGroup.wxs")) + .arg("-t").arg(etc.join("msi/squash-components.xsl"))); build.run(Command::new(&heat) .current_dir(&exe) .arg("dir") @@ -840,6 +925,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-nologo") .arg("-dRustcDir=rustc") .arg("-dDocsDir=rust-docs") + .arg("-dRlsDir=rls") + .arg("-dAnalysisDir=rust-analysis") .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") .arg("-arch").arg(&arch) @@ -857,6 +944,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { candle(&etc.join("msi/rustwelcomedlg.wxs")); candle("RustcGroup.wxs".as_ref()); candle("DocsGroup.wxs".as_ref()); + candle("RlsGroup.wxs".as_ref()); + candle("AnalysisGroup.wxs".as_ref()); candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); @@ -879,6 +968,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("rustwelcomedlg.wixobj") .arg("RustcGroup.wixobj") .arg("DocsGroup.wixobj") + .arg("RlsGroup.wixobj") + .arg("AnalysisGroup.wixobj") .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") .current_dir(&exe); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8303a40bb6965..81ab2b0d1cef2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1044,6 +1044,21 @@ impl Build { panic!("failed to find version in cargo's Cargo.toml") } + /// Returns the `a.b.c` version that the RLS is at. + fn rls_release_num(&self) -> String { + let mut toml = String::new(); + t!(t!(File::open(self.src.join("rls/Cargo.toml"))).read_to_string(&mut toml)); + for line in toml.lines() { + let prefix = "version = \""; + let suffix = "\""; + if line.starts_with(prefix) && line.ends_with(suffix) { + return line[prefix.len()..line.len() - suffix.len()].to_string() + } + } + + panic!("failed to find version in the RLS's Cargo.toml") + } + /// Returns whether unstable features should be enabled for the compiler /// we're building. fn unstable_features(&self) -> bool { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 5560b5b0333c8..d1581576957dc 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -570,6 +570,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .host(&build.config.build) }) .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); + rules.build("tool-rls", "rls") + .host(true) + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "rls")); // ======================================================================== // Documentation targets @@ -694,6 +698,11 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .default(true) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); + rules.dist("dist-rls", "rls") + .host(true) + .only_host_build(true) + .dep(|s| s.name("tool-rls")) + .run(move |s| dist::rls(build, s.stage, s.target)); rules.dist("install", "path/to/nowhere") .dep(|s| s.name("default:dist")) .run(move |s| install::install(build, s.stage, s.target)); @@ -711,6 +720,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|d| d.name("dist-mingw")) .dep(|d| d.name("dist-docs")) .dep(|d| d.name("dist-cargo")) + .dep(|d| d.name("dist-rls")) + .dep(|d| d.name("dist-analysis")) .run(move |s| dist::extended(build, s.stage, s.target)); rules.dist("dist-sign", "hash-and-sign") From 223b280f31622e6292653c5b5a0755657e514524 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 28 Mar 2017 08:00:46 +1300 Subject: [PATCH 599/662] Reviewer changes --- rls | 2 +- src/bootstrap/dist.rs | 59 ++++------------------------ src/bootstrap/lib.rs | 26 +++--------- src/tools/build-manifest/src/main.rs | 5 +++ 4 files changed, 19 insertions(+), 73 deletions(-) diff --git a/rls b/rls index e24fc84bfc4b3..88fc39bd654c5 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit e24fc84bfc4b3360a3d65d9adeab0f701140094d +Subproject commit 88fc39bd654c536b4f8f1cd1fc8245706f0284ec diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d2c9e248e03a8..88a3441d42015 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -40,7 +40,7 @@ fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) } else { - assert!(component.starts_with("rust")); + assert!(component.starts_with("rust") || component == "rls"); format!("{}-{}", component, build.rust_package_vers()) } } @@ -540,7 +540,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { let src = build.src.join("cargo"); let etc = src.join("src/etc"); - let release_num = build.cargo_release_num(); + let release_num = build.release_num("cargo"); let name = pkgname(build, "cargo"); let version = build.cargo_info.version(build, &release_num); @@ -599,7 +599,7 @@ pub fn rls(build: &Build, stage: u32, target: &str) { let compiler = Compiler::new(stage, &build.config.build); let src = build.src.join("rls"); - let release_num = build.rls_release_num(); + let release_num = build.release_num("rls"); let name = format!("rls-{}", build.package_vers(&release_num)); let tmp = tmpdir(build); @@ -642,8 +642,9 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let cargo_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "cargo"), target)); - let rls_installer = dist.join(format!("{}.tar.gz", - pkgname(build, "rls"))); + let rls_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rls"), + target)); let analysis_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-analysis"), target)); @@ -720,8 +721,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&pkg); t!(fs::create_dir_all(pkg.join("rustc"))); t!(fs::create_dir_all(pkg.join("cargo"))); - t!(fs::create_dir_all(pkg.join("rls"))); - t!(fs::create_dir_all(pkg.join("rust-analysis"))); t!(fs::create_dir_all(pkg.join("rust-docs"))); t!(fs::create_dir_all(pkg.join("rust-std"))); @@ -729,10 +728,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { &pkg.join("rustc")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)), &pkg.join("cargo")); - cp_r(&work.join(pkgname(build, "rls")), - &pkg.join("rls")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)), - &pkg.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)), &pkg.join("rust-docs")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)), @@ -740,8 +735,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755); @@ -755,8 +748,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { }; pkgbuild("rustc"); pkgbuild("cargo"); - pkgbuild("rls"); - pkgbuild("rust-analysis"); pkgbuild("rust-docs"); pkgbuild("rust-std"); @@ -782,8 +773,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&exe); t!(fs::create_dir_all(exe.join("rustc"))); t!(fs::create_dir_all(exe.join("cargo"))); - t!(fs::create_dir_all(exe.join("rls"))); - t!(fs::create_dir_all(exe.join("rust-analysis"))); t!(fs::create_dir_all(exe.join("rust-docs"))); t!(fs::create_dir_all(exe.join("rust-std"))); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)) @@ -792,12 +781,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)) .join("cargo"), &exe.join("cargo")); - cp_r(&work.join(pkgname(build, "rls")) - .join("rls"), - &exe.join("rls")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)) - .join("rust-analysis"), - &exe.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)) .join("rust-docs"), &exe.join("rust-docs")); @@ -807,8 +790,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { t!(fs::remove_file(exe.join("rustc/manifest.in"))); t!(fs::remove_file(exe.join("cargo/manifest.in"))); - t!(fs::remove_file(exe.join("rls/manifest.in"))); - t!(fs::remove_file(exe.join("rust-analysis/manifest.in"))); t!(fs::remove_file(exe.join("rust-docs/manifest.in"))); t!(fs::remove_file(exe.join("rust-std/manifest.in"))); @@ -865,26 +846,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-var").arg("var.DocsDir") .arg("-out").arg(exe.join("DocsGroup.wxs")) .arg("-t").arg(etc.join("msi/squash-components.xsl"))); - build.run(Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rls") - .args(&heat_flags) - .arg("-cg").arg("RlsGroup") - .arg("-dr").arg("Rls") - .arg("-var").arg("var.RlsDir") - .arg("-out").arg(exe.join("RlsGroup.wxs")) - .arg("-t").arg(etc.join("msi/squash-components.xsl"))); - build.run(Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-analysis") - .args(&heat_flags) - .arg("-cg").arg("AnalysisGroup") - .arg("-dr").arg("Analysis") - .arg("-var").arg("var.AnalysisDir") - .arg("-out").arg(exe.join("AnalysisGroup.wxs")) - .arg("-t").arg(etc.join("msi/squash-components.xsl"))); build.run(Command::new(&heat) .current_dir(&exe) .arg("dir") @@ -925,8 +886,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-nologo") .arg("-dRustcDir=rustc") .arg("-dDocsDir=rust-docs") - .arg("-dRlsDir=rls") - .arg("-dAnalysisDir=rust-analysis") .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") .arg("-arch").arg(&arch) @@ -944,8 +903,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { candle(&etc.join("msi/rustwelcomedlg.wxs")); candle("RustcGroup.wxs".as_ref()); candle("DocsGroup.wxs".as_ref()); - candle("RlsGroup.wxs".as_ref()); - candle("AnalysisGroup.wxs".as_ref()); candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); @@ -968,8 +925,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("rustwelcomedlg.wixobj") .arg("RustcGroup.wixobj") .arg("DocsGroup.wixobj") - .arg("RlsGroup.wixobj") - .arg("AnalysisGroup.wixobj") .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") .current_dir(&exe); @@ -1037,7 +992,7 @@ pub fn hash_and_sign(build: &Build) { cmd.arg(distdir(build)); cmd.arg(today.trim()); cmd.arg(build.rust_package_vers()); - cmd.arg(build.package_vers(&build.cargo_release_num())); + cmd.arg(build.package_vers(&build.release_num("cargo"))); cmd.arg(addr); t!(fs::create_dir_all(distdir(build))); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 81ab2b0d1cef2..f9981f76ad845 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1017,7 +1017,7 @@ impl Build { /// Returns the value of `package_vers` above for Cargo fn cargo_package_vers(&self) -> String { - self.package_vers(&self.cargo_release_num()) + self.package_vers(&self.release_num("cargo")) } /// Returns the `version` string associated with this compiler for Rust @@ -1029,10 +1029,11 @@ impl Build { self.rust_info.version(self, channel::CFG_RELEASE_NUM) } - /// Returns the `a.b.c` version that Cargo is at. - fn cargo_release_num(&self) -> String { + /// Returns the `a.b.c` version that the given package is at. + fn release_num(&self, package: &str) -> String { let mut toml = String::new(); - t!(t!(File::open(self.src.join("cargo/Cargo.toml"))).read_to_string(&mut toml)); + let toml_file_name = self.src.join(&format!("{}/Cargo.toml", package)); + t!(t!(File::open(toml_file_name)).read_to_string(&mut toml)); for line in toml.lines() { let prefix = "version = \""; let suffix = "\""; @@ -1041,22 +1042,7 @@ impl Build { } } - panic!("failed to find version in cargo's Cargo.toml") - } - - /// Returns the `a.b.c` version that the RLS is at. - fn rls_release_num(&self) -> String { - let mut toml = String::new(); - t!(t!(File::open(self.src.join("rls/Cargo.toml"))).read_to_string(&mut toml)); - for line in toml.lines() { - let prefix = "version = \""; - let suffix = "\""; - if line.starts_with(prefix) && line.ends_with(suffix) { - return line[prefix.len()..line.len() - suffix.len()].to_string() - } - } - - panic!("failed to find version in the RLS's Cargo.toml") + panic!("failed to find version in {}'s Cargo.toml", package) } /// Returns whether unstable features should be enabled for the compiler diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index adddd7b7e89b0..eab2dc75af8d0 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -225,6 +225,7 @@ impl Builder { self.package("rust-src", &mut manifest.pkg, &["*"]); if self.rust_release == "nightly" { + self.package("rls", &mut manifest.pkg, HOSTS); self.package("rust-analysis", &mut manifest.pkg, TARGETS); } @@ -277,6 +278,10 @@ impl Builder { pkg: "rust-analysis".to_string(), target: target.to_string(), }); + extensions.push(Component { + pkg: "rls".to_string(), + target: host.to_string(), + }); } } extensions.push(Component { From 5766d526a250c92792ec877a65003d43683c94e5 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 5 Apr 2017 11:34:14 +1200 Subject: [PATCH 600/662] Remove --enable-save-analysis configure flag --- cargo | 2 +- configure | 1 - rls | 2 +- src/bootstrap/config.rs | 4 ---- src/bootstrap/config.toml.example | 3 --- src/bootstrap/dist.rs | 8 +++----- src/bootstrap/install.rs | 5 ----- src/bootstrap/lib.rs | 2 +- src/ci/run.sh | 1 - 9 files changed, 6 insertions(+), 22 deletions(-) diff --git a/cargo b/cargo index 4729175045b41..4e95c6b41eca3 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 +Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 diff --git a/configure b/configure index d6dded6dc5f7b..35b376d5f27b8 100755 --- a/configure +++ b/configure @@ -445,7 +445,6 @@ 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 "check if the LLVM version is supported, build anyway" opt codegen-tests 1 "run the src/test/codegen tests" -opt save-analysis 0 "save API analysis data" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" opt locked-deps 0 "force Cargo.lock to be up to date" diff --git a/rls b/rls index 88fc39bd654c5..016cbc514cf44 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 88fc39bd654c536b4f8f1cd1fc8245706f0284ec +Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 52ebf401aefd6..693114d01ad9c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -74,7 +74,6 @@ pub struct Config { pub rustc_default_ar: Option, pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, - pub rust_save_analysis: bool, pub rust_dist_src: bool, pub build: String, @@ -226,7 +225,6 @@ struct Rust { optimize_tests: Option, debuginfo_tests: Option, codegen_tests: Option, - save_analysis: Option, } /// TOML representation of how each build target is configured. @@ -352,7 +350,6 @@ impl Config { set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); - set(&mut config.rust_save_analysis, rust.save_analysis); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); @@ -460,7 +457,6 @@ impl Config { ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), ("CODEGEN_TESTS", self.codegen_tests), - ("SAVE_ANALYSIS", self.rust_save_analysis), ("LOCKED_DEPS", self.locked_deps), ("VENDOR", self.vendor), ("FULL_BOOTSTRAP", self.full_bootstrap), diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 6b2cc6eb6474c..fad79022043e3 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -234,9 +234,6 @@ # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true -# Flag indicating whether the API analysis data should be saved. -#save-analysis = false - # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 88a3441d42015..e786d69555a10 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -315,15 +315,12 @@ pub fn rust_src_location(build: &Build) -> PathBuf { /// Creates a tarball of save-analysis metadata, if available. pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { - if !build.config.rust_save_analysis { - return - } - + assert!(build.config.extended); println!("Dist analysis"); if compiler.host != build.config.build { println!("\tskipping, not a build host"); - return + return; } // Package save-analysis from stage1 if not doing a full bootstrap, as the @@ -595,6 +592,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { } pub fn rls(build: &Build, stage: u32, target: &str) { + assert!(build.config.extended); println!("Dist RLS stage{} ({})", stage, target); let compiler = Compiler::new(stage, &build.config.build); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 25082e3a9d095..d508616e4b1cc 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -55,11 +55,6 @@ pub fn install(build: &Build, stage: u32, host: &str) { &docdir, &libdir, &mandir, &empty_dir); } - if build.config.rust_save_analysis { - install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); - } - install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f9981f76ad845..e91664ac8aba7 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -545,7 +545,7 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } - if self.config.rust_save_analysis && compiler.is_final_stage(self) { + if self.config.extended && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } diff --git a/src/ci/run.sh b/src/ci/run.sh index 6c6a49ada15d9..c6510120b47ae 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -42,7 +42,6 @@ fi if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=nightly" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-save-analysis" if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" From 4bc7f5b52c41ffd45aaf8f27e7ec667f549011c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 6 Apr 2017 12:18:18 -0700 Subject: [PATCH 601/662] Always show end line of multiline annotations ```rust error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | 20 | impl Iterator for Recurrence { | _________^ starting here... 21 | | //~^ ERROR E0046 22 | | //~| NOTE missing `Item` in implementation 23 | | //~| NOTE `Item` from trait: `type Item;` ... | 36 | | } 37 | | } | |_________^ ...ending here: missing `Item` in implementation | = note: `Item` from trait: `type Item;` ``` instead of ```rust error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | 20 | impl Iterator for Recurrence { | ^ missing `Item` in implementation | = note: `Item` from trait: `type Item;` ``` --- src/librustc_errors/emitter.rs | 196 +++++++++++------- src/librustc_errors/snippet.rs | 13 +- src/libsyntax/test_snippet.rs | 134 ++++++++++++ .../ui/span/impl-wrong-item-for-trait.stderr | 9 +- src/test/ui/span/issue-23729.stderr | 11 +- src/test/ui/span/issue-23827.stderr | 3 +- 6 files changed, 269 insertions(+), 97 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 367b85ac726db..a52628ceb47ab 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -21,6 +21,8 @@ use std::io::prelude::*; use std::io; use std::rc::Rc; use term; +use std::collections::HashMap; +use std::cmp::min; /// Emitter trait for emitting errors. pub trait Emitter { @@ -156,15 +158,6 @@ impl EmitterWriter { } let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); - let mut is_minimized = false; - - // If the span is long multi-line, simplify down to the span of one character - let max_multiline_span_length = 8; - if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length { - hi.line = lo.line; - hi.col = CharPos(lo.col.0 + 1); - is_minimized = true; - } // Watch out for "empty spans". If we get a span like 6..6, we // want to just display a `^` at 6, so convert that to @@ -175,16 +168,7 @@ impl EmitterWriter { hi.col = CharPos(lo.col.0 + 1); } - let mut ann = Annotation { - start_col: lo.col.0, - end_col: hi.col.0, - is_primary: span_label.is_primary, - label: span_label.label.clone(), - annotation_type: AnnotationType::Singleline, - }; - if is_minimized { - ann.annotation_type = AnnotationType::Minimized; - } else if lo.line != hi.line { + let ann_type = if lo.line != hi.line { let ml = MultilineAnnotation { depth: 1, line_start: lo.line, @@ -194,8 +178,17 @@ impl EmitterWriter { is_primary: span_label.is_primary, label: span_label.label.clone(), }; - ann.annotation_type = AnnotationType::Multiline(ml.clone()); - multiline_annotations.push((lo.file.clone(), ml)); + multiline_annotations.push((lo.file.clone(), ml.clone())); + AnnotationType::Multiline(ml) + } else { + AnnotationType::Singleline + }; + let ann = Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + label: span_label.label.clone(), + annotation_type: ann_type, }; if !ann.is_multiline() { @@ -233,9 +226,15 @@ impl EmitterWriter { max_depth = ann.depth; } add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); - for line in ann.line_start + 1..ann.line_end { + let middle = min(ann.line_start + 4, ann.line_end); + for line in ann.line_start + 1..middle { add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); } + if middle < ann.line_end - 1 { + for line in ann.line_end - 1..ann.line_end { + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + } add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end()); } for file_vec in output.iter_mut() { @@ -249,16 +248,11 @@ impl EmitterWriter { file: Rc, line: &Line, width_offset: usize, - multiline_depth: usize) { + code_offset: usize) -> Vec<(usize, Style)> { let source_string = file.get_line(line.line_index - 1) .unwrap_or(""); let line_offset = buffer.num_lines(); - let code_offset = if multiline_depth == 0 { - width_offset - } else { - width_offset + multiline_depth + 1 - }; // First create the source line we will highlight. buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); @@ -286,7 +280,7 @@ impl EmitterWriter { // previous borrow of `vec` occurs here // // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `~`. + // and "annotations lines", where the highlight lines have the `^`. // Sort the annotations by (start, end col) let mut annotations = line.annotations.clone(); @@ -410,25 +404,9 @@ impl EmitterWriter { // If there are no annotations or the only annotations on this line are // MultilineLine, then there's only code being shown, stop processing. if line.annotations.is_empty() || line.annotations.iter() - .filter(|a| { - // Set the multiline annotation vertical lines to the left of - // the code in this line. - if let AnnotationType::MultilineLine(depth) = a.annotation_type { - buffer.putc(line_offset, - width_offset + depth - 1, - '|', - if a.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }); - false - } else { - true - } - }).collect::>().len() == 0 + .filter(|a| !a.is_line()).collect::>().len() == 0 { - return; + return vec![]; } // Write the colunmn separator. @@ -483,8 +461,7 @@ impl EmitterWriter { } } - // Write the vertical lines for multiline spans and for labels that are - // on a different line as the underline. + // Write the vertical lines for labels that are on a different line as the underline. // // After this we will have: // @@ -492,7 +469,7 @@ impl EmitterWriter { // | __________ // | | | // | | - // 3 | | + // 3 | // 4 | | } // | |_ for &(pos, annotation) in &annotations_position { @@ -528,16 +505,6 @@ impl EmitterWriter { style); } } - AnnotationType::MultilineLine(depth) => { - // the first line will have already be filled when we checked - // wether there were any annotations for this line. - for p in line_offset + 1..line_offset + line_len + 2 { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); - } - } _ => (), } } @@ -548,11 +515,11 @@ impl EmitterWriter { // // 2 | fn foo() { // | __________ starting here... - // | | | - // | | something about `foo` - // 3 | | - // 4 | | } - // | |_ ...ending here: test + // | | + // | something about `foo` + // 3 | + // 4 | } + // | _ ...ending here: test for &(pos, annotation) in &annotations_position { let style = if annotation.is_primary { Style::LabelPrimary @@ -591,11 +558,11 @@ impl EmitterWriter { // // 2 | fn foo() { // | ____-_____^ starting here... - // | | | - // | | something about `foo` - // 3 | | - // 4 | | } - // | |_^ ...ending here: test + // | | + // | something about `foo` + // 3 | + // 4 | } + // | _^ ...ending here: test for &(_, annotation) in &annotations_position { let (underline, style) = if annotation.is_primary { ('^', Style::UnderlinePrimary) @@ -609,6 +576,20 @@ impl EmitterWriter { style); } } + annotations_position.iter().filter_map(|&(_, annotation)| { + match annotation.annotation_type { + AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { + let style = if annotation.is_primary { + Style::LabelPrimary + } else { + Style::LabelSecondary + }; + Some((p, style)) + }, + _ => None + } + + }).collect::>() } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { @@ -902,22 +883,64 @@ impl EmitterWriter { let buffer_msg_line_offset = buffer.num_lines(); draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); + // Contains the vertical lines' positions for active multiline annotations + let mut multilines = HashMap::new(); + // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { - self.render_source_line(&mut buffer, - annotated_file.file.clone(), - &annotated_file.lines[line_idx], - 3 + max_line_num_len, - annotated_file.multiline_depth); + let previous_buffer_line = buffer.num_lines(); + + let width_offset = 3 + max_line_num_len; + let code_offset = if annotated_file.multiline_depth == 0 { + width_offset + } else { + width_offset + annotated_file.multiline_depth + 1 + }; + + let depths = self.render_source_line(&mut buffer, + annotated_file.file.clone(), + &annotated_file.lines[line_idx], + width_offset, + code_offset); + let mut to_add = HashMap::new(); + + for (depth, style) in depths { + if multilines.get(&depth).is_some() { + multilines.remove(&depth); + } else { + to_add.insert(depth, style); + } + } + + // Set the multiline annotation vertical lines to the left of + // the code in this line. + for (depth, style) in &multilines { + for line in previous_buffer_line..buffer.num_lines() { + draw_multiline_line(&mut buffer, + line, + width_offset, + *depth, + *style); + } + } // check to see if we need to print out or elide lines that come between - // this annotated line and the next one + // this annotated line and the next one. if line_idx < (annotated_file.lines.len() - 1) { let line_idx_delta = annotated_file.lines[line_idx + 1].line_index - annotated_file.lines[line_idx].line_index; if line_idx_delta > 2 { let last_buffer_line_num = buffer.num_lines(); buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber); + + // Set the multiline annotation vertical lines on `...` bridging line. + for (depth, style) in &multilines { + draw_multiline_line(&mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style); + } } else if line_idx_delta == 2 { let unannotated_line = annotated_file.file .get_line(annotated_file.lines[line_idx].line_index) @@ -932,11 +955,21 @@ impl EmitterWriter { Style::LineNumber); draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len); buffer.puts(last_buffer_line_num, - 3 + max_line_num_len, + code_offset, &unannotated_line, Style::Quotation); + + for (depth, style) in &multilines { + draw_multiline_line(&mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style); + } } } + + multilines.extend(&to_add); } } @@ -1085,6 +1118,15 @@ fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { buffer.puts(line, col, "= ", Style::LineNumber); } +fn draw_multiline_line(buffer: &mut StyledBuffer, + line: usize, + offset: usize, + depth: usize, + style: Style) +{ + buffer.putc(line, offset + depth - 1, '|', style); +} + fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool { let extra = if inclusive { 1 diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 5debbf4d37c20..9aa4682e1afcb 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -97,9 +97,6 @@ pub enum AnnotationType { /// Annotation under a single line of code Singleline, - /// Annotation under the first character of a multiline span - Minimized, - /// Annotation enclosing the first and last character of a multiline span Multiline(MultilineAnnotation), @@ -118,6 +115,9 @@ pub enum AnnotationType { /// Annotation marking the last character of a fully shown multiline span MultilineEnd(usize), /// Line at the left enclosing the lines of a fully shown multiline span + // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4 + // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in + // `draw_multiline_line`. MultilineLine(usize), } @@ -144,13 +144,6 @@ pub struct Annotation { } impl Annotation { - pub fn is_minimized(&self) -> bool { - match self.annotation_type { - AnnotationType::Minimized => true, - _ => false, - } - } - /// Wether this annotation is a vertical line placeholder. pub fn is_line(&self) -> bool { if let AnnotationType::MultilineLine(_) = self.annotation_type { diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c537a0ee16644..a74f59b004bb7 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -932,3 +932,137 @@ error: foo "#); } + +#[test] +fn long_snippet() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | X1 Y1 Z1 + | |____^____- starting here... + | ||____| + | | ...ending here: `X` is a good letter +5 | | 1 +6 | | 2 +7 | | 3 +... | +15 | | X2 Y2 Z2 +16 | | X3 Y3 Z3 + | |___________- ...ending here: `Y` is a good letter too + +"#); +} + +#[test] +fn long_snippet_multiple_spans() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 +1 +2 +3 + X1 Y1 Z1 +4 +5 +6 + X2 Y2 Z2 +7 +8 +9 +10 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y3", + count: 1, + }, + label: "`Y` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Z` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | 1 +5 | | 2 +6 | | 3 +7 | | X1 Y1 Z1 + | |_________- starting here... +8 | || 4 +9 | || 5 +10 | || 6 +11 | || X2 Y2 Z2 + | ||__________- ...ending here: `Z` is a good letter too +... | +15 | | 10 +16 | | X3 Y3 Z3 + | |_______^ ...ending here: `Y` is a good letter + +"#); +} + diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 717f5ee200c74..367af12bb6b1c 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -24,8 +24,7 @@ error[E0046]: not all trait items implemented, missing: `bar` 23 | | //~^ ERROR E0046 24 | | //~| NOTE missing `bar` in implementation 25 | | const bar: u64 = 1; -26 | | //~^ ERROR E0323 -27 | | //~| NOTE does not match trait +... | 28 | | const MY_CONST: u32 = 1; 29 | | } | |_^ ...ending here: missing `bar` in implementation @@ -50,8 +49,7 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST` 34 | | //~^ ERROR E0046 35 | | //~| NOTE missing `MY_CONST` in implementation 36 | | fn bar(&self) {} -37 | | fn MY_CONST() {} -38 | | //~^ ERROR E0324 +... | 39 | | //~| NOTE does not match trait 40 | | } | |_^ ...ending here: missing `MY_CONST` in implementation @@ -76,8 +74,7 @@ error[E0046]: not all trait items implemented, missing: `bar` 45 | | //~^ ERROR E0046 46 | | //~| NOTE missing `bar` in implementation 47 | | type bar = u64; -48 | | //~^ ERROR E0325 -49 | | //~| NOTE does not match trait +... | 50 | | const MY_CONST: u32 = 1; 51 | | } | |_^ ...ending here: missing `bar` in implementation diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr index 493ca01778bc1..701576ff6f475 100644 --- a/src/test/ui/span/issue-23729.stderr +++ b/src/test/ui/span/issue-23729.stderr @@ -1,8 +1,15 @@ error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | -20 | impl Iterator for Recurrence { - | ^ missing `Item` in implementation +20 | impl Iterator for Recurrence { + | _________^ starting here... +21 | | //~^ ERROR E0046 +22 | | //~| NOTE missing `Item` in implementation +23 | | //~| NOTE `Item` from trait: `type Item;` +... | +36 | | } +37 | | } + | |_________^ ...ending here: missing `Item` in implementation | = note: `Item` from trait: `type Item;` diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr index 6c1c246753011..457fed34ff1ad 100644 --- a/src/test/ui/span/issue-23827.stderr +++ b/src/test/ui/span/issue-23827.stderr @@ -6,8 +6,7 @@ error[E0046]: not all trait items implemented, missing: `Output` 37 | | //~^ ERROR E0046 38 | | //~| NOTE missing `Output` in implementation 39 | | //~| NOTE `Output` from trait: `type Output;` -40 | | extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype { -41 | | Fn::call(&self, (comp,)) +... | 42 | | } 43 | | } | |_^ ...ending here: missing `Output` in implementation From a2b28be3f8f2920d39c9c87fef968d3885753ba4 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Fri, 10 Mar 2017 12:10:26 -0500 Subject: [PATCH 602/662] Reduce str transmutes, add mut versions of methods. --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/str-mut-extras.md | 8 +++++ src/libcollections/lib.rs | 1 + src/libcollections/str.rs | 9 ++++- src/libcollections/string.rs | 4 +-- src/libcore/char.rs | 3 +- src/libcore/str/mod.rs | 39 +++++++++++++++++---- src/libstd/ascii.rs | 5 ++- src/libstd/lib.rs | 1 + 9 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/doc/unstable-book/src/str-mut-extras.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index d86766bac02a2..c077568d96e1b 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -187,6 +187,7 @@ - [str_checked_slicing](str-checked-slicing.md) - [str_escape](str-escape.md) - [str_internals](str-internals.md) +- [str_mut_extras](str-mut-extras.md) - [struct_field_attributes](struct-field-attributes.md) - [structural_match](structural-match.md) - [target_feature](target-feature.md) diff --git a/src/doc/unstable-book/src/str-mut-extras.md b/src/doc/unstable-book/src/str-mut-extras.md new file mode 100644 index 0000000000000..df4f35832cdc1 --- /dev/null +++ b/src/doc/unstable-book/src/str-mut-extras.md @@ -0,0 +1,8 @@ +# `str_mut_extras` + +The tracking issue for this feature is: [#str_mut_extras] + +[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119 + +------------------------ + diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f6..b485f900094f0 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -57,6 +57,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] +#![feature(str_mut_extras)] #![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b5572..d04f414250ade 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -72,7 +72,7 @@ pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8_unchecked, ParseBoolError}; +pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] @@ -294,6 +294,13 @@ impl str { core_str::StrExt::as_bytes(self) } + /// Converts a mutable string slice to a mutable byte slice. + #[unstable(feature = "str_mut_extras", issue = "41119")] + #[inline(always)] + pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + core_str::StrExt::as_bytes_mut(self) + } + /// Converts a string slice to a raw pointer. /// /// As string slices are a slice of bytes, the raw pointer points to a diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 0ee4c8b8e95a6..7d9d7276201bd 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1790,7 +1790,7 @@ impl ops::IndexMut> for String { impl ops::IndexMut for String { #[inline] fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { - unsafe { mem::transmute(&mut *self.vec) } + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -1822,7 +1822,7 @@ impl ops::Deref for String { impl ops::DerefMut for String { #[inline] fn deref_mut(&mut self) -> &mut str { - unsafe { mem::transmute(&mut *self.vec) } + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index b27c801cf89d5..98268e3813fac 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -19,6 +19,7 @@ use char_private::is_printable; use convert::TryFrom; use fmt::{self, Write}; use slice; +use str::from_utf8_unchecked_mut; use iter::FusedIterator; use mem::transmute; @@ -448,7 +449,7 @@ impl CharExt for char { code, dst.len()) }; - transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len)) + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 352cc926994e3..2ceef54ffed6a 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -21,8 +21,8 @@ use char; use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; -use mem; use slice::{self, SliceIndex}; +use mem; pub mod pattern; @@ -300,6 +300,13 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { Ok(unsafe { from_utf8_unchecked(v) }) } +/// Converts a mutable slice of bytes to a mutable string slice. +#[unstable(feature = "str_mut_extras", issue = "41119")] +pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + run_utf8_validation(v)?; + Ok(unsafe { from_utf8_unchecked_mut(v) }) +} + /// Forms a str from a pointer and a length. /// /// The `len` argument is the number of bytes in the string. @@ -325,7 +332,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// str is returned. /// unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { - mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len)) + from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len)) } /// Converts a slice of bytes to a string slice without checking @@ -365,6 +372,18 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { mem::transmute(v) } +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8; mutable version. +/// +/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information. +/// +/// [fromutf8]: fn.from_utf8_unchecked.html +#[inline(always)] +#[unstable(feature = "str_mut_extras", issue = "41119")] +pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + mem::transmute(v) +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1474,7 +1493,6 @@ Section: Trait implementations mod traits { use cmp::Ordering; use ops; - use mem; use slice::{self, SliceIndex}; use str::eq_slice; @@ -1811,7 +1829,7 @@ mod traits { unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr().offset(self.start as isize); let len = self.end - self.start; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1859,7 +1877,7 @@ mod traits { #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr(); - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1905,7 +1923,7 @@ mod traits { unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr().offset(self.start as isize); let len = slice.len() - self.start; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1998,7 +2016,7 @@ mod traits { #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr(); - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2096,6 +2114,8 @@ pub trait StrExt { fn is_char_boundary(&self, index: usize) -> bool; #[stable(feature = "core", since = "1.6.0")] fn as_bytes(&self) -> &[u8]; + #[unstable(feature = "str_mut_extras", issue = "0")] + unsafe fn as_bytes_mut(&mut self) -> &mut [u8]; #[stable(feature = "core", since = "1.6.0")] fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; #[stable(feature = "core", since = "1.6.0")] @@ -2373,6 +2393,11 @@ impl StrExt for str { unsafe { mem::transmute(self) } } + #[inline] + unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + mem::transmute(self) + } + fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { pat.into_searcher(self).next_match().map(|(i, _)| i) } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index b36253862094f..4e3781ecafab5 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -27,7 +27,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use mem; use ops::Range; use iter::FusedIterator; @@ -599,12 +598,12 @@ impl AsciiExt for str { } fn make_ascii_uppercase(&mut self) { - let me: &mut [u8] = unsafe { mem::transmute(self) }; + let me = unsafe { self.as_bytes_mut() }; me.make_ascii_uppercase() } fn make_ascii_lowercase(&mut self) { - let me: &mut [u8] = unsafe { mem::transmute(self) }; + let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 064144dcd6818..6299a9070ae03 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -296,6 +296,7 @@ #![feature(stmt_expr_attributes)] #![feature(str_char)] #![feature(str_internals)] +#![feature(str_mut_extras)] #![feature(str_utf16)] #![feature(test, rustc_private)] #![feature(thread_local)] From 3d60bf45f42fe3ab6f6a64a983ed256d86ffdbbe Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Sun, 9 Apr 2017 19:42:01 -0400 Subject: [PATCH 603/662] Minor fix to mutex example Presumably `N` was supposed to be used in both places. --- src/libstd/sync/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index f2c178a1ad503..a27f621e6b2ae 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -61,7 +61,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// let data = Arc::new(Mutex::new(0)); /// /// let (tx, rx) = channel(); -/// for _ in 0..10 { +/// for _ in 0..N { /// let (data, tx) = (data.clone(), tx.clone()); /// thread::spawn(move || { /// // The shared state can only be accessed once the lock is held. From 0867981f5e5dafa80135314fba3e989dc1bd6209 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 10 Apr 2017 05:53:10 +0200 Subject: [PATCH 604/662] Apply clippy's doc_markdown improvements to libcollections Since my last PR led to linker failure, I'm now taking much smaller steps. This only fixes some doc_markdown warnings; as they are in comments only, we shouldn't get any problems building. --- src/libcollections/btree/map.rs | 24 ++++++++++++------------ src/libcollections/enum_set.rs | 2 +- src/libcollections/lib.rs | 4 ++-- src/libcollections/range.rs | 2 +- src/libcollections/vec_deque.rs | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index dcacef4f0f0d5..b30700c3f694e 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -262,7 +262,7 @@ impl super::Recover for BTreeMap } } -/// An iterator over a BTreeMap's entries. +/// An iterator over a `BTreeMap`'s entries. #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { range: Range<'a, K, V>, @@ -276,7 +276,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { } } -/// A mutable iterator over a BTreeMap's entries. +/// A mutable iterator over a `BTreeMap`'s entries. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, K: 'a, V: 'a> { @@ -284,7 +284,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { length: usize, } -/// An owning iterator over a BTreeMap's entries. +/// An owning iterator over a `BTreeMap`'s entries. #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { front: Handle, marker::Edge>, @@ -303,7 +303,7 @@ impl fmt::Debug for IntoIter { } } -/// An iterator over a BTreeMap's keys. +/// An iterator over a `BTreeMap`'s keys. #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -316,7 +316,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Keys<'a, K, V> { } } -/// An iterator over a BTreeMap's values. +/// An iterator over a `BTreeMap`'s values. #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -329,14 +329,14 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> } } -/// A mutable iterator over a BTreeMap's values. +/// A mutable iterator over a `BTreeMap`'s values. #[stable(feature = "map_values_mut", since = "1.10.0")] #[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } -/// An iterator over a sub-range of BTreeMap's entries. +/// An iterator over a sub-range of `BTreeMap`'s entries. #[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -350,7 +350,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> } } -/// A mutable iterator over a sub-range of BTreeMap's entries. +/// A mutable iterator over a sub-range of `BTreeMap`'s entries. #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -378,12 +378,12 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, /// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant Entry + /// A vacant `Entry` #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), - /// An occupied Entry + /// An occupied `Entry` #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), @@ -403,7 +403,7 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A vacant Entry. It is part of the [`Entry`] enum. +/// A vacant `Entry`. It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] @@ -425,7 +425,7 @@ impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { } } -/// An occupied Entry. It is part of the [`Entry`] enum. +/// An occupied `Entry`. It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index e56b94b2e1ea2..ebee75d1a1a64 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -215,7 +215,7 @@ impl BitXor for EnumSet { } } -/// An iterator over an EnumSet +/// An iterator over an `EnumSet` pub struct Iter { index: usize, bits: usize, diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f6..79ae2d411b6fd 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -10,8 +10,8 @@ //! Collection types. //! -//! See [std::collections](../std/collections/index.html) for a detailed discussion of -//! collections in Rust. +//! See [`std::collections`](../std/collections/index.html) for a detailed +//! discussion of collections in Rust. #![crate_name = "collections"] #![crate_type = "rlib"] diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 06d89a6a70b4a..8f3209d015b15 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -17,7 +17,7 @@ use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; use Bound::{self, Excluded, Included, Unbounded}; -/// **RangeArgument** is implemented by Rust's built-in range types, produced +/// `RangeArgument` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. pub trait RangeArgument { /// Start index bound. diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 22f2ff1a34618..f1ea0010e98c2 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! VecDeque is a double-ended queue, which is implemented with the help of a +//! `VecDeque` is a double-ended queue, which is implemented with the help of a //! growing ring buffer. //! //! This queue has `O(1)` amortized inserts and removals from both ends of the @@ -1847,7 +1847,7 @@ fn wrap_index(index: usize, size: usize) -> usize { index & (size - 1) } -/// Returns the two slices that cover the VecDeque's valid range +/// Returns the two slices that cover the `VecDeque`'s valid range trait RingSlices: Sized { fn slice(self, from: usize, to: usize) -> Self; fn split_at(self, i: usize) -> (Self, Self); @@ -2047,7 +2047,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} -/// A by-value VecDeque iterator +/// A by-value `VecDeque` iterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -2097,7 +2097,7 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -/// A draining VecDeque iterator +/// A draining `VecDeque` iterator #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { after_tail: usize, From 1e7f3551d161ace63264b466707c0a1c5c589fb9 Mon Sep 17 00:00:00 2001 From: mandeep Date: Sun, 9 Apr 2017 23:07:18 -0500 Subject: [PATCH 605/662] Added doc comments for fmt::Result --- src/libcore/fmt/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0bfab92fa5d51..8c3d3ce7d886b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -49,8 +49,31 @@ pub mod rt { pub mod v1; } -#[stable(feature = "rust1", since = "1.0.0")] /// The type returned by formatter methods. +/// +/// # Examples +/// +/// ``` +/// use std::fmt; +/// +/// #[derive(Debug)] +/// struct Triangle { +/// a: f32, +/// b: f32, +/// c: f32 +/// } +/// +/// impl fmt::Display for Triangle { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "({}, {}, {})", self.a, self.b, self.c) +/// } +/// } +/// +/// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 }; +/// +/// println!("{}", pythagorean_triple); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. From 251d9be42933e4cc4660802dc449d9466f54209b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 09:53:24 -0500 Subject: [PATCH 606/662] --subsystem needs -Wl when using non-ld linkers --- src/librustc_trans/back/linker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 48e469e28ee31..61c57f00de70d 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -363,7 +363,7 @@ impl<'a> Linker for GccLinker<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("--subsystem,{}", subsystem)); + self.linker_arg(&format!("--subsystem,{}", subsystem)); } fn finalize(&mut self) -> Command { From e192fb3d892f04e90a78378bd772cc003304a887 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 09:55:52 -0500 Subject: [PATCH 607/662] explain why we have a fake cfail test --- src/test/compile-fail/feature-gate-linker-flavor.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs index 68679d7dac896..955ec39cda1e5 100644 --- a/src/test/compile-fail/feature-gate-linker-flavor.rs +++ b/src/test/compile-fail/feature-gate-linker-flavor.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// This is a fake compile fail test as there's no way to generate a +// `#![feature(linker_flavor)]` error. The only reason we have a `linker_flavor` +// feature gate is to be able to document `-Z linker-flavor` in the unstable +// book + #[used] fn foo() {} //~^^ ERROR the `#[used]` attribute is an experimental feature From 1c3f34dba6a8219822a48f3db7e6f50ff04e0f78 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 10 Apr 2017 20:50:42 +0000 Subject: [PATCH 608/662] Convert HashMap to BTree in build-manifest --- src/tools/build-manifest/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index adddd7b7e89b0..a7a43e6858ef9 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -11,7 +11,7 @@ extern crate toml; extern crate rustc_serialize; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::env; use std::fs::File; use std::io::{self, Read, Write}; @@ -101,13 +101,13 @@ static MINGW: &'static [&'static str] = &[ struct Manifest { manifest_version: String, date: String, - pkg: HashMap, + pkg: BTreeMap, } #[derive(RustcEncodable)] struct Package { version: String, - target: HashMap, + target: BTreeMap, } #[derive(RustcEncodable)] @@ -138,7 +138,7 @@ struct Builder { input: PathBuf, output: PathBuf, gpg_passphrase: String, - digests: HashMap, + digests: BTreeMap, s3_address: String, date: String, rust_version: String, @@ -162,7 +162,7 @@ fn main() { input: input, output: output, gpg_passphrase: passphrase, - digests: HashMap::new(), + digests: BTreeMap::new(), s3_address: s3_address, date: date, rust_version: String::new(), @@ -214,7 +214,7 @@ impl Builder { let mut manifest = Manifest { manifest_version: "2".to_string(), date: self.date.to_string(), - pkg: HashMap::new(), + pkg: BTreeMap::new(), }; self.package("rustc", &mut manifest.pkg, HOSTS); @@ -230,7 +230,7 @@ impl Builder { let mut pkg = Package { version: self.cached_version("rust").to_string(), - target: HashMap::new(), + target: BTreeMap::new(), }; for host in HOSTS { let filename = self.filename("rust", host); @@ -299,7 +299,7 @@ impl Builder { fn package(&mut self, pkgname: &str, - dst: &mut HashMap, + dst: &mut BTreeMap, targets: &[&str]) { let targets = targets.iter().map(|name| { let filename = self.filename(pkgname, name); From 4c80170782c168e5aae848b2911c16921e5a2f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 9 Apr 2017 16:28:31 -0700 Subject: [PATCH 609/662] Point at only one char on `Span::next_point` Avoid pointing at two chars so the diagnostic output doesn't display a multiline span when starting beyond a line end. --- src/libsyntax/parse/parser.rs | 6 ++++-- src/libsyntax_pos/lib.rs | 2 +- src/test/ui/token/issue-41155.rs | 13 +++++++++++++ src/test/ui/token/issue-41155.stderr | 10 ++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/token/issue-41155.rs create mode 100644 src/test/ui/token/issue-41155.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43d21015a4fb1..58be43526fd9d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -592,8 +592,10 @@ impl<'a> Parser<'a> { } else { label_sp }; - err.span_label(sp, &label_exp); - if !sp.source_equal(&self.span) { + if self.span.contains(sp) { + err.span_label(self.span, &label_exp); + } else { + err.span_label(sp, &label_exp); err.span_label(self.span, &"unexpected token"); } Err(err) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9b88b9f7696fb..aaafcadc38a14 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -89,7 +89,7 @@ impl Span { /// Returns a new span representing the next character after the end-point of this span pub fn next_point(self) -> Span { let lo = cmp::max(self.hi.0, self.lo.0 + 1); - Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self } + Span { lo: BytePos(lo), hi: BytePos(lo), ..self } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/token/issue-41155.rs b/src/test/ui/token/issue-41155.rs new file mode 100644 index 0000000000000..0f473c9e07388 --- /dev/null +++ b/src/test/ui/token/issue-41155.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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. + +impl S { + pub +} diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr new file mode 100644 index 0000000000000..0da3abd4eaf9c --- /dev/null +++ b/src/test/ui/token/issue-41155.stderr @@ -0,0 +1,10 @@ +error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}` + --> $DIR/issue-41155.rs:13:1 + | +12 | pub + | - expected one of 7 possible tokens here +13 | } + | ^ unexpected token + +error: aborting due to previous error + From b9d662a00026390aa7b7b5706d3c800e4d6e6fdb Mon Sep 17 00:00:00 2001 From: Nathaniel Ringo Date: Mon, 10 Apr 2017 16:12:39 -0500 Subject: [PATCH 610/662] Fixes incorrect formatting in array's documentation. --- src/libstd/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5b2053e929a10..052340a0f253a 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -277,7 +277,7 @@ mod prim_pointer { } /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if /// the element type allows it: /// -/// - [`Clone`][clone] (only if `T: [Copy][copy]`) +/// - [`Clone`][clone] (only if `T: `[`Copy`][copy]) /// - [`Debug`][debug] /// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] From be8787dfe564cf315a9343a84724130da322e805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 10 Apr 2017 14:17:49 -0700 Subject: [PATCH 611/662] Explicit help message for binop type missmatch When trying to do a binary operation with missing implementation, for example `1 + Some(2)`, provide an explicit help message: ``` note: no implementation for `{integer} + std::option::Option<{integer}>` ``` Use `rustc_on_unimplemented` for the suggestions. Move cfail test to ui. --- src/libcore/cmp.rs | 2 + src/libcore/ops.rs | 20 +++++++ src/librustc/traits/error_reporting.rs | 20 +++---- .../impl-trait/equality.rs | 2 +- src/test/ui/impl-trait/equality.stderr | 55 ++++++++++++++++++ src/test/ui/mismatched_types/binops.rs | 18 ++++++ src/test/ui/mismatched_types/binops.stderr | 58 +++++++++++++++++++ src/test/ui/span/multiline-span-simple.stderr | 6 +- 8 files changed, 164 insertions(+), 17 deletions(-) rename src/test/{compile-fail => ui}/impl-trait/equality.rs (95%) create mode 100644 src/test/ui/impl-trait/equality.stderr create mode 100644 src/test/ui/mismatched_types/binops.rs create mode 100644 src/test/ui/mismatched_types/binops.stderr diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 74ded948b18e7..d4544dadaeb0c 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -102,6 +102,7 @@ use self::Ordering::*; /// ``` #[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -550,6 +551,7 @@ impl PartialOrd for Ordering { /// ``` #[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index d203b68c0dfd5..175b3a5a69ac1 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -242,6 +242,7 @@ pub trait Drop { /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"] pub trait Add { /// The resulting type after applying the `+` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -315,6 +316,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"] pub trait Sub { /// The resulting type after applying the `-` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -437,6 +439,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"] pub trait Mul { /// The resulting type after applying the `*` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -565,6 +568,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"] pub trait Div { /// The resulting type after applying the `/` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -644,6 +648,7 @@ div_impl_float! { f32 f64 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"] pub trait Rem { /// The resulting type after applying the `%` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -883,6 +888,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitand"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"] pub trait BitAnd { /// The resulting type after applying the `&` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -966,6 +972,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitor"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"] pub trait BitOr { /// The resulting type after applying the `|` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1052,6 +1059,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitxor"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"] pub trait BitXor { /// The resulting type after applying the `^` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1134,6 +1142,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "shl"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"] pub trait Shl { /// The resulting type after applying the `<<` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1237,6 +1246,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// ``` #[lang = "shr"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"] pub trait Shr { /// The resulting type after applying the `>>` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1321,6 +1331,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"] pub trait AddAssign { /// The method for the `+=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1377,6 +1388,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"] pub trait SubAssign { /// The method for the `-=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1422,6 +1434,7 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"] pub trait MulAssign { /// The method for the `*=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1467,6 +1480,7 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"] pub trait DivAssign { /// The method for the `/=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1511,6 +1525,7 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "rem_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"] pub trait RemAssign { /// The method for the `%=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1597,6 +1612,7 @@ rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "bitand_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"] pub trait BitAndAssign { /// The method for the `&=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1641,6 +1657,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitor_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"] pub trait BitOrAssign { /// The method for the `|=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1685,6 +1702,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitxor_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"] pub trait BitXorAssign { /// The method for the `^=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1729,6 +1747,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "shl_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"] pub trait ShlAssign { /// The method for the `<<=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1794,6 +1813,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "shr_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"] pub trait ShrAssign { /// The method for the `>>=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 152dd6ac3000f..931c77badad22 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -524,15 +524,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "the trait bound `{}` is not satisfied{}", trait_ref.to_predicate(), post_message); - err.span_label(span, - &format!("{}the trait `{}` is not \ - implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); // Try to report a help message - if !trait_ref.has_infer_types() && self.predicate_can_apply(trait_ref) { // If a where-clause may be useful, remind the @@ -544,17 +537,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - } else if let Some(s) = self.on_unimplemented_note(trait_ref, - obligation) { + } else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) { // If it has a custom "#[rustc_on_unimplemented]" // error message, let's display it! err.note(&s); } else { - // If we can't show anything useful, try to find - // similar impls. + // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_ref); self.report_similar_impl_candidates(impl_candidates, &mut err); } + + err.span_label(span, + &format!("{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty())); err } @@ -997,3 +994,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { suggested_limit)); } } + diff --git a/src/test/compile-fail/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs similarity index 95% rename from src/test/compile-fail/impl-trait/equality.rs rename to src/test/ui/impl-trait/equality.rs index 36df4f0eb4d46..96db53ad2e46e 100644 --- a/src/test/compile-fail/impl-trait/equality.rs +++ b/src/test/ui/impl-trait/equality.rs @@ -32,7 +32,7 @@ fn sum_to(n: u32) -> impl Foo { 0 } else { n + sum_to(n - 1) - //~^ ERROR the trait bound `u32: std::ops::Add` is not satisfied + //~^ ERROR no implementation for `u32 + impl Foo` } } diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr new file mode 100644 index 0000000000000..bd024d6766eda --- /dev/null +++ b/src/test/ui/impl-trait/equality.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/equality.rs:25:5 + | +25 | 0_u32 + | ^^^^^ expected i32, found u32 + | + = note: expected type `i32` + found type `u32` + +error[E0277]: the trait bound `u32: std::ops::Add` is not satisfied + --> $DIR/equality.rs:34:9 + | +34 | n + sum_to(n - 1) + | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add` is not implemented for `u32` + | + = note: no implementation for `u32 + impl Foo` + +error[E0308]: mismatched types + --> $DIR/equality.rs:53:18 + | +53 | let _: u32 = hide(0_u32); + | ^^^^^^^^^^^ expected u32, found anonymized type + | + = note: expected type `u32` + found type `impl Foo` + +error[E0308]: mismatched types + --> $DIR/equality.rs:59:18 + | +59 | let _: i32 = Leak::leak(hide(0_i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type + | + = note: expected type `i32` + found type `::T` + +error[E0308]: mismatched types + --> $DIR/equality.rs:66:10 + | +66 | x = (x.1, + | ^^^ expected u32, found i32 + | + = note: expected type `impl Foo` (u32) + found type `impl Foo` (i32) + +error[E0308]: mismatched types + --> $DIR/equality.rs:69:10 + | +69 | x.0); + | ^^^ expected i32, found u32 + | + = note: expected type `impl Foo` (i32) + found type `impl Foo` (u32) + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs new file mode 100644 index 0000000000000..98449e596641e --- /dev/null +++ b/src/test/ui/mismatched_types/binops.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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() { + 1 + Some(1); + 2 as usize - Some(1); + 3 * (); + 4 / ""; + 5 < String::new(); + 6 == Ok(1); +} diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr new file mode 100644 index 0000000000000..a0f7ff6587097 --- /dev/null +++ b/src/test/ui/mismatched_types/binops.stderr @@ -0,0 +1,58 @@ +error[E0277]: the trait bound `{integer}: std::ops::Add>` is not satisfied + --> $DIR/binops.rs:12:5 + | +12 | 1 + Some(1); + | ^^^^^^^^^^^ the trait `std::ops::Add>` is not implemented for `{integer}` + | + = note: no implementation for `{integer} + std::option::Option<{integer}>` + +error[E0277]: the trait bound `usize: std::ops::Sub>` is not satisfied + --> $DIR/binops.rs:13:5 + | +13 | 2 as usize - Some(1); + | ^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Sub>` is not implemented for `usize` + | + = note: no implementation for `usize - std::option::Option<{integer}>` + +error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied + --> $DIR/binops.rs:14:5 + | +14 | 3 * (); + | ^^^^^^ the trait `std::ops::Mul<()>` is not implemented for `{integer}` + | + = note: no implementation for `{integer} * ()` + +error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied + --> $DIR/binops.rs:15:5 + | +15 | 4 / ""; + | ^^^^^^ the trait `std::ops::Div<&str>` is not implemented for `{integer}` + | + = note: no implementation for `{integer} / &str` + +error[E0277]: the trait bound `{integer}: std::cmp::PartialEq` is not satisfied + --> $DIR/binops.rs:16:5 + | +16 | 5 < String::new(); + | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq` is not implemented for `{integer}` + | + = note: can't compare `{integer}` with `std::string::String` + +error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied + --> $DIR/binops.rs:16:5 + | +16 | 5 < String::new(); + | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialOrd` is not implemented for `{integer}` + | + = note: can't compare `{integer}` with `std::string::String` + +error[E0277]: the trait bound `{integer}: std::cmp::PartialEq>` is not satisfied + --> $DIR/binops.rs:17:5 + | +17 | 6 == Ok(1); + | ^^^^^^^^^^ the trait `std::cmp::PartialEq>` is not implemented for `{integer}` + | + = note: can't compare `{integer}` with `std::result::Result<{integer}, _>` + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 85c11c05b9f90..161b6ca48b282 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -9,11 +9,7 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied 27 | | y), | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32` | - = help: the following implementations were found: - - <&'a u32 as std::ops::Add> - > - <&'b u32 as std::ops::Add<&'a u32>> + = note: no implementation for `u32 + ()` error: aborting due to previous error From f297767b2c262e8542a4734a3f47b0a75502c9fd Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Tue, 11 Apr 2017 00:22:26 +0100 Subject: [PATCH 612/662] Make sccache a bit quieter --- src/bootstrap/native.rs | 2 +- src/ci/docker/run.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 62eed8be3ccb7..726e94e49a19e 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -147,7 +147,7 @@ pub fn llvm(build: &Build, target: &str) { } if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=debug"); + cfg.env("RUST_LOG", "sccache=info"); } // FIXME: we don't actually need to build all LLVM tools and all LLVM diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 71a4bfae3caf9..59b93b784b2f6 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -38,7 +38,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" - args="$args --env SCCACHE_LOG_LEVEL=debug" args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache From 0303a3364b68e412539634617c734192760a7df4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 11 Apr 2017 01:04:33 +0300 Subject: [PATCH 613/662] Fix pairs of doubles using an illegal <8 x i8> vector. --- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/cabi_x86_64.rs | 17 +++++++++-------- .../extern-fn-struct-passing-abi/test.c | 19 +++++++++++++++++++ .../extern-fn-struct-passing-abi/test.rs | 11 +++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 7be80a757ca01..c4fdc46d030c9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -283,7 +283,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { Layout::Vector { .. } => { Some(Reg { - kind: RegKind::Integer, + kind: RegKind::Vector, size: self.size(ccx) }) } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index cbe170d85834c..2daebf5cf3d6b 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -173,14 +173,15 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option { Class::Sse => { let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count(); *i += vec_len; - Some(match size { - 4 => Reg::f32(), - 8 => Reg::f64(), - _ => { - Reg { - kind: RegKind::Vector, - size: Size::from_bytes(vec_len as u64 * 8) - } + Some(if vec_len == 1 { + match size { + 4 => Reg::f32(), + _ => Reg::f64() + } + } else { + Reg { + kind: RegKind::Vector, + size: Size::from_bytes(vec_len as u64 * 8) } }) } diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c index 4253767ee76a9..4e09928edc6d1 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.c +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c @@ -38,6 +38,11 @@ struct Huge { int32_t e; }; +struct FloatPoint { + double x; + double y; +}; + // System V x86_64 ABI: // a, b, c, d, e should be in registers // s should be byval pointer @@ -258,3 +263,17 @@ struct Huge huge_struct(struct Huge s) { return s; } + +// System V x86_64 ABI: +// p should be in registers +// return should be in registers +// +// Win64 ABI: +// p should be a byval pointer +// return should be in a hidden sret pointer +struct FloatPoint float_point(struct FloatPoint p) { + assert(p.x == 5.); + assert(p.y == -3.); + + return p; +} diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs index b91362b8edccb..ff845a644b114 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs @@ -46,6 +46,13 @@ struct Huge { e: i32 } +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct FloatPoint { + x: f64, + y: f64 +} + #[link(name = "test", kind = "static")] extern { fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect); @@ -72,6 +79,8 @@ extern { fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect; fn huge_struct(s: Huge) -> Huge; + + fn float_point(p: FloatPoint) -> FloatPoint; } fn main() { @@ -79,6 +88,7 @@ fn main() { let t = BiggerRect { s: s, a: 27834, b: 7657 }; let u = FloatRect { a: 3489, b: 3490, c: 8. }; let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 }; + let p = FloatPoint { x: 5., y: -3. }; unsafe { byval_rect(1, 2, 3, 4, 5, s); @@ -94,5 +104,6 @@ fn main() { assert_eq!(split_ret_byval_struct(1, 2, s), s); assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t); assert_eq!(sret_split_struct(1, 2, s), t); + assert_eq!(float_point(p), p); } } From 63ebf08be50c2716b66f14f0ab6e9885542eb0a0 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 16:28:47 -0500 Subject: [PATCH 614/662] Initial attempt at implementing optimization fuel and re-enabling struct field reordering. --- src/librustc/session/config.rs | 24 +++++++++ src/librustc/session/mod.rs | 52 ++++++++++++++++++++ src/librustc/ty/context.rs | 5 ++ src/librustc/ty/layout.rs | 9 +--- src/librustc/ty/mod.rs | 5 ++ src/librustc_driver/lib.rs | 8 +++ src/test/run-pass/type-sizes.rs | 13 +++++ src/test/ui/print_type_sizes/nullable.stdout | 35 ++++++------- src/test/ui/print_type_sizes/packed.stdout | 10 ++-- src/test/ui/print_type_sizes/padding.stdout | 16 +++--- 10 files changed, 138 insertions(+), 39 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ef825a6854cec..b9a974045bced 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -643,6 +643,8 @@ macro_rules! options { Some("one of: `address`, `leak`, `memory` or `thread`"); pub const parse_linker_flavor: Option<&'static str> = Some(::rustc_back::LinkerFlavor::one_of()); + pub const parse_optimization_fuel: Option<&'static str> = + Some("crate=integer"); } #[allow(dead_code)] @@ -787,6 +789,21 @@ macro_rules! options { } true } + + fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) => { + let parts = s.split('=').collect::>(); + if parts.len() != 2 { return false; } + let crate_name = parts[0].to_string(); + let fuel = parts[1].parse::(); + if fuel.is_err() { return false; } + *slot = Some((crate_name, fuel.unwrap())); + true + } + } + } } ) } @@ -991,6 +1008,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Use a sanitizer"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], "Linker flavor"), + fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], + "Set the optimization fuel quota for a crate."), + print_fuel: Option = (None, parse_opt_string, [TRACKED], + "Make Rustc print the total optimization fuel used by a crate."), } pub fn default_lib_output() -> CrateType { @@ -1784,11 +1805,13 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(bool); impl_dep_tracking_hash_via_hash!(usize); + impl_dep_tracking_hash_via_hash!(u64); impl_dep_tracking_hash_via_hash!(String); impl_dep_tracking_hash_via_hash!(lint::Level); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); @@ -1810,6 +1833,7 @@ mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, Option)); + impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl DepTrackingHash for SearchPaths { fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) { let mut elems: Vec<_> = self diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 70b2809ccbed2..2d204908a521c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -123,6 +123,20 @@ pub struct Session { pub code_stats: RefCell, next_node_id: Cell, + + /// If -zfuel=crate=n is specified, Some(crate). + optimization_fuel_crate: Option, + /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0. + optimization_fuel_limit: Cell, + /// We're rejecting all further optimizations. + out_of_fuel: Cell, + + // The next two are public because the driver needs to read them. + + /// If -zprint-fuel=crate, Some(crate). + pub print_fuel_crate: Option, + /// Always set to zero and incremented so that we can print fuel expended by a crate. + pub print_fuel: Cell, } pub struct PerfStats { @@ -507,6 +521,33 @@ impl Session { println!("Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } + + /// We want to know if we're allowed to do an optimization for crate crate. + /// This expends fuel if applicable, and records fuel if applicable. + pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { + let mut ret = true; + match self.optimization_fuel_crate { + Some(ref c) if c == crate_name => { + let fuel = self.optimization_fuel_limit.get(); + ret = fuel != 0; + if fuel == 0 && !self.out_of_fuel.get(){ + println!("optimization-fuel-exhausted: {}", msg()); + self.out_of_fuel.set(true); + } + else { + self.optimization_fuel_limit.set(fuel-1); + } + } + _ => {} + } + match self.print_fuel_crate { + Some(ref c) if c == crate_name=> { + self.print_fuel.set(self.print_fuel.get()+1); + }, + _ => {} + } + ret + } } pub fn build_session(sopts: config::Options, @@ -602,6 +643,12 @@ pub fn build_session_(sopts: config::Options, } ); + let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); + let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref() + .map(|i| i.1).unwrap_or(0)); + let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); + let print_fuel = Cell::new(0); + let sess = Session { dep_graph: dep_graph.clone(), target: target_cfg, @@ -643,6 +690,11 @@ pub fn build_session_(sopts: config::Options, decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), }, code_stats: RefCell::new(CodeStats::new()), + optimization_fuel_crate: optimization_fuel_crate, + optimization_fuel_limit: optimization_fuel_limit, + print_fuel_crate: print_fuel_crate, + print_fuel: print_fuel, + out_of_fuel: Cell::new(false), }; init_llvm(&sess); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index da56514ea82fb..8b7438c0bfad2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -732,6 +732,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast_ty_to_ty_cache: RefCell::new(NodeMap()), }, f) } + + pub fn consider_optimizing String>(&self, msg: T) -> bool { + let cname = self.crate_name(LOCAL_CRATE).as_str(); + self.sess.consider_optimizing(&cname, msg) + } } impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 54e5de3909086..a344f89a66830 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -580,7 +580,6 @@ enum StructKind { } impl<'a, 'gcx, 'tcx> Struct { - // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type. fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { @@ -598,12 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct { // Neither do 1-member and 2-member structs. // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. - let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed); - - // Disable field reordering until we can decide what to do. - // The odd pattern here avoids a warning about the value never being read. - if can_optimize { can_optimize = false; } + let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) + && ! (repr.c || repr.packed || repr.linear || repr.simd); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f1..ba9c177f90483 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1411,6 +1411,8 @@ pub struct ReprOptions { pub packed: bool, pub simd: bool, pub int: Option, + // Internal only for now. If true, don't reorder fields. + pub linear: bool, } impl_stable_hash_for!(struct ReprOptions { @@ -1440,6 +1442,9 @@ impl ReprOptions { ret.simd = true; } + // This is here instead of layout because the choice must make it into metadata. + ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", + tcx.item_path_str(did))); ret } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c90dde3a5f6e0..1fef97d54a141 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -517,6 +517,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.make_glob_map = resolve::MakeGlobMap::Yes; } + if sess.print_fuel_crate.is_some() { + control.compilation_done.callback = box |state| { + let sess = state.session; + println!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.get()); + } + } control } } diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index bbb01eaaf46b9..9d1a3500a582a 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -31,6 +31,17 @@ enum e3 { a([u16; 0], u8), b } +struct ReorderedStruct { + a: u8, + b: u64, + c: u8 +} + +enum ReorderedEnum { + A(u8, u64, u8), + B(u8, u64, u8), +} + pub fn main() { assert_eq!(size_of::(), 1 as usize); assert_eq!(size_of::(), 4 as usize); @@ -54,4 +65,6 @@ pub fn main() { assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 4 as usize); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 16); } diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout index dd999c4a5e4c7..830678f174f88 100644 --- a/src/test/ui/print_type_sizes/nullable.stdout +++ b/src/test/ui/print_type_sizes/nullable.stdout @@ -1,25 +1,22 @@ -print-type-size type: `IndirectNonZero`: 20 bytes, alignment: 4 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.nested`: 12 bytes, alignment: 4 bytes +print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes +print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes -print-type-size type: `MyOption>`: 20 bytes, alignment: 4 bytes -print-type-size variant `Some`: 20 bytes -print-type-size field `.0`: 20 bytes -print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes -print-type-size variant `Record`: 10 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.val`: 4 bytes, alignment: 4 bytes -print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes -print-type-size type: `NestedNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.val`: 4 bytes, alignment: 4 bytes +print-type-size end padding: 1 bytes +print-type-size type: `MyOption>`: 12 bytes, alignment: 4 bytes +print-type-size variant `Some`: 12 bytes +print-type-size field `.0`: 12 bytes +print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes +print-type-size variant `Record`: 7 bytes +print-type-size field `.val`: 4 bytes +print-type-size field `.post`: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes +print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes +print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout index 1278a7d7c92c6..83fd333c9c7fc 100644 --- a/src/test/ui/print_type_sizes/packed.stdout +++ b/src/test/ui/print_type_sizes/packed.stdout @@ -1,13 +1,11 @@ -print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes +print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes -print-type-size padding: 2 bytes -print-type-size field `.g`: 4 bytes, alignment: 4 bytes print-type-size field `.c`: 1 bytes -print-type-size padding: 1 bytes -print-type-size field `.h`: 2 bytes, alignment: 2 bytes print-type-size field `.d`: 1 bytes -print-type-size end padding: 3 bytes +print-type-size end padding: 2 bytes print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout index bb95f790bd9e4..0eaff7118b35c 100644 --- a/src/test/ui/print_type_sizes/padding.stdout +++ b/src/test/ui/print_type_sizes/padding.stdout @@ -1,10 +1,12 @@ print-type-size type: `E1`: 12 bytes, alignment: 4 bytes -print-type-size discriminant: 4 bytes -print-type-size variant `A`: 5 bytes -print-type-size field `.0`: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 7 bytes print-type-size field `.1`: 1 bytes -print-type-size variant `B`: 8 bytes -print-type-size field `.0`: 8 bytes +print-type-size padding: 2 bytes +print-type-size field `.0`: 4 bytes, alignment: 4 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `E2`: 12 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `A`: 7 bytes @@ -15,7 +17,7 @@ print-type-size variant `B`: 11 bytes print-type-size padding: 3 bytes print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `S`: 8 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes -print-type-size padding: 2 bytes -print-type-size field `.g`: 4 bytes, alignment: 4 bytes +print-type-size end padding: 2 bytes From 4db9c7a2a2ba42fb15a58f5d770294b797bd57d4 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 22:20:07 -0500 Subject: [PATCH 615/662] Make a comment better. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2d204908a521c..4304248d158e1 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate crate. + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From 912599944effe3ad379622c173e8f9a85dd7eaac Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Fri, 10 Mar 2017 14:13:59 -0500 Subject: [PATCH 616/662] Tests for -Z fuel=foo=n --- src/librustc/session/mod.rs | 2 +- src/test/run-pass/optimization-fuel-0.rs | 24 ++++++++++++++++++++++ src/test/run-pass/optimization-fuel-1.rs | 26 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/optimization-fuel-0.rs create mode 100644 src/test/run-pass/optimization-fuel-1.rs diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 4304248d158e1..1be7d1afe45a8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -534,7 +534,7 @@ impl Session { println!("optimization-fuel-exhausted: {}", msg()); self.out_of_fuel.set(true); } - else { + else if fuel > 0{ self.optimization_fuel_limit.set(fuel-1); } } diff --git a/src/test/run-pass/optimization-fuel-0.rs b/src/test/run-pass/optimization-fuel-0.rs new file mode 100644 index 0000000000000..3832c040108f8 --- /dev/null +++ b/src/test/run-pass/optimization-fuel-0.rs @@ -0,0 +1,24 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name="foo"] + +use std::mem::size_of; + +// compile-flags: -Z fuel=foo=0 + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); + +fn main() { + assert_eq!(size_of::(), 6); + assert_eq!(size_of::(), 6); +} + diff --git a/src/test/run-pass/optimization-fuel-1.rs b/src/test/run-pass/optimization-fuel-1.rs new file mode 100644 index 0000000000000..5f294e26aa53e --- /dev/null +++ b/src/test/run-pass/optimization-fuel-1.rs @@ -0,0 +1,26 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name="foo"] + +use std::mem::size_of; + +// compile-flags: -Z fuel=foo=1 + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); + +fn main() { + let optimized = (size_of::() == 4) as usize + +(size_of::() == 4) as usize; + assert_eq!(optimized, 1); +} + + From 8b00837691d9757b6c607b28b42d33dd581cac3b Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Fri, 10 Mar 2017 14:24:50 -0500 Subject: [PATCH 617/662] UI test for -Z print-fuel=foo --- src/test/ui/print-fuel/print-fuel.rs | 21 +++++++++++++++++++++ src/test/ui/print-fuel/print-fuel.stdout | 1 + 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/print-fuel/print-fuel.rs create mode 100644 src/test/ui/print-fuel/print-fuel.stdout diff --git a/src/test/ui/print-fuel/print-fuel.rs b/src/test/ui/print-fuel/print-fuel.rs new file mode 100644 index 0000000000000..0d9e243763f78 --- /dev/null +++ b/src/test/ui/print-fuel/print-fuel.rs @@ -0,0 +1,21 @@ +// 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. + +#![crate_name="foo"] +#![allow(dead_code)] + +// compile-flags: -Z print-fuel=foo + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); +struct S3(u8, u16, u8); + +fn main() { +} diff --git a/src/test/ui/print-fuel/print-fuel.stdout b/src/test/ui/print-fuel/print-fuel.stdout new file mode 100644 index 0000000000000..cc88cc077bb21 --- /dev/null +++ b/src/test/ui/print-fuel/print-fuel.stdout @@ -0,0 +1 @@ +Fuel used by foo: 3 From 98eb121b7a748fd2668bf03ace8307be2880955f Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Mon, 20 Mar 2017 14:07:46 -0400 Subject: [PATCH 618/662] We have to use u16 to test field reordering because u64's alignment changes based on 32-bit or 64-bit architecture. --- src/test/run-pass/type-sizes.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 9d1a3500a582a..2f50e63153ea4 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -33,13 +33,13 @@ enum e3 { struct ReorderedStruct { a: u8, - b: u64, + b: u16, c: u8 } enum ReorderedEnum { - A(u8, u64, u8), - B(u8, u64, u8), + A(u8, u16, u8), + B(u8, u16, u8), } pub fn main() { @@ -65,6 +65,6 @@ pub fn main() { assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 4 as usize); - assert_eq!(size_of::(), 16); - assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 6); } From 0931e2006a5f8fd88032247ea543239c628cf10c Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 16:28:47 -0500 Subject: [PATCH 619/662] Initial attempt at implementing optimization fuel and re-enabling struct field reordering. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1be7d1afe45a8..b32d05971ff3b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. + /// We want to know if we're allowed to do an optimization for crate crate. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From d821e98fd73ee16c2f2733570220b2b64d367d45 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 22:20:07 -0500 Subject: [PATCH 620/662] Make a comment better. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b32d05971ff3b..1be7d1afe45a8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate crate. + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From a384f131cbb3e79154cc99ef0d025fc9ed6d9674 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 11 Apr 2017 14:31:20 +0300 Subject: [PATCH 621/662] Fix handling of closure arguments Those did not take tuple reordering into account, causing majority of the compiler test suite to fail. --- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/mod.rs | 3 ++- src/librustc_trans/intrinsic.rs | 9 +++++---- src/librustc_trans/mir/mod.rs | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a344f89a66830..d7a4b3fda63bb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -598,7 +598,7 @@ impl<'a, 'gcx, 'tcx> Struct { // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed || repr.linear || repr.simd); + && !(repr.c || repr.packed || repr.linear || repr.simd); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ba9c177f90483..a2c356c20db09 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1419,7 +1419,8 @@ impl_stable_hash_for!(struct ReprOptions { c, packed, simd, - int + int, + linear }); impl ReprOptions { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5e7d612d17f82..b6fbc2f5ad537 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -16,7 +16,7 @@ use llvm; use llvm::{ValueRef}; use abi::{Abi, FnType}; use adt; -use mir::lvalue::LvalueRef; +use mir::lvalue::{LvalueRef, Alignment}; use base::*; use common::*; use declare; @@ -36,8 +36,6 @@ use syntax_pos::Span; use std::cmp::Ordering; use std::iter; -use mir::lvalue::Alignment; - fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { let llvm_name = match name { "sqrtf32" => "llvm.sqrt.f32", @@ -622,7 +620,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, for i in 0..elems.len() { let val = bcx.extract_value(val, i); - bcx.store(val, bcx.struct_gep(llresult, i), None); + let lval = LvalueRef::new_sized_ty(llresult, ret_ty, + Alignment::AbiAligned); + let (dest, _) = lval.trans_field_ptr(bcx, i); + bcx.store(val, dest, None); } C_nil(ccx) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c8d15d28708f4..f4c9a136ace3c 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -386,7 +386,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index)); for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() { - let dst = bcx.struct_gep(lvalue.llval, i); + let (dst, _) = lvalue.trans_field_ptr(bcx, i); let arg = &mircx.fn_ty.args[idx]; idx += 1; if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) { From e18c59fd48a8387767d44fdd4d36208dfd33f762 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 11 Apr 2017 15:57:49 +0300 Subject: [PATCH 622/662] Fix some nits --- src/librustc/session/mod.rs | 5 ++--- src/librustc_driver/lib.rs | 4 +++- src/librustc_trans/intrinsic.rs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1be7d1afe45a8..039db3d9ee911 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -530,11 +530,10 @@ impl Session { Some(ref c) if c == crate_name => { let fuel = self.optimization_fuel_limit.get(); ret = fuel != 0; - if fuel == 0 && !self.out_of_fuel.get(){ + if fuel == 0 && !self.out_of_fuel.get() { println!("optimization-fuel-exhausted: {}", msg()); self.out_of_fuel.set(true); - } - else if fuel > 0{ + } else if fuel > 0 { self.optimization_fuel_limit.set(fuel-1); } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1fef97d54a141..1a892b73aa5d7 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -518,7 +518,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } if sess.print_fuel_crate.is_some() { - control.compilation_done.callback = box |state| { + let old_callback = control.compilation_done.callback; + control.compilation_done.callback = box move |state| { + old_callback(state); let sess = state.session; println!("Fuel used by {}: {}", sess.print_fuel_crate.as_ref().unwrap(), diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b6fbc2f5ad537..7cfc28622c443 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -622,8 +622,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let val = bcx.extract_value(val, i); let lval = LvalueRef::new_sized_ty(llresult, ret_ty, Alignment::AbiAligned); - let (dest, _) = lval.trans_field_ptr(bcx, i); - bcx.store(val, dest, None); + let (dest, align) = lval.trans_field_ptr(bcx, i); + bcx.store(val, dest, align.to_align()); } C_nil(ccx) } From 143f7be8b65d5e1be549e1b283e8e3423bdab41c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 10 Apr 2017 14:35:28 +0200 Subject: [PATCH 623/662] Remove strings fulfilled with whitespaces in code block headers --- src/librustdoc/html/markdown.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index dca873a85d813..c59101cc77996 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -469,28 +469,28 @@ impl LangString { ); for token in tokens { - match token { + match token.trim() { "" => {}, "should_panic" => { data.should_panic = true; seen_rust_tags = seen_other_tags == false; } - "no_run" => { data.no_run = true; seen_rust_tags = seen_other_tags == false; } - "ignore" => { data.ignore = true; seen_rust_tags = seen_other_tags == false; } + "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } + "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; } "rust" => { data.rust = true; seen_rust_tags = true; } "test_harness" => { data.test_harness = true; - seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { if let Ok(_) = x[1..].parse::() { data.error_codes.push(x.to_owned()); - seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } else { seen_other_tags = true; } @@ -680,6 +680,7 @@ mod tests { t("{.example .rust}", false, false, false, true, false, false, Vec::new()); t("{.test_harness .rust}", false, false, false, true, true, false, Vec::new()); t("text, no_run", false, true, false, false, false, false, Vec::new()); + t("text,no_run", false, true, false, false, false, false, Vec::new()); } #[test] From 316af6082c8c23615cc54302ee7efa0811bbabe7 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Tue, 11 Apr 2017 14:51:56 +0200 Subject: [PATCH 624/662] Clarify Iterator::position doc Extend the example a little bit to show behaviour better. --- src/libcore/iter/iterator.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 618edf48abd04..8bf641e37fe46 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1532,14 +1532,18 @@ pub trait Iterator { /// Stopping at the first `true`: /// /// ``` - /// let a = [1, 2, 3]; + /// let a = [1, 2, 3, 4]; /// /// let mut iter = a.iter(); /// - /// assert_eq!(iter.position(|&x| x == 2), Some(1)); + /// assert_eq!(iter.position(|&x| x >= 2), Some(1)); /// /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&3)); + /// + /// // The returned index depends on iterator state + /// assert_eq!(iter.position(|&x| x == 4), Some(0)); + /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 13d008d1e8b671e78c92e61b42ae7b82f5736121 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 10 Apr 2017 11:22:38 -0700 Subject: [PATCH 625/662] Touch up rls integration * Use the right version when building combined installer * Update dependencies of rls as it depends on rustc and plugins * Fix build-manifest and the versions it uses for the rls --- cargo | 2 +- src/bootstrap/dist.rs | 18 ++++++++++++-- src/bootstrap/lib.rs | 3 +++ src/bootstrap/step.rs | 9 +++++-- src/tools/build-manifest/src/main.rs | 35 ++++++++++++++++------------ 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/cargo b/cargo index 4e95c6b41eca3..4729175045b41 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 +Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e786d69555a10..4328c4e3f1d4c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -39,8 +39,10 @@ use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) + } else if component == "rls" { + format!("{}-{}", component, build.package_vers(&build.release_num("rls"))) } else { - assert!(component.starts_with("rust") || component == "rls"); + assert!(component.starts_with("rust")); format!("{}-{}", component, build.rust_package_vers()) } } @@ -598,7 +600,8 @@ pub fn rls(build: &Build, stage: u32, target: &str) { let src = build.src.join("rls"); let release_num = build.release_num("rls"); - let name = format!("rls-{}", build.package_vers(&release_num)); + let name = pkgname(build, "rls"); + let version = build.rls_info.version(build, &release_num); let tmp = tmpdir(build); let image = tmp.join("rls-image"); @@ -614,6 +617,15 @@ pub fn rls(build: &Build, stage: u32, target: &str) { install(&src.join("LICENSE-MIT"), &doc, 0o644); install(&src.join("LICENSE-APACHE"), &doc, 0o644); + // Prepare the overlay + let overlay = tmp.join("rls-overlay"); + drop(fs::remove_dir_all(&overlay)); + t!(fs::create_dir_all(&overlay)); + install(&src.join("README.md"), &overlay, 0o644); + install(&src.join("LICENSE-MIT"), &overlay, 0o644); + install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes())); + // Generate the installer tarball let mut cmd = Command::new("sh"); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) @@ -623,6 +635,7 @@ pub fn rls(build: &Build, stage: u32, target: &str) { .arg(format!("--image-dir={}", sanitize_sh(&image))) .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--non-installed-overlay={}", sanitize_sh(&overlay))) .arg(format!("--package-name={}-{}", name, target)) .arg("--component-name=rls") .arg("--legacy-manifest-dirs=rustlib,cargo"); @@ -991,6 +1004,7 @@ pub fn hash_and_sign(build: &Build) { cmd.arg(today.trim()); cmd.arg(build.rust_package_vers()); cmd.arg(build.package_vers(&build.release_num("cargo"))); + cmd.arg(build.package_vers(&build.release_num("rls"))); cmd.arg(addr); t!(fs::create_dir_all(distdir(build))); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e91664ac8aba7..d711b63ea2e26 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -151,6 +151,7 @@ pub struct Build { out: PathBuf, rust_info: channel::GitInfo, cargo_info: channel::GitInfo, + rls_info: channel::GitInfo, local_rebuild: bool, // Probed tools at runtime @@ -234,6 +235,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let rls_info = channel::GitInfo::new(&src.join("rls")); let src_is_git = src.join(".git").exists(); Build { @@ -246,6 +248,7 @@ impl Build { rust_info: rust_info, cargo_info: cargo_info, + rls_info: rls_info, local_rebuild: local_rebuild, cc: HashMap::new(), cxx: HashMap::new(), diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index d1581576957dc..596cbcf01bb80 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -572,7 +572,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); rules.build("tool-rls", "rls") .host(true) - .dep(|s| s.name("libstd")) + .dep(|s| s.name("librustc")) + .dep(move |s| { + // rls, like cargo, uses procedural macros + s.name("librustc-link") + .target(&build.config.build) + .host(&build.config.build) + }) .run(move |s| compile::tool(build, s.stage, s.target, "rls")); // ======================================================================== @@ -695,7 +701,6 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("dist-analysis", "analysis") .dep(|s| s.name("dist-std")) - .default(true) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); rules.dist("dist-rls", "rls") diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index eab2dc75af8d0..248f3d49f0935 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -135,6 +135,7 @@ macro_rules! t { struct Builder { rust_release: String, cargo_release: String, + rls_release: String, input: PathBuf, output: PathBuf, gpg_passphrase: String, @@ -143,6 +144,7 @@ struct Builder { date: String, rust_version: String, cargo_version: String, + rls_version: String, } fn main() { @@ -152,6 +154,7 @@ fn main() { let date = args.next().unwrap(); let rust_release = args.next().unwrap(); let cargo_release = args.next().unwrap(); + let rls_release = args.next().unwrap(); let s3_address = args.next().unwrap(); let mut passphrase = String::new(); t!(io::stdin().read_to_string(&mut passphrase)); @@ -159,6 +162,7 @@ fn main() { Builder { rust_release: rust_release, cargo_release: cargo_release, + rls_release: rls_release, input: input, output: output, gpg_passphrase: passphrase, @@ -167,6 +171,7 @@ fn main() { date: date, rust_version: String::new(), cargo_version: String::new(), + rls_version: String::new(), }.build(); } @@ -174,6 +179,7 @@ impl Builder { fn build(&mut self) { self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); + self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu"); self.digest_and_sign(); let Manifest { manifest_version, date, pkg } = self.build_manifest(); @@ -223,11 +229,8 @@ impl Builder { self.package("rust-std", &mut manifest.pkg, TARGETS); self.package("rust-docs", &mut manifest.pkg, TARGETS); self.package("rust-src", &mut manifest.pkg, &["*"]); - - if self.rust_release == "nightly" { - self.package("rls", &mut manifest.pkg, HOSTS); - self.package("rust-analysis", &mut manifest.pkg, TARGETS); - } + self.package("rls", &mut manifest.pkg, HOSTS); + self.package("rust-analysis", &mut manifest.pkg, TARGETS); let mut pkg = Package { version: self.cached_version("rust").to_string(), @@ -266,6 +269,14 @@ impl Builder { }); } + extensions.push(Component { + pkg: "rls".to_string(), + target: host.to_string(), + }); + extensions.push(Component { + pkg: "rust-analysis".to_string(), + target: host.to_string(), + }); for target in TARGETS { if target != host { extensions.push(Component { @@ -273,16 +284,6 @@ impl Builder { target: target.to_string(), }); } - if self.rust_release == "nightly" { - extensions.push(Component { - pkg: "rust-analysis".to_string(), - target: target.to_string(), - }); - extensions.push(Component { - pkg: "rls".to_string(), - target: host.to_string(), - }); - } } extensions.push(Component { pkg: "rust-src".to_string(), @@ -348,6 +349,8 @@ impl Builder { format!("rust-src-{}.tar.gz", self.rust_release) } else if component == "cargo" { format!("cargo-{}-{}.tar.gz", self.cargo_release, target) + } else if component == "rls" { + format!("rls-{}-{}.tar.gz", self.rls_release, target) } else { format!("{}-{}-{}.tar.gz", component, self.rust_release, target) } @@ -356,6 +359,8 @@ impl Builder { fn cached_version(&self, component: &str) -> &str { if component == "cargo" { &self.cargo_version + } else if component == "rls" { + &self.rls_version } else { &self.rust_version } From 384ec80d2b3dd61a5f9910dc660bffea8710002e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 11 Apr 2017 23:52:51 +0300 Subject: [PATCH 626/662] store Spans for all MIR locals --- src/librustc/ich/impls_mir.rs | 3 +- src/librustc/mir/mod.rs | 40 +++++++++++-------- src/librustc/mir/visit.rs | 5 +-- .../borrowck/mir/elaborate_drops.rs | 6 +-- src/librustc_mir/build/expr/as_lvalue.rs | 3 +- src/librustc_mir/build/expr/as_rvalue.rs | 14 +++---- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 3 +- src/librustc_mir/build/matches/test.rs | 13 +++--- src/librustc_mir/build/misc.rs | 6 +-- src/librustc_mir/build/mod.rs | 12 ++++-- src/librustc_mir/shim.rs | 23 ++++++----- src/librustc_mir/transform/inline.rs | 15 +++---- src/librustc_mir/transform/promote_consts.rs | 6 ++- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_mir/util/patch.rs | 5 ++- src/librustc_mir/util/pretty.rs | 4 +- .../debuginfo/create_scope_map.rs | 2 +- src/librustc_trans/mir/mod.rs | 5 +-- 21 files changed, 96 insertions(+), 77 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 401f7e1921ab4..3ff8ffb35054a 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -22,7 +22,8 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); -impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info, +is_user_variable}); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index aea4684e526ce..9ff64b295b765 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -197,10 +197,10 @@ impl<'tcx> Mir<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - Some(local) - } else { + if self.local_decls[local].is_user_variable { None + } else { + Some(local) } }) } @@ -210,10 +210,10 @@ impl<'tcx> Mir<'tcx> { pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - None - } else { + if self.local_decls[local].is_user_variable { Some(local) + } else { + None } }) } @@ -370,6 +370,9 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return pointer are always mutable. pub mutability: Mutability, + /// True if this corresponds to a user-declared local variable. + pub is_user_variable: bool, + /// Type of this local. pub ty: Ty<'tcx>, @@ -379,24 +382,23 @@ pub struct LocalDecl<'tcx> { /// to generate better debuginfo. pub name: Option, - /// For user-declared variables, stores their source information. - /// - /// For temporaries, this is `None`. - /// - /// This is the primary way to differentiate between user-declared - /// variables and compiler-generated temporaries. - pub source_info: Option, + /// Source info of the local. + pub source_info: SourceInfo, } impl<'tcx> LocalDecl<'tcx> { /// Create a new `LocalDecl` for a temporary. #[inline] - pub fn new_temp(ty: Ty<'tcx>) -> Self { + pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { LocalDecl { mutability: Mutability::Mut, ty: ty, name: None, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, + is_user_variable: false } } @@ -404,12 +406,16 @@ impl<'tcx> LocalDecl<'tcx> { /// /// This must be inserted into the `local_decls` list as the first local. #[inline] - pub fn new_return_pointer(return_ty: Ty) -> LocalDecl { + pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability: Mutability::Mut, ty: return_ty, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, name: None, // FIXME maybe we do want some name here? + is_user_variable: false } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 733ad36de90e3..83963de8b0014 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -630,12 +630,11 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, name: _, ref $($mutability)* source_info, + is_user_variable: _, } = *local_decl; self.visit_ty(ty); - if let Some(ref $($mutability)* info) = *source_info { - self.visit_source_info(info); - } + self.visit_source_info(source_info); } fn super_visibility_scope(&mut self, diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 713e656666271..ca313622a3afd 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -307,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { data } - fn create_drop_flag(&mut self, index: MovePathIndex) { + fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { - patch.new_temp(tcx.types.bool) + patch.new_temp(tcx.types.bool, span) }); } @@ -374,7 +374,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, location, path, (maybe_live, maybe_dead)); if maybe_live && maybe_dead { - self.create_drop_flag(child) + self.create_drop_flag(child, terminator.source_info.span) } }); } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 1cd9a1b25bade..df2841a668269 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -62,7 +62,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let idx = unpack!(block = this.as_operand(block, None, index)); // bounds check: - let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty)); + let (len, lt) = (this.temp(usize_ty.clone(), expr_span), + this.temp(bool_ty, expr_span)); this.cfg.push_assign(block, source_info, // len = len(slice) &len, Rvalue::Len(slice.clone())); this.cfg.push_assign(block, source_info, // lt = idx < len diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6694107a8d485..fb547332c5f58 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = this.hir.bool_ty(); let minval = this.minval_literal(expr_span, expr.ty); - let is_min = this.temp(bool_ty); + let is_min = this.temp(bool_ty, expr_span); this.cfg.push_assign(block, source_info, &is_min, Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval)); @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } ExprKind::Box { value, value_extents } => { let value = this.hir.mirror(value); - let result = this.temp(expr.ty); + let result = this.temp(expr.ty, expr_span); // to start, malloc some memory of suitable type (thus far, uninitialized): this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty)); this.in_scope(value_extents, block, |this| { @@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = self.hir.bool_ty(); if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() { let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false); - let result_value = self.temp(result_tup); + let result_value = self.temp(result_tup, span); self.cfg.push_assign(block, source_info, &result_value, Rvalue::CheckedBinaryOp(op, @@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; // Check for / 0 - let is_zero = self.temp(bool_ty); + let is_zero = self.temp(bool_ty, span); let zero = self.zero_literal(span, ty); self.cfg.push_assign(block, source_info, &is_zero, Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero)); @@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let neg_1 = self.neg_1_literal(span, ty); let min = self.minval_literal(span, ty); - let is_neg_1 = self.temp(bool_ty); - let is_min = self.temp(bool_ty); - let of = self.temp(bool_ty); + let is_neg_1 = self.temp(bool_ty, span); + let is_min = self.temp(bool_ty, span); + let of = self.temp(bool_ty, span); // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 42d9ab4d2bf27..e4598b4143871 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -44,8 +44,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let expr_ty = expr.ty.clone(); - let temp = this.temp(expr_ty.clone()); let expr_span = expr.span; + let temp = this.temp(expr_ty.clone(), expr_span); let source_info = this.source_info(expr_span); if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) { diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 7336da654c184..c03432312b0ab 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let expr_ty = expr.ty; - let temp = this.temp(expr.ty.clone()); + let temp = this.temp(expr.ty.clone(), expr_span); unpack!(block = this.into(&temp, block, expr)); unpack!(block = this.build_drop(block, expr_span, temp, expr_ty)); block.unit() diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 705eb1f56608e..ddeec1fe6d0ba 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -710,7 +710,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mutability: mutability, ty: var_ty.clone(), name: Some(name), - source_info: Some(source_info), + source_info: source_info, + is_user_variable: true, }); self.var_indices.insert(var_id, var); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index f4fdf8ade900a..5fece4d6a5d23 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); - let discr = self.temp(discr_ty); + let discr = self.temp(discr_ty, test.span); self.cfg.push_assign(block, source_info, &discr, Rvalue::Discriminant(lvalue.clone())); assert_eq!(values.len() + 1, targets.len()); @@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let ty::TyRef(region, mt) = ty.sty { if let ty::TyArray(_, _) = mt.ty.sty { ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); - let val_slice = self.temp(ty); + let val_slice = self.temp(ty, test.span); self.cfg.push_assign(block, source_info, &val_slice, Rvalue::Cast(CastKind::Unsize, val, ty)); val = Operand::Consume(val_slice); @@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: value.clone() }); - let slice = self.temp(ty); + let slice = self.temp(ty, test.span); self.cfg.push_assign(block, source_info, &slice, Rvalue::Cast(CastKind::Unsize, array, ty)); Operand::Consume(slice) @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); - let eq_result = self.temp(bool_ty); + let eq_result = self.temp(bool_ty, test.span); let eq_block = self.cfg.start_new_block(); let cleanup = self.diverge_cleanup(); self.cfg.terminate(block, source_info, TerminatorKind::Call { @@ -349,7 +349,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TestKind::Len { len, op } => { let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty()); - let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); + let (actual, result) = (self.temp(usize_ty, test.span), + self.temp(bool_ty, test.span)); // actual = len(lvalue) self.cfg.push_assign(block, source_info, @@ -383,7 +384,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { left: Operand<'tcx>, right: Operand<'tcx>) -> BasicBlock { let bool_ty = self.hir.bool_ty(); - let result = self.temp(bool_ty); + let result = self.temp(bool_ty, span); // result = op(left, right) let source_info = self.source_info(span); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 99aa5cb0fa86e..35a8b245f2bb6 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// /// NB: **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. - pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { - let temp = self.local_decls.push(LocalDecl::new_temp(ty)); + pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Lvalue<'tcx> { + let temp = self.local_decls.push(LocalDecl::new_temp(ty, span)); let lvalue = Lvalue::Local(temp); debug!("temp: created temp {:?} with type {:?}", lvalue, self.local_decls[temp].ty); @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: u64) -> Lvalue<'tcx> { let usize_ty = self.hir.usize_ty(); - let temp = self.temp(usize_ty); + let temp = self.temp(usize_ty, source_info.span); self.cfg.push_assign_constant( block, source_info, &temp, Constant { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index db03a1c68f715..ef3fa23500b34 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -249,7 +249,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, breakable_scopes: vec![], - local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), + local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty, + span), 1), var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, @@ -304,8 +305,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.local_decls.push(LocalDecl { mutability: Mutability::Not, ty: ty, - source_info: None, + source_info: SourceInfo { + scope: ARGUMENT_VISIBILITY_SCOPE, + span: pattern.map_or(self.fn_span, |pat| pat.span) + }, name: name, + is_user_variable: false, }); } @@ -341,7 +346,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some(ref tmp) => tmp.clone(), None => { let ty = self.hir.unit_ty(); - let tmp = self.temp(ty); + let fn_span = self.fn_span; + let tmp = self.temp(ty, fn_span); self.unit_temp = Some(tmp.clone()); tmp } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 63d20be88feee..0cec84d16a81c 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -137,16 +137,20 @@ enum CallKind { Direct(DefId), } -fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl { - LocalDecl { mutability, ty, name: None, source_info: None } +fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { + LocalDecl { + mutability, ty, name: None, + source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span }, + is_user_variable: false + } } -fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) +fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span) -> IndexVec> { - iter::once(temp_decl(Mutability::Mut, sig.output())) + iter::once(temp_decl(Mutability::Mut, sig.output(), span)) .chain(sig.inputs().iter().map( - |ity| temp_decl(Mutability::Not, ity))) + |ity| temp_decl(Mutability::Not, ity, span))) .collect() } @@ -188,7 +192,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ), IndexVec::new(), sig.output(), - local_decls_for_sig(&sig), + local_decls_for_sig(&sig, span), sig.inputs().len(), vec![], span @@ -297,7 +301,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, debug!("build_call_shim: sig={:?}", sig); - let mut local_decls = local_decls_for_sig(&sig); + let mut local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; let rcvr_arg = Local::new(1+0); @@ -317,7 +321,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, tcx.mk_ref(re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable - }) + }), + span )); statements.push(Statement { source_info: source_info, @@ -442,7 +447,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields); - let local_decls = local_decls_for_sig(&sig); + let local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo { span: span, diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 80a9c06f11b28..ac2bdaad24f76 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -461,11 +461,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { for loc in callee_mir.vars_and_temps_iter() { let mut local = callee_mir.local_decls[loc].clone(); - if let Some(ref mut source_info) = local.source_info { - source_info.scope = scope_map[source_info.scope]; - - source_info.span = callsite.location.span; - } + local.source_info.scope = scope_map[local.source_info.scope]; + local.source_info.span = callsite.location.span; let idx = caller_mir.local_decls.push(local); local_map.push(idx); @@ -506,7 +503,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ty = dest.ty(caller_mir, self.tcx); - let temp = LocalDecl::new_temp(ty); + let temp = LocalDecl::new_temp(ty, callsite.location.span); let tmp = caller_mir.local_decls.push(temp); let tmp = Lvalue::Local(tmp); @@ -590,7 +587,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { arg.deref()); let ty = arg.ty(caller_mir, self.tcx); - let ref_tmp = LocalDecl::new_temp(ty); + let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span); let ref_tmp = caller_mir.local_decls.push(ref_tmp); let ref_tmp = Lvalue::Local(ref_tmp); @@ -611,7 +608,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty); - let cast_tmp = LocalDecl::new_temp(ptr_ty); + let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); let cast_tmp = caller_mir.local_decls.push(cast_tmp); let cast_tmp = Lvalue::Local(cast_tmp); @@ -645,7 +642,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ty = arg.ty(caller_mir, tcx); - let arg_tmp = LocalDecl::new_temp(ty); + let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); let arg_tmp = caller_mir.local_decls.push(arg_tmp); let arg_tmp = Lvalue::Local(arg_tmp); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 57cf4b1e8b02b..ed9a0d3809f24 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -208,7 +208,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let no_stmts = self.source[loc.block].statements.len(); let new_temp = self.promoted.local_decls.push( - LocalDecl::new_temp(self.source.local_decls[temp].ty)); + LocalDecl::new_temp(self.source.local_decls[temp].ty, + self.source.local_decls[temp].source_info.span)); debug!("promote({:?} @ {:?}/{:?}, {:?})", temp, loc, no_stmts, self.keep_original); @@ -379,7 +380,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }; // Declare return pointer local - let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect(); + let initial_locals = iter::once(LocalDecl::new_return_pointer(ty, span)) + .collect(); let mut promoter = Promoter { promoted: Mir::new( diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8eabe92fb98c0..1313b24fa74f5 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -881,7 +881,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { let decl = &self.mir.local_decls[index]; - span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022, + span_err!(self.tcx.sess, decl.source_info.span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); return; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index ccbc6700d89c1..04a1fc891cf1e 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -686,7 +686,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> } fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { - self.elaborator.patch().new_temp(ty) + self.elaborator.patch().new_temp(ty, self.source_info.span) } fn terminator_loc(&mut self, bb: BasicBlock) -> Location { diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 19f240da73059..7898d93c22e3b 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -11,6 +11,7 @@ use rustc::ty::Ty; use rustc::mir::*; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use syntax_pos::Span; /// This struct represents a patch to MIR, which can add /// new statements and basic blocks and patch over block @@ -92,10 +93,10 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { + pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; - self.new_locals.push(LocalDecl::new_temp(ty)); + self.new_locals.push(LocalDecl::new_temp(ty, span)); Local::new(index as usize) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index ef2bf6e543420..b202e1495104e 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -196,8 +196,8 @@ fn write_scope_tree(tcx: TyCtxt, // User variable types (including the user's name in a comment). for local in mir.vars_iter() { let var = &mir.local_decls[local]; - let (name, source_info) = if var.source_info.unwrap().scope == child { - (var.name.unwrap(), var.source_info.unwrap()) + let (name, source_info) = if var.source_info.scope == child { + (var.name.unwrap(), var.source_info) } else { // Not a variable or not declared in this scope. continue; diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index c6f8ba7b6dc78..3d074c31c8a32 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -65,7 +65,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function let mut has_variables = BitVector::new(mir.visibility_scopes.len()); for var in mir.vars_iter() { let decl = &mir.local_decls[var]; - has_variables.insert(decl.source_info.unwrap().scope.index()); + has_variables.insert(decl.source_info.scope.index()); } // Instantiate all scopes. diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c8d15d28708f4..892a27e4550a7 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -255,8 +255,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( if let Some(name) = decl.name { // User variable - let source_info = decl.source_info.unwrap(); - let debug_scope = mircx.scopes[source_info.scope]; + let debug_scope = mircx.scopes[decl.source_info.scope]; let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; if !lvalue_locals.contains(local.index()) && !dbg { @@ -268,7 +267,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( assert!(!ty.has_erasable_regions()); let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str()); if dbg { - let (scope, span) = mircx.debug_loc(source_info); + let (scope, span) = mircx.debug_loc(decl.source_info); declare_local(&bcx, &mircx.debug_context, name, ty, scope, VariableAccess::DirectVariable { alloca: lvalue.llval }, VariableKind::LocalVariable, span); From 56503dd4adf65518a9645409e534935c2f434fe2 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 11 Apr 2017 22:53:16 +0200 Subject: [PATCH 627/662] use correct vault url --- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index b322f56f0d048..c25c770136f90 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index cbe5f5936a506..e835e8d2f7161 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ From 0144613078b8210a774f51d7bf6282812bef1e91 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 11 Apr 2017 23:53:20 +0300 Subject: [PATCH 628/662] Move rvalue checking to MIR Fixes #41139. --- src/librustc_driver/driver.rs | 8 +- src/librustc_mir/diagnostics.rs | 33 ++++++++ src/librustc_mir/transform/type_check.rs | 48 ++++++++++- src/librustc_passes/diagnostics.rs | 33 -------- src/librustc_passes/lib.rs | 1 - src/librustc_passes/rvalues.rs | 103 ----------------------- src/test/compile-fail/issue-41139.rs | 18 ++++ 7 files changed, 97 insertions(+), 147 deletions(-) delete mode 100644 src/librustc_passes/rvalues.rs create mode 100644 src/test/compile-fail/issue-41139.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bdb05d06b0b10..4dfffe7fd5c98 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -35,7 +35,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, +use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats, mir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -957,10 +957,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "liveness checking", || middle::liveness::check_crate(tcx)); - time(time_passes, - "rvalue checking", - || rvalues::check_crate(tcx)); - time(time_passes, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); @@ -976,8 +972,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // in stage 4 below. passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); - passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(box mir::transform::type_check::TypeckMir); + passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass( box mir::transform::simplify_branches::SimplifyBranches::new("initial")); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index eb16812af9b02..bb07081fe433b 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; ``` "##, +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + E0396: r##" The value behind a raw pointer can't be determined at compile-time (or even link-time), which means it can't be used in a constant diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 3d604affbfea9..f209b93cee18f 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -24,6 +24,7 @@ use std::fmt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { @@ -87,6 +88,11 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.sanitize_type(rvalue, rval_ty); } + fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) { + self.super_local_decl(local_decl); + self.sanitize_type(local_decl, local_decl.ty); + } + fn visit_mir(&mut self, mir: &Mir<'tcx>) { self.sanitize_type(&"return type", mir.return_ty); for local_decl in &mir.local_decls { @@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fulfillment_cx: traits::FulfillmentContext<'tcx>, last_span: Span, body_id: ast::NodeId, + reported_errors: FxHashSet<(Ty<'tcx>, Span)>, } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fulfillment_cx: traits::FulfillmentContext::new(), last_span: DUMMY_SP, body_id: body_id, + reported_errors: FxHashSet(), } } @@ -641,9 +649,39 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn typeck_mir(&mut self, mir: &Mir<'tcx>) { + fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) { + match mir.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Arg => { + // return values of normal functions are required to be + // sized by typeck, but return values of ADT constructors are + // not because we don't include a `Self: Sized` bounds on them. + // + // Unbound parts of arguments were never required to be Sized + // - maybe we should make that a warning. + return + } + LocalKind::Var | LocalKind::Temp => {} + } + + let span = local_decl.source_info.span; + let ty = local_decl.ty; + if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + if let None = self.reported_errors.replace((ty, span)) { + span_err!(self.tcx().sess, span, E0161, + "cannot move a value of type {0}: the size of {0} \ + cannot be statically determined", ty); + } + } + } + + fn typeck_mir(&mut self, mir: &Mir<'gcx>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); + + for (local, local_decl) in mir.local_decls.iter_enumerated() { + self.check_local(mir, local, local_decl); + } + for block in mir.basic_blocks() { for stmt in &block.statements { if stmt.source_info.span != DUMMY_SP { @@ -698,16 +736,18 @@ impl TypeckMir { impl<'tcx> MirPass<'tcx> for TypeckMir { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - debug!("run_pass: {}", tcx.node_path_str(src.item_id())); + let item_id = src.item_id(); + let def_id = tcx.hir.local_def_id(item_id); + debug!("run_pass: {}", tcx.item_path_str(def_id)); if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. return; } - let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); + let param_env = ty::ParameterEnvironment::for_item(tcx, item_id); tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { - let mut checker = TypeChecker::new(&infcx, src.item_id()); + let mut checker = TypeChecker::new(&infcx, item_id); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 5f06eadb84a92..036a52d5a3db3 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -82,39 +82,6 @@ extern { ``` "##, -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - E0265: r##" This error indicates that a static or constant references itself. All statics and constants need to resolve to a value in an acyclic manner. diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 7a465f0ec4239..22566c813d86a 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -47,5 +47,4 @@ pub mod hir_stats; pub mod loops; pub mod mir_stats; pub mod no_asm; -pub mod rvalues; pub mod static_recursion; diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs deleted file mode 100644 index c367e71fcd246..0000000000000 --- a/src/librustc_passes/rvalues.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Checks that all rvalues in a crate have statically known size. check_crate -// is the public starting point. - -use rustc::dep_graph::DepNode; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization as mc; -use rustc::ty::{self, TyCtxt}; -use rustc::traits::Reveal; - -use rustc::hir; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use syntax::ast; -use syntax_pos::Span; - -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut rvcx = RvalueContext { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor()); -} - -struct RvalueContext<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_nested_body(&mut self, body_id: hir::BodyId) { - let body = self.tcx.hir.body(body_id); - self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { - let mut delegate = RvalueContextDelegate { - tcx: infcx.tcx, - param_env: &infcx.parameter_environment - }; - euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body); - }); - self.visit_body(body); - } -} - -struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - param_env: &'a ty::ParameterEnvironment<'gcx>, -} - -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> { - fn consume(&mut self, - _: ast::NodeId, - span: Span, - cmt: mc::cmt<'tcx>, - _: euv::ConsumeMode) { - debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty); - let ty = self.tcx.lift_to_global(&cmt.ty).unwrap(); - if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) { - span_err!(self.tcx.sess, span, E0161, - "cannot move a value of type {0}: the size of {0} cannot be statically determined", - ty); - } - } - - fn matched_pat(&mut self, - _matched_pat: &hir::Pat, - _cmt: mc::cmt, - _mode: euv::MatchMode) {} - - fn consume_pat(&mut self, - _consume_pat: &hir::Pat, - _cmt: mc::cmt, - _mode: euv::ConsumeMode) { - } - - fn borrow(&mut self, - _borrow_id: ast::NodeId, - _borrow_span: Span, - _cmt: mc::cmt, - _loan_region: &'tcx ty::Region, - _bk: ty::BorrowKind, - _loan_cause: euv::LoanCause) { - } - - fn decl_without_init(&mut self, - _id: ast::NodeId, - _span: Span) { - } - - fn mutate(&mut self, - _assignment_id: ast::NodeId, - _assignment_span: Span, - _assignee_cmt: mc::cmt, - _mode: euv::MutateMode) { - } -} diff --git a/src/test/compile-fail/issue-41139.rs b/src/test/compile-fail/issue-41139.rs new file mode 100644 index 0000000000000..15ca151c49a79 --- /dev/null +++ b/src/test/compile-fail/issue-41139.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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 get_function<'a>() -> &'a Fn() -> Trait { panic!("") } + +fn main() { + let t : &Trait = &get_function()(); + //~^ ERROR cannot move a value of type Trait + 'static +} From 540a069761c1184ee2998f23a24b76c97c274043 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 12 Apr 2017 00:44:17 +0300 Subject: [PATCH 629/662] address review comments --- src/librustc_mir/transform/type_check.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f209b93cee18f..bfb08de56d8bb 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -666,6 +666,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let span = local_decl.source_info.span; let ty = local_decl.ty; if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + // in current MIR construction, all non-control-flow rvalue + // expressions evaluate through `as_temp` or `into` a return + // slot or local, so to find all unsized rvalues it is enough + // to check all temps, return slots and locals. if let None = self.reported_errors.replace((ty, span)) { span_err!(self.tcx().sess, span, E0161, "cannot move a value of type {0}: the size of {0} \ From 2389830deaf39b736e35c471e39543d30f708972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Feb 2017 14:31:59 -0800 Subject: [PATCH 630/662] Highlight and simplify mismatched types Shorten mismatched types errors by replacing subtypes that are not different with `_`, and highlighting only the subtypes that are different. Given a file ```rust struct X { x: T1, y: T2, } fn foo() -> X, String> { X { x: X {x: "".to_string(), y: 2}, y: "".to_string()} } fn bar() -> Option { "".to_string() } ``` provide the following output ```rust error[E0308]: mismatched types --> file.rs:6:5 | 6 | X { x: X {x: "".to_string(), y: 2}, y: "".to_string()} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found {integer} | = note: expected type `X, _>` ^^^^^^^^^^^^^^^^^^^ // < highlighted found type `X, _>` ^^^^^^^^^ // < highlighted error[E0308]: mismatched types --> file.rs:6:5 | 10 | "".to_string() | ^^^^^^^^^^^^^^ expected struct `std::option::Option`, found `std::string::String` | = note: expected type `Option` ^^^^^^^ ^ // < highlighted found type `std::string::String` ``` --- src/librustc/infer/error_reporting/mod.rs | 288 +++++++++++++++++- src/librustc/infer/error_reporting/note.rs | 2 + src/librustc/ty/mod.rs | 2 +- src/librustc_errors/diagnostic.rs | 72 ++++- src/librustc_errors/diagnostic_builder.rs | 10 +- src/librustc_errors/lib.rs | 2 +- .../ex2a-push-one-existing-name.stderr | 4 +- .../ex2b-push-no-existing-names.stderr | 4 +- .../ex2c-push-inference-variable.stderr | 2 +- src/test/ui/mismatched_types/abridged.rs | 61 ++++ src/test/ui/mismatched_types/abridged.stderr | 70 +++++ 11 files changed, 485 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/mismatched_types/abridged.rs create mode 100644 src/test/ui/mismatched_types/abridged.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9fa2bc8a2a7a9..dcbe50de2e9b2 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -70,7 +70,7 @@ use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, Issue32330}; use ty::error::TypeError; use syntax_pos::{Pos, Span}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; @@ -365,6 +365,262 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` + /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and + /// populate `other_value` with `other_ty`. + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn highlight_outer(&self, + mut value: &mut DiagnosticStyledString, + mut other_value: &mut DiagnosticStyledString, + name: String, + sub: &ty::subst::Substs<'tcx>, + pos: usize, + other_ty: &ty::Ty<'tcx>) { + // `value` and `other_value` hold two incomplete type representation for display. + // `name` is the path of both types being compared. `sub` + value.push_highlighted(name); + let len = sub.len(); + if len > 0 { + value.push_highlighted("<"); + } + + // Output the lifetimes fot the first type + let lifetimes = sub.regions().map(|lifetime| { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + }).collect::>().join(", "); + if !lifetimes.is_empty() { + if sub.regions().count() < len { + value.push_normal(lifetimes + &", "); + } else { + value.push_normal(lifetimes); + } + } + + // Highlight all the type arguments that aren't at `pos` and compare the type argument at + // `pos` and `other_ty`. + for (i, type_arg) in sub.types().enumerate() { + if i == pos { + let values = self.cmp(type_arg, other_ty); + value.0.extend((values.0).0); + other_value.0.extend((values.1).0); + } else { + value.push_highlighted(format!("{}", type_arg)); + } + + if len > 0 && i != len - 1 { + value.push_normal(", "); + } + //self.push_comma(&mut value, &mut other_value, len, i); + } + if len > 0 { + value.push_highlighted(">"); + } + } + + /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, + /// as that is the difference to the other type. + /// + /// For the following code: + /// + /// ```norun + /// let x: Foo> = foo::>(); + /// ``` + /// + /// The type error output will behave in the following way: + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn cmp_type_arg(&self, + mut t1_out: &mut DiagnosticStyledString, + mut t2_out: &mut DiagnosticStyledString, + path: String, + sub: &ty::subst::Substs<'tcx>, + other_path: String, + other_ty: &ty::Ty<'tcx>) -> Option<()> { + for (i, ta) in sub.types().enumerate() { + if &ta == other_ty { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + if let &ty::TyAdt(def, _) = &ta.sty { + let path_ = self.tcx.item_path_str(def.did.clone()); + if path_ == other_path { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + } + } + None + } + + /// Add a `,` to the type representation only if it is appropriate. + fn push_comma(&self, + value: &mut DiagnosticStyledString, + other_value: &mut DiagnosticStyledString, + len: usize, + pos: usize) { + if len > 0 && pos != len - 1 { + value.push_normal(", "); + other_value.push_normal(", "); + } + } + + /// Compare two given types, eliding parts that are the same between them and highlighting + /// relevant differences, and return two representation of those types for highlighted printing. + fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>) + -> (DiagnosticStyledString, DiagnosticStyledString) + { + match (&t1.sty, &t2.sty) { + (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { + let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); + let path1 = self.tcx.item_path_str(def1.did.clone()); + let path2 = self.tcx.item_path_str(def2.did.clone()); + if def1.did == def2.did { + // Easy case. Replace same types with `_` to shorten the output and highlight + // the differing ones. + // let x: Foo = y::>(); + // Foo + // Foo + // --- ^ type argument elided + // | + // highlighted in output + values.0.push_normal(path1); + values.1.push_normal(path2); + + // Only draw `<...>` if there're lifetime/type arguments. + let len = sub1.len(); + if len > 0 { + values.0.push_normal("<"); + values.1.push_normal("<"); + } + + fn lifetime_display(lifetime: &Region) -> String { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + } + // At one point we'd like to elide all lifetimes here, they are irrelevant for + // all diagnostics that use this output + // + // Foo<'x, '_, Bar> + // Foo<'y, '_, Qux> + // ^^ ^^ --- type arguments are not elided + // | | + // | elided as they were the same + // not elided, they were different, but irrelevant + let lifetimes = sub1.regions().zip(sub2.regions()); + for (i, lifetimes) in lifetimes.enumerate() { + let l1 = lifetime_display(lifetimes.0); + let l2 = lifetime_display(lifetimes.1); + if l1 == l2 { + values.0.push_normal("'_"); + values.1.push_normal("'_"); + } else { + values.0.push_highlighted(l1); + values.1.push_highlighted(l2); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // We're comparing two types with the same path, so we compare the type + // arguments for both. If they are the same, do not highlight and elide from the + // output. + // Foo<_, Bar> + // Foo<_, Qux> + // ^ elided type as this type argument was the same in both sides + let type_arguments = sub1.types().zip(sub2.types()); + let regions_len = sub1.regions().collect::>().len(); + for (i, (ta1, ta2)) in type_arguments.enumerate() { + let i = i + regions_len; + if ta1 == ta2 { + values.0.push_normal("_"); + values.1.push_normal("_"); + } else { + let (x1, x2) = self.cmp(ta1, ta2); + (values.0).0.extend(x1.0); + (values.1).0.extend(x2.0); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // Close the type argument bracket. + // Only draw `<...>` if there're lifetime/type arguments. + if len > 0 { + values.0.push_normal(">"); + values.1.push_normal(">"); + } + values + } else { + // Check for case: + // let x: Foo = foo::>(); + // Foo + // ------- this type argument is exactly the same as the other type + // Bar + if self.cmp_type_arg(&mut values.0, + &mut values.1, + path1.clone(), + sub1, + path2.clone(), + &t2).is_some() { + return values; + } + // Check for case: + // let x: Bar = y:>>(); + // Bar + // Foo> + // ------- this type argument is exactly the same as the other type + if self.cmp_type_arg(&mut values.1, + &mut values.0, + path2, + sub2, + path1, + &t1).is_some() { + return values; + } + + // We couldn't find anything in common, highlight everything. + // let x: Bar = y::>(); + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + _ => { + if t1 == t2 { + // The two types are the same, elide and don't highlight. + (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) + } else { + // We couldn't find anything in common, highlight everything. + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + } + } + pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, @@ -397,14 +653,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { - (&TypeError::Sorts(ref values), false, true) => { + (&TypeError::Sorts(ref values), false, true) => { diag.note_expected_found_extra( - &"type", &expected, &found, + &"type", expected, found, &format!(" ({})", values.expected.sort_string(self.tcx)), &format!(" ({})", values.found.sort_string(self.tcx))); } (_, false, _) => { - diag.note_expected_found(&"type", &expected, &found); + diag.note_expected_found(&"type", expected, found); } _ => (), } @@ -472,26 +728,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag } - /// Returns a string of the form "expected `{}`, found `{}`". - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { + fn values_str(&self, values: &ValuePairs<'tcx>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> + { match *values { - infer::Types(ref exp_found) => self.expected_found_str(exp_found), + infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } + fn expected_found_str_ty(&self, + exp_found: &ty::error::ExpectedFound>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { + return None; + } + + Some(self.cmp(exp_found.expected, exp_found.found)) + } + + /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) - -> Option<(String, String)> + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_type_vars_if_possible(exp_found); if exp_found.references_error() { return None; } - Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) + Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), + DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) } fn report_generic_bound_failure(&self, diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 8f8b2603dad84..8b753e0d22be7 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -20,6 +20,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match *origin { infer::Subtype(ref trace) => { if let Some((expected, found)) = self.values_str(&trace.values) { + let expected = expected.content(); + let found = found.content(); // FIXME: do we want a "the" here? err.span_note(trace.cause.span, &format!("...so that {} (expected {}, found {})", diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f1..3c51fd546c7c2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2218,7 +2218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `DefId` is really just an interned def-path). /// /// Note that if `id` is not local to this crate, the result will - // be a non-local `DefPath`. + /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { if id.is_local() { self.hir.def_path(id) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1b77ead92deb6..9715ace3e2e2e 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -35,6 +35,46 @@ pub struct SubDiagnostic { pub render_span: Option, } +#[derive(PartialEq, Eq)] +pub struct DiagnosticStyledString(pub Vec); + +impl DiagnosticStyledString { + pub fn new() -> DiagnosticStyledString { + DiagnosticStyledString(vec![]) + } + pub fn push_normal>(&mut self, t: S) { + self.0.push(StringPart::Normal(t.into())); + } + pub fn push_highlighted>(&mut self, t: S) { + self.0.push(StringPart::Highlighted(t.into())); + } + pub fn normal>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Normal(t.into())]) + } + + pub fn highlighted>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) + } + + pub fn content(&self) -> String { + self.0.iter().map(|x| x.content()).collect::() + } +} + +#[derive(PartialEq, Eq)] +pub enum StringPart { + Normal(String), + Highlighted(String), +} + +impl StringPart { + pub fn content(&self) -> String { + match self { + &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned() + } + } +} + impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) @@ -81,8 +121,8 @@ impl Diagnostic { pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self { self.note_expected_found_extra(label, expected, found, &"", &"") @@ -90,21 +130,29 @@ impl Diagnostic { pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self { + let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)]; + msg.extend(expected.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}\n", expected_extra), Style::NoStyle)); + msg.push((format!(" found {} `", label), Style::NoStyle)); + msg.extend(found.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}", found_extra), Style::NoStyle)); + // For now, just attach these as notes - self.highlighted_note(vec![ - (format!("expected {} `", label), Style::NoStyle), - (format!("{}", expected), Style::Highlight), - (format!("`{}\n", expected_extra), Style::NoStyle), - (format!(" found {} `", label), Style::NoStyle), - (format!("{}", found), Style::Highlight), - (format!("`{}", found_extra), Style::NoStyle), - ]); + self.highlighted_note(msg); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7dfea6b8951b0..7b27f13951b61 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -9,6 +9,8 @@ // except according to those terms. use Diagnostic; +use DiagnosticStyledString; + use Level; use Handler; use std::fmt::{self, Debug}; @@ -115,14 +117,14 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self); forward!(pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 2efdaa57fba36..da29e354a7014 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -203,7 +203,7 @@ impl error::Error for ExplicitBug { } } -pub use diagnostic::{Diagnostic, SubDiagnostic}; +pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, StringPart}; pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr index 6f42a9f679a6a..6956a043cc694 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 16 | x.push(y); | ^ lifetime mismatch | - = note: expected type `Ref<'a, i32>` - found type `Ref<'_, i32>` + = note: expected type `Ref<'a, _>` + found type `Ref<'_, _>` note: the anonymous lifetime #2 defined on the body at 15:51... --> $DIR/ex2a-push-one-existing-name.rs:15:52 | diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr index edc1c2362de57..990ae65ba9854 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 16 | x.push(y); | ^ lifetime mismatch | - = note: expected type `Ref<'_, i32>` - found type `Ref<'_, i32>` + = note: expected type `Ref<'_, _>` + found type `Ref<'_, _>` note: the anonymous lifetime #3 defined on the body at 15:43... --> $DIR/ex2b-push-no-existing-names.rs:15:44 | diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr index 755b71d4a1d9e..82f6c71ec1c2e 100644 --- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr @@ -27,7 +27,7 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body 17 | | x.push(z); 18 | | } | |_^ ...ending here -note: ...so that expression is assignable (expected Ref<'b, i32>, found Ref<'_, i32>) +note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>) --> $DIR/ex2c-push-inference-variable.rs:17:12 | 17 | x.push(z); diff --git a/src/test/ui/mismatched_types/abridged.rs b/src/test/ui/mismatched_types/abridged.rs new file mode 100644 index 0000000000000..c448ad955fab4 --- /dev/null +++ b/src/test/ui/mismatched_types/abridged.rs @@ -0,0 +1,61 @@ +// Copyright 2017 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. + +enum Bar { + Qux, + Zar, +} + +struct Foo { + bar: usize, +} + +struct X { + x: T1, + y: T2, +} + +fn a() -> Foo { + Some(Foo { bar: 1 }) +} + +fn a2() -> Foo { + Ok(Foo { bar: 1}) +} + +fn b() -> Option { + Foo { bar: 1 } +} + +fn c() -> Result { + Foo { bar: 1 } +} + +fn d() -> X, String> { + X { + x: X { + x: "".to_string(), + y: 2, + }, + y: 3, + } +} + +fn e() -> X, String> { + X { + x: X { + x: "".to_string(), + y: 2, + }, + y: "".to_string(), + } +} + +fn main() {} diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr new file mode 100644 index 0000000000000..c67c6113d17c5 --- /dev/null +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -0,0 +1,70 @@ +error[E0308]: mismatched types + --> $DIR/abridged.rs:26:5 + | +26 | Some(Foo { bar: 1 }) + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option` + | + = note: expected type `Foo` + found type `std::option::Option` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:30:5 + | +30 | Ok(Foo { bar: 1}) + | ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result` + | + = note: expected type `Foo` + found type `std::result::Result` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:34:5 + | +34 | Foo { bar: 1 } + | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo` + | + = note: expected type `std::option::Option` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:38:5 + | +38 | Foo { bar: 1 } + | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo` + | + = note: expected type `std::result::Result` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:42:5 + | +42 | X { + | _____^ starting here... +43 | | x: X { +44 | | x: "".to_string(), +45 | | y: 2, +46 | | }, +47 | | y: 3, +48 | | } + | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | + = note: expected type `X, std::string::String>` + found type `X, {integer}>` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:52:5 + | +52 | X { + | _____^ starting here... +53 | | x: X { +54 | | x: "".to_string(), +55 | | y: 2, +56 | | }, +57 | | y: "".to_string(), +58 | | } + | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | + = note: expected type `X, _>` + found type `X, _>` + +error: aborting due to 6 previous errors + From 4a0a0e949a077a6d83ca152daa404ff47c9c1dcf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 21:29:22 -0500 Subject: [PATCH 631/662] remove type variable defaults code This just limits ourselves to the "old school" defaults: diverging variables and integer variables. --- src/librustc_typeck/check/mod.rs | 211 +----------------- .../compile-fail/default_ty_param_conflict.rs | 33 --- .../default_ty_param_conflict_cross_crate.rs | 32 --- ...param_default_dependent_associated_type.rs | 36 --- .../default_ty_param_dependent_defaults.rs | 19 -- .../default_ty_param_method_call_test.rs | 24 -- src/test/run-pass/default_ty_param_struct.rs | 23 -- .../default_ty_param_struct_and_type_alias.rs | 40 ---- .../run-pass/default_ty_param_trait_impl.rs | 25 --- .../default_ty_param_trait_impl_simple.rs | 26 --- .../run-pass/default_ty_param_type_alias.rs | 19 -- 11 files changed, 3 insertions(+), 485 deletions(-) delete mode 100644 src/test/compile-fail/default_ty_param_conflict.rs delete mode 100644 src/test/compile-fail/default_ty_param_conflict_cross_crate.rs delete mode 100644 src/test/run-pass/default_ty_param_default_dependent_associated_type.rs delete mode 100644 src/test/run-pass/default_ty_param_dependent_defaults.rs delete mode 100644 src/test/run-pass/default_ty_param_method_call_test.rs delete mode 100644 src/test/run-pass/default_ty_param_struct.rs delete mode 100644 src/test/run-pass/default_ty_param_struct_and_type_alias.rs delete mode 100644 src/test/run-pass/default_ty_param_trait_impl.rs delete mode 100644 src/test/run-pass/default_ty_param_trait_impl_simple.rs delete mode 100644 src/test/run-pass/default_ty_param_type_alias.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c995b7e92843d..d300552af2caf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,7 +88,7 @@ use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; -use rustc::infer::type_variable::{self, TypeVariableOrigin}; +use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; @@ -105,7 +105,7 @@ use session::{Session, CompileResult}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; +use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell}; use std::cmp; @@ -1978,218 +1978,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + // Implements type inference fallback algorithm fn select_all_obligations_and_apply_defaults(&self) { - if self.tcx.sess.features.borrow().default_type_parameter_fallback { - self.new_select_all_obligations_and_apply_defaults(); - } else { - self.old_select_all_obligations_and_apply_defaults(); - } - } - - // Implements old type inference fallback algorithm - fn old_select_all_obligations_and_apply_defaults(&self) { self.select_obligations_where_possible(); self.default_type_parameters(); self.select_obligations_where_possible(); } - fn new_select_all_obligations_and_apply_defaults(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - // For the time being this errs on the side of being memory wasteful but provides better - // error reporting. - // let type_variables = self.type_variables.clone(); - - // There is a possibility that this algorithm will have to run an arbitrary number of times - // to terminate so we bound it by the compiler's recursion limit. - for _ in 0..self.tcx.sess.recursion_limit.get() { - // First we try to solve all obligations, it is possible that the last iteration - // has made it possible to make more progress. - self.select_obligations_where_possible(); - - let mut conflicts = Vec::new(); - - // Collect all unsolved type, integral and floating point variables. - let unsolved_variables = self.unsolved_variables(); - - // We must collect the defaults *before* we do any unification. Because we have - // directly attached defaults to the type variables any unification that occurs - // will erase defaults causing conflicting defaults to be completely ignored. - let default_map: FxHashMap, _> = - unsolved_variables - .iter() - .filter_map(|t| self.default(t).map(|d| (*t, d))) - .collect(); - - let mut unbound_tyvars = FxHashSet(); - - debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); - - // We loop over the unsolved variables, resolving them and if they are - // and unconstrainted numeric type we add them to the set of unbound - // variables. We do this so we only apply literal fallback to type - // variables without defaults. - for ty in &unsolved_variables { - let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt | UnconstrainedFloat => { - unbound_tyvars.insert(resolved); - }, - Neither => {} - } - } - } - - // We now remove any numeric types that also have defaults, and instead insert - // the type variable with a defined fallback. - for ty in &unsolved_variables { - if let Some(_default) = default_map.get(ty) { - let resolved = self.resolve_type_vars_if_possible(ty); - - debug!("select_all_obligations_and_apply_defaults: \ - ty: {:?} with default: {:?}", - ty, _default); - - match resolved.sty { - ty::TyInfer(ty::TyVar(_)) => { - unbound_tyvars.insert(ty); - } - - ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) => { - unbound_tyvars.insert(ty); - if unbound_tyvars.contains(resolved) { - unbound_tyvars.remove(resolved); - } - } - - _ => {} - } - } - } - - // If there are no more fallbacks to apply at this point we have applied all possible - // defaults and type inference will proceed as normal. - if unbound_tyvars.is_empty() { - break; - } - - // Finally we go through each of the unbound type variables and unify them with - // the proper fallback, reporting a conflicting default error if any of the - // unifications fail. We know it must be a conflicting default because the - // variable would only be in `unbound_tyvars` and have a concrete value if - // it had been solved by previously applying a default. - - // We wrap this in a transaction for error reporting, if we detect a conflict - // we will rollback the inference context to its prior state so we can probe - // for conflicts and correctly report them. - - let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| { - conflicts.extend( - self.apply_defaults_and_return_conflicts(&unbound_tyvars, &default_map, None) - ); - - // If there are conflicts we rollback, otherwise commit - if conflicts.len() > 0 { - Err(()) - } else { - Ok(()) - } - }); - - // Loop through each conflicting default, figuring out the default that caused - // a unification failure and then report an error for each. - for (conflict, default) in conflicts { - let conflicting_default = - self.apply_defaults_and_return_conflicts( - &unbound_tyvars, - &default_map, - Some(conflict) - ) - .last() - .map(|(_, tv)| tv) - .unwrap_or(type_variable::Default { - ty: self.next_ty_var( - TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)), - origin_span: syntax_pos::DUMMY_SP, - // what do I put here? - def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID) - }); - - // This is to ensure that we elimnate any non-determinism from the error - // reporting by fixing an order, it doesn't matter what order we choose - // just that it is consistent. - let (first_default, second_default) = - if default.def_id < conflicting_default.def_id { - (default, conflicting_default) - } else { - (conflicting_default, default) - }; - - - self.report_conflicting_default_types( - first_default.origin_span, - self.body_id, - first_default, - second_default) - } - } - - self.select_obligations_where_possible(); - } - - // For use in error handling related to default type parameter fallback. We explicitly - // apply the default that caused conflict first to a local version of the type variable - // table then apply defaults until we find a conflict. That default must be the one - // that caused conflict earlier. - fn apply_defaults_and_return_conflicts<'b>( - &'b self, - unbound_vars: &'b FxHashSet>, - default_map: &'b FxHashMap, type_variable::Default<'tcx>>, - conflict: Option>, - ) -> impl Iterator, type_variable::Default<'tcx>)> + 'b { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - conflict.into_iter().chain(unbound_vars.iter().cloned()).flat_map(move |ty| { - if self.type_var_diverges(ty) { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(ty) { - UnconstrainedInt => { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.f64) - }, - Neither => { - if let Some(default) = default_map.get(ty) { - let default = default.clone(); - let default_ty = self.normalize_associated_types_in( - default.origin_span, &default.ty); - match self.eq_types(false, - &self.misc(default.origin_span), - ty, - default_ty) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - return Some((ty, default)); - } - } - } - } - } - } - - None - }) - } - fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs deleted file mode 100644 index 8cde239ca6edf..0000000000000 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -use std::fmt::Debug; - -// Example from the RFC -fn foo() -> F { F::default() } -//~^ NOTE: a default was defined here... - -fn bar(b: B) { println!("{:?}", b); } -//~^ NOTE: a second default was defined here... - -fn main() { - // Here, F is instantiated with $0=uint - let x = foo(); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: ...that was applied to an unconstrained type variable here - - // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. - bar(x); - //~^ NOTE: ...that also applies to the same type variable here -} diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs deleted file mode 100644 index e5b035e50aa93..0000000000000 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -//aux-build:default_ty_param_cross_crate_crate.rs - -#![feature(default_type_parameter_fallback)] - -extern crate default_param_test; - -use default_param_test::{Foo, bleh}; - -fn meh(x: Foo) {} -//~^ NOTE: a default was defined here... - -fn main() { - let foo = bleh(); - //~^ NOTE: ...that also applies to the same type variable here - - meh(foo); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `bool` and `char` - //~| NOTE: conflicting type parameter defaults `bool` and `char` - //~| a second default is defined on `default_param_test::bleh` - //~| NOTE: ...that was applied to an unconstrained type variable here -} diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs deleted file mode 100644 index 8fc2c2e6bce70..0000000000000 --- a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// - -#![feature(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -trait Id { - type This; -} - -impl Id for A { - type This = A; -} - -struct Foo::This> { - data: PhantomData<(X, Y)> -} - -impl Foo { - fn new() -> Foo { - Foo { data: PhantomData } - } -} - -fn main() { - let foo = Foo::new(); -} diff --git a/src/test/run-pass/default_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs deleted file mode 100644 index ac833d0f54744..0000000000000 --- a/src/test/run-pass/default_ty_param_dependent_defaults.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// - -#![feature(default_type_parameter_fallback)] -use std::marker::PhantomData; - -struct Foo { t: T, data: PhantomData } - -fn main() { - let foo = Foo { t: 'a', data: PhantomData }; -} diff --git a/src/test/run-pass/default_ty_param_method_call_test.rs b/src/test/run-pass/default_ty_param_method_call_test.rs deleted file mode 100644 index e8d93092ec53d..0000000000000 --- a/src/test/run-pass/default_ty_param_method_call_test.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -struct Foo; - -impl Foo { - fn method(&self) -> A { - A::default() - } -} - -fn main() { - let f = Foo.method(); - println!("{}", f); -} diff --git a/src/test/run-pass/default_ty_param_struct.rs b/src/test/run-pass/default_ty_param_struct.rs deleted file mode 100644 index d9ac51fc23b02..0000000000000 --- a/src/test/run-pass/default_ty_param_struct.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -struct Foo(A); - -impl Foo { - fn new() -> Foo { - Foo(A::default()) - } -} - -fn main() { - let foo = Foo::new(); -} diff --git a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs deleted file mode 100644 index d3bdab9082e32..0000000000000 --- a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// - -#![feature(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -pub struct DeterministicHasher; -pub struct RandomHasher; - - -pub struct MyHashMap { - data: PhantomData<(K, V, H)> -} - -impl MyHashMap { - fn new() -> MyHashMap { - MyHashMap { data: PhantomData } - } -} - -mod mystd { - use super::{MyHashMap, RandomHasher}; - pub type HashMap = MyHashMap; -} - -fn try_me(hash_map: mystd::HashMap) {} - -fn main() { - let hash_map = mystd::HashMap::new(); - try_me(hash_map); -} diff --git a/src/test/run-pass/default_ty_param_trait_impl.rs b/src/test/run-pass/default_ty_param_trait_impl.rs deleted file mode 100644 index c67d3a49aff3d..0000000000000 --- a/src/test/run-pass/default_ty_param_trait_impl.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -// Another example from the RFC -trait Foo { } -trait Bar { } - -impl Foo for Vec {} -impl Bar for usize {} - -fn takes_foo(f: F) {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - takes_foo(x); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default_ty_param_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_trait_impl_simple.rs deleted file mode 100644 index 067ad524922c0..0000000000000 --- a/src/test/run-pass/default_ty_param_trait_impl_simple.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -// An example from the RFC -trait Foo { fn takes_foo(&self); } -trait Bar { } - -impl Foo for Vec { - fn takes_foo(&self) {} -} - -impl Bar for usize {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - x.takes_foo(); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default_ty_param_type_alias.rs b/src/test/run-pass/default_ty_param_type_alias.rs deleted file mode 100644 index 1b4747406d0c6..0000000000000 --- a/src/test/run-pass/default_ty_param_type_alias.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -use std::collections::HashMap; - -type IntMap = HashMap; - -fn main() { - let x = IntMap::new(); -} From 18ea55fe1636001c4d030911e2c4c165af1cabfc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 10 Mar 2017 13:30:09 -0500 Subject: [PATCH 632/662] remove bivariance There is one fishy part of these changes: when computing the LUB/GLB of a "bivariant" type parameter, I currently return the `a` value. Bivariant type parameters are only allowed in a very particular situation, where the type parameter is only used as an associated type output, like this: ```rust pub struct Foo where A: Fn() -> B { data: A } ``` In principle, if one had `T=Foo` and `U=Foo` and (e.g.) `A: for<'a> Fn() -> &'a u32`, then I think that computing the LUB of `T` and `U` might do the wrong thing. Probably the right behavior is just to create a fresh type variable. However, that particular example would not compile (because the where-clause is illegal; `'a` does not appear in any input type). I was not able to make an example that *would* compile and demonstrate this shortcoming, and handling the LUB/GLB was mildly inconvenient, so I left it as is. I am considering whether to revisit this. --- src/librustc/infer/bivariate.rs | 123 -------------------------------- src/librustc/infer/combine.rs | 7 +- src/librustc/infer/glb.rs | 2 +- src/librustc/infer/lub.rs | 2 +- src/librustc/infer/mod.rs | 1 - src/librustc/infer/sub.rs | 2 +- 6 files changed, 4 insertions(+), 133 deletions(-) delete mode 100644 src/librustc/infer/bivariate.rs diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs deleted file mode 100644 index 4acb8b807d594..0000000000000 --- a/src/librustc/infer/bivariate.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Applies the "bivariance relationship" to two types and/or regions. -//! If (A,B) are bivariant then either A <: B or B <: A. It occurs -//! when type/lifetime parameters are unconstrained. Usually this is -//! an error, but we permit it in the specific case where a type -//! parameter is constrained in a where-clause via an associated type. -//! -//! There are several ways one could implement bivariance. You could -//! just do nothing at all, for example, or you could fully verify -//! that one of the two subtyping relationships hold. We choose to -//! thread a middle line: we relate types up to regions, but ignore -//! all region relationships. -//! -//! At one point, handling bivariance in this fashion was necessary -//! for inference, but I'm actually not sure if that is true anymore. -//! In particular, it might be enough to say (A,B) are bivariant for -//! all (A,B). - -use super::combine::CombineFields; -use super::type_variable::{BiTo}; - -use ty::{self, Ty, TyCtxt}; -use ty::TyVar; -use ty::relate::{Relate, RelateResult, TypeRelation}; - -pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Bivariate<'combine, 'infcx, 'gcx, 'tcx> - { - Bivariate { fields: fields, a_is_expected: a_is_expected } - } -} - -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> - for Bivariate<'combine, 'infcx, 'gcx, 'tcx> -{ - fn tag(&self) -> &'static str { "Bivariate" } - - fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - // If we have Foo and Foo is invariant w/r/t A, - // and we want to assert that - // - // Foo <: Foo || - // Foo <: Foo - // - // then still A must equal B. - ty::Invariant => self.relate(a, b), - - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.relate(a, b), - ty::Contravariant => self.relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); - Ok(a) - } - - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?; - Ok(a) - } - - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?; - Ok(a) - } - - _ => { - self.fields.infcx.super_combine_tys(self, a, b) - } - } - } - - fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'tcx> - { - let a1 = self.tcx().erase_late_bound_regions(a); - let b1 = self.tcx().erase_late_bound_regions(b); - let c = self.relate(&a1, &b1)?; - Ok(ty::Binder(c)) - } -} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 5d33d6e6d2e71..9430421f91014 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -32,7 +32,6 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. -use super::bivariate::Bivariate; use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; @@ -159,10 +158,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Equate::new(self, a_is_expected) } - pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> { - Bivariate::new(self, a_is_expected) - } - pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> { Sub::new(self, a_is_expected) } @@ -251,7 +246,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { - BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty), + BiTo => Ok(a_ty), EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), SupertypeOf => self.sub(a_is_expected).relate_with_variance( diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8ccadc6b2af04..8c167e0a8ac91 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -49,7 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 89571dea10c34..28ae1ae556b0b 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -49,7 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b07ef4dfd448e..98c8ce0f03144 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -48,7 +48,6 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; -mod bivariate; mod combine; mod equate; pub mod error_reporting; diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index dae30ea97c80d..a6b0e02d47722 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -65,7 +65,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), } } From 58609ef879e604d161f4ee6c612d6d127120e289 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 21:47:09 -0500 Subject: [PATCH 633/662] add Subtype predicate --- src/librustc/ich/impls_ty.rs | 4 +++ src/librustc/infer/mod.rs | 39 ++++++++++++++++++++++- src/librustc/middle/free_region.rs | 1 + src/librustc/traits/error_reporting.rs | 23 +++++++++++++ src/librustc/traits/fulfill.rs | 21 ++++++++++++ src/librustc/traits/object_safety.rs | 2 ++ src/librustc/traits/select.rs | 12 +++++++ src/librustc/traits/structural_impls.rs | 1 + src/librustc/traits/util.rs | 9 +++++- src/librustc/ty/mod.rs | 17 ++++++++++ src/librustc/ty/structural_impls.rs | 35 ++++++++++++++++++-- src/librustc/ty/util.rs | 1 + src/librustc/ty/wf.rs | 5 +++ src/librustc/util/ppaux.rs | 14 ++++++++ src/librustc_typeck/check/closure.rs | 1 + src/librustc_typeck/check/method/probe.rs | 1 + src/librustdoc/clean/mod.rs | 11 +++++++ 17 files changed, 193 insertions(+), 4 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11ec..b8888eee9c6ef 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -170,6 +170,7 @@ impl_stable_hash_for!(enum ty::Visibility { impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); +impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate where A: HashStable>, @@ -200,6 +201,9 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx ty::Predicate::Equate(ref pred) => { pred.hash_stable(hcx, hasher); } + ty::Predicate::Subtype(ref pred) => { + pred.hash_stable(hcx, hasher); + } ty::Predicate::RegionOutlives(ref pred) => { pred.hash_stable(hcx, hasher); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 98c8ce0f03144..999ebbfa20fbf 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -551,7 +551,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { } impl ExpectedFound { - fn new(a_is_expected: bool, a: T, b: T) -> Self { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { if a_is_expected { ExpectedFound {expected: a, found: b} } else { @@ -1129,6 +1129,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } + pub fn subtype_predicate(&self, + cause: &ObligationCause<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>) + -> Option> + { + // Subtle: it's ok to skip the binder here and resolve because + // `shallow_resolve` just ignores anything that is not a type + // variable, and because type variable's can't (at present, at + // least) capture any of the things bound by this binder. + // + // Really, there is no *particular* reason to do this + // `shallow_resolve` here except as a + // micro-optimization. Naturally I could not + // resist. -nmatsakis + let two_unbound_type_vars = { + let a = self.shallow_resolve(predicate.skip_binder().a); + let b = self.shallow_resolve(predicate.skip_binder().b); + a.is_ty_var() && b.is_ty_var() + }; + + if two_unbound_type_vars { + // Two unbound type variables? Can't make progress. + return None; + } + + Some(self.commit_if_ok(|snapshot| { + let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + + let cause_span = cause.span; + let ok = self.sub_types(a_is_expected, cause, a, b)?; + self.leak_check(false, cause_span, &skol_map, snapshot)?; + self.pop_skolemized(skol_map, snapshot); + Ok(ok.unit()) + })) + } + pub fn region_outlives_predicate(&self, cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab40098..963cc4314eda5 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -60,6 +60,7 @@ impl FreeRegionMap { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 931c77badad22..8a303a5da1184 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -39,6 +39,7 @@ use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; +use ty::SubtypePredicate; use util::nodemap::{FxHashMap, FxHashSet}; use syntax_pos::{DUMMY_SP, Span}; @@ -112,6 +113,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { FulfillmentErrorCode::CodeAmbiguity => { self.maybe_report_ambiguity(&error.obligation); } + FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { + self.report_mismatched_types(&error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone()) + .emit(); + } } } @@ -555,6 +563,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } + ty::Predicate::Subtype(ref predicate) => { + // TODO + panic!("subtype requirement not satisfied {:?}", predicate) + } + ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.equality_predicate(&obligation.cause, @@ -761,6 +774,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref data) => { + if data.references_error() || self.tcx.sess.has_errors() { + // no need to overload user in such cases + } else { + let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); + assert!(a.is_ty_var() && b.is_ty_var()); // else other would've been instantiated + self.need_type_info(obligation, a); + } + } + _ => { if !self.tcx.sess.has_errors() { let mut err = struct_span_err!(self.tcx.sess, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b87d18464377f..64453f2983b92 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,6 +11,7 @@ use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate}; +use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; @@ -496,6 +497,26 @@ fn process_predicate<'a, 'gcx, 'tcx>( s => Ok(s) } } + + ty::Predicate::Subtype(ref subtype) => { + match selcx.infcx().subtype_predicate(&obligation.cause, subtype) { + None => { + // none means that both are unresolved + pending_obligation.stalled_on = vec![subtype.skip_binder().a, + subtype.skip_binder().b]; + Ok(None) + } + Some(Ok(ok)) => { + Ok(Some(ok.obligations)) + } + Some(Err(err)) => { + let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, + subtype.skip_binder().a, + subtype.skip_binder().b); + Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + } + } + } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7cd0b26940d91..d190635bec306 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -178,6 +178,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Equate(..) => { false } @@ -209,6 +210,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 38ea1e4a19b91..67d50210ba39a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -568,6 +568,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref p) => { + // does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, p) { + Some(Ok(InferOk { obligations, .. })) => { + self.inferred_obligations.extend(obligations); + EvaluatedToOk + }, + Some(Err(_)) => EvaluatedToErr, + None => EvaluatedToAmbig, + } + } + ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.infcx, obligation.cause.body_id, ty, obligation.cause.span) { diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 44ef461327ddb..fcaa29be9632c 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,6 +130,7 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeSubtypeError(ref a, ref b) => write!(f, "CodeSubtypeError({:?}, {:?})", a, b), super::CodeAmbiguity => write!(f, "Ambiguity") } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 602f27a64d4d8..d4245ec9b2475 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -42,7 +42,10 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::ObjectSafe(data), ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind) + ty::Predicate::ClosureKind(closure_def_id, kind), + + ty::Predicate::Subtype(ref data) => + ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), } } @@ -160,6 +163,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { // `X == Y`, though conceivably we might. For example, // `&X == &Y` implies that `X == Y`. } + ty::Predicate::Subtype(..) => { + // Currently, we do not "elaborate" predicates like `X + // <: Y`, though conceivably we might. + } ty::Predicate::Projection(..) => { // Nothing to elaborate in a projection predicate. } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f1..d720911db39fb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -755,6 +755,9 @@ pub enum Predicate<'tcx> { /// for some substitutions `...` and T being a closure type. /// Satisfied (or refuted) once we know the closure's kind. ClosureKind(DefId, ClosureKind), + + /// `T1 <: T2` + Subtype(PolySubtypePredicate<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { @@ -833,6 +836,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::Trait(ty::Binder(data.subst(tcx, substs))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::Subtype(ty::Binder(ref data)) => + Predicate::Subtype(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), Predicate::TypeOutlives(ty::Binder(ref data)) => @@ -912,6 +917,14 @@ pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Reg &'tcx ty::Region>; pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx ty::Region>; +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct SubtypePredicate<'tcx> { + pub a_is_expected: bool, + pub a: Ty<'tcx>, + pub b: Ty<'tcx> +} +pub type PolySubtypePredicate<'tcx> = ty::Binder>; + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1025,6 +1038,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } + ty::Predicate::Subtype(ty::Binder(SubtypePredicate { a, b, a_is_expected: _ })) => { + vec![a, b] + } ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { vec![data.0] } @@ -1061,6 +1077,7 @@ impl<'tcx> Predicate<'tcx> { } Predicate::Projection(..) | Predicate::Equate(..) | + Predicate::Subtype(..) | Predicate::RegionOutlives(..) | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9126600e3f653..a4466d7d84011 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -111,6 +111,18 @@ impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { + type Lifted = ty::SubtypePredicate<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option> { + tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: a, + b: b, + }) + } +} + impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -167,6 +179,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::Equate(ref binder) => { tcx.lift(binder).map(ty::Predicate::Equate) } + ty::Predicate::Subtype(ref binder) => { + tcx.lift(binder).map(ty::Predicate::Subtype) + } ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) } @@ -693,6 +708,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::Trait(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::Subtype(ref binder) => + ty::Predicate::Subtype(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => ty::Predicate::RegionOutlives(binder.fold_with(folder)), ty::Predicate::TypeOutlives(ref binder) => @@ -712,6 +729,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), + ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), @@ -776,8 +794,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::EquatePredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) + ty::EquatePredicate(self.0.fold_with(folder), self.1.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -785,6 +802,20 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: self.a.fold_with(folder), + b: self.b.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.a.visit_with(visitor) || self.b.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitPredicate { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9a6..2efefd750ae8a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -312,6 +312,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 8a5bd6862cf45..0b0e8a180cc36 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,10 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Subtype(ref data) => { + wf.compute(data.skip_binder().a); // (*) + wf.compute(data.skip_binder().b); // (*) + } } wf.normalize() @@ -156,6 +160,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match obligation.predicate { ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) => diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6323f1dc0d4c4..2daf71d95addf 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -416,6 +416,7 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), + ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair), @@ -676,6 +677,12 @@ impl<'tcx> fmt::Display for ty::Binder> { } } +impl<'tcx> fmt::Display for ty::Binder> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) + } +} + impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) @@ -897,6 +904,12 @@ impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> { } } +impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} <: {}", self.a, self.b) + } +} + impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TraitPredicate({:?})", @@ -949,6 +962,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), + ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 51fbc5aab6cd1..78176b155691c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -169,6 +169,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Equate(..) => None, + ty::Predicate::Subtype(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 5b0418921563a..8071fe3cc2806 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -576,6 +576,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } } ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a24c..1a194cd125462 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -875,6 +875,7 @@ impl<'a> Clean for ty::Predicate<'a> { match *self { Predicate::Trait(ref pred) => pred.clean(cx), Predicate::Equate(ref pred) => pred.clean(cx), + Predicate::Subtype(ref pred) => pred.clean(cx), Predicate::RegionOutlives(ref pred) => pred.clean(cx), Predicate::TypeOutlives(ref pred) => pred.clean(cx), Predicate::Projection(ref pred) => pred.clean(cx), @@ -904,6 +905,16 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } } +impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { + fn clean(&self, cx: &DocContext) -> WherePredicate { + let ty::SubtypePredicate { a_is_expected: _, a, b } = *self; + WherePredicate::EqPredicate { // TODO This is obviously wrong :P + lhs: a.clean(cx), + rhs: b.clean(cx) + } + } +} + impl<'tcx> Clean for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref a, ref b) = *self; From 4e4bdea0ae8b3b1995b002374db1a7b7639eb52d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 10 Mar 2017 05:19:49 -0500 Subject: [PATCH 634/662] propagate sub-obligations better The most interesting place is the hinting mechanism; once we start having subtyping obligations, it's important to see those through. --- src/librustc_typeck/check/method/probe.rs | 16 +++++++-------- src/librustc_typeck/check/mod.rs | 25 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8071fe3cc2806..59dbbfe49f0a9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1149,19 +1149,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.probe(|_| { // First check that the self type can be related. - match self.sub_types(false, - &ObligationCause::dummy(), - self_ty, - probe.xform_self_ty) { - Ok(InferOk { obligations, value: () }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - } + let sub_obligations = match self.sub_types(false, + &ObligationCause::dummy(), + self_ty, + probe.xform_self_ty) { + Ok(InferOk { obligations, value: () }) => obligations, Err(_) => { debug!("--> cannot relate self-types"); return false; } - } + }; // If so, impls may carry other conditions (e.g., where // clauses) that must be considered. Make sure that those @@ -1200,6 +1197,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Evaluate those obligations to see if they might possibly hold. let mut all_true = true; for o in obligations.iter() + .chain(sub_obligations.iter()) .chain(norm_obligations.iter()) .chain(ref_obligations.iter()) { if !selcx.evaluate_obligation(o) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d300552af2caf..77213b5a7436f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,7 +90,7 @@ use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; @@ -2552,11 +2552,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // No argument expectations are produced if unification fails. let origin = self.misc(call_span); let ures = self.sub_types(false, &origin, formal_ret, ret_ty); + // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(e) => return Err(e), + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + let result = self.save_and_restore_obligations_in_snapshot_flag(|_| { + let mut fulfill = FulfillmentContext::new(); + let ok = ok; // FIXME(#30046) + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }); + + match result { + Ok(()) => { } + Err(_) => return Err(()), + } + } + Err(_) => return Err(()), } // Record all the argument types, with the substitutions From 105ec7e3bbbef50076f0e6963e8a9327bacf7b5f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 10 Mar 2017 05:21:27 -0500 Subject: [PATCH 635/662] use obligations to propagate sub-typing instead of the TV code --- src/librustc/infer/sub.rs | 25 +++++++++++++++++++++---- src/librustc/traits/mod.rs | 5 ++++- src/test/compile-fail/issue-7813.rs | 5 ++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index a6b0e02d47722..1a94f12973de8 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -12,8 +12,10 @@ use super::SubregionOrigin; use super::combine::CombineFields; use super::type_variable::{SubtypeOf, SupertypeOf}; +use traits::Obligation; use ty::{self, Ty, TyCtxt}; use ty::TyVar; +use ty::fold::TypeFoldable; use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; @@ -79,10 +81,25 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables - .borrow_mut() - .relate_vars(a_id, SubtypeOf, b_id); + (&ty::TyInfer(TyVar(_)), &ty::TyInfer(TyVar(_))) => { + // Shouldn't have any LBR here, so we can safely put + // this under a binder below without fear of accidental + // capture. + assert!(!a.has_escaping_regions()); + assert!(!b.has_escaping_regions()); + + // can't make progress on `A <: B` if both A and B are + // type variables, so record an obligation. + self.fields.obligations.push( + Obligation::new( + self.fields.trace.cause.clone(), + ty::Predicate::Subtype( + ty::Binder(ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a, + b, + })))); + Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 47cbccdd2ab10..ea243d65881ea 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -20,7 +20,8 @@ use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate}; -use infer::InferCtxt; +use ty::error::{ExpectedFound, TypeError}; +use infer::{InferCtxt}; use std::rc::Rc; use syntax::ast; @@ -214,6 +215,8 @@ pub struct FulfillmentError<'tcx> { pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound>, + TypeError<'tcx>), // always comes from a SubtypePredicate CodeAmbiguity, } diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index fdd89058fd397..662b9e894ba3a 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -10,7 +10,6 @@ fn main() { let v = &[]; - let it = v.iter(); //~ ERROR type annotations needed [E0282] - //~| NOTE cannot infer type for `T` - //~| NOTE consider giving `it` a type + //~^ NOTE consider giving `it` a type + let it = v.iter(); //~ ERROR cannot infer type for `_` } From e58e2b423dabc816ba5d9e2382373622cc07bc8d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Mar 2017 09:05:39 -0400 Subject: [PATCH 636/662] remove the subtyping relations from TypeVariable --- src/librustc/infer/combine.rs | 14 ++- src/librustc/infer/equate.rs | 9 +- src/librustc/infer/sub.rs | 7 +- src/librustc/infer/type_variable.rs | 144 ++++++---------------------- src/librustc/lib.rs | 1 + src/test/compile-fail/issue-7813.rs | 6 +- 6 files changed, 51 insertions(+), 130 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 9430421f91014..825f279e78e4b 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -38,7 +38,6 @@ use super::lub::Lub; use super::sub::Sub; use super::InferCtxt; use super::{MiscVariable, TypeTrace}; -use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use ty::{IntType, UintType}; use ty::{self, Ty, TyCtxt}; @@ -59,6 +58,11 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub obligations: PredicateObligations<'tcx>, } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum RelationDir { + SubtypeOf, SupertypeOf, EqTo +} + impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_tys(&self, relation: &mut R, @@ -177,6 +181,8 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { a_is_expected: bool) -> RelateResult<'tcx, ()> { + use self::RelationDir::*; + // We use SmallVector here instead of Vec because this code is hot and // it's rare that the stack length exceeds 1. let mut stack = SmallVector::new(); @@ -224,7 +230,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // Generalize type if necessary. let generalized_ty = match dir { EqTo => self.generalize(a_ty, b_vid, false), - BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), + SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), }?; debug!("instantiate(a_ty={:?}, dir={:?}, \ b_vid={:?}, generalized_ty={:?})", @@ -232,8 +238,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { generalized_ty); self.infcx.type_variables .borrow_mut() - .instantiate_and_push( - b_vid, generalized_ty, &mut stack); + .instantiate(b_vid, generalized_ty); generalized_ty } }; @@ -246,7 +251,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { - BiTo => Ok(a_ty), EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), SupertypeOf => self.sub(a_is_expected).relate_with_variance( diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index bf247acec5a2d..f620965ced845 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::CombineFields; +use super::combine::{CombineFields, RelationDir}; use super::{Subtype}; -use super::type_variable::{EqTo}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; @@ -58,17 +57,17 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id); + infcx.type_variables.borrow_mut().equate(a_id, b_id); Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 1a94f12973de8..f1de9b043e36f 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -9,8 +9,7 @@ // except according to those terms. use super::SubregionOrigin; -use super::combine::CombineFields; -use super::type_variable::{SubtypeOf, SupertypeOf}; +use super::combine::{CombineFields, RelationDir}; use traits::Obligation; use ty::{self, Ty, TyCtxt}; @@ -104,11 +103,11 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } (&ty::TyInfer(TyVar(a_id)), _) => { self.fields - .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; + .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 67f37e5f9272e..298b2a97d5f36 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::RelationDir::*; use self::TypeVariableValue::*; -use self::UndoEntry::*; use hir::def_id::{DefId}; -use syntax::util::small_vector::SmallVector; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; @@ -55,7 +52,6 @@ struct TypeVariableData<'tcx> { enum TypeVariableValue<'tcx> { Known(Ty<'tcx>), Bounded { - relations: Vec, default: Option> } } @@ -76,33 +72,13 @@ pub struct Snapshot { eq_snapshot: ut::Snapshot, } -enum UndoEntry<'tcx> { - // The type of the var was specified. - SpecifyVar(ty::TyVid, Vec, Option>), - Relate(ty::TyVid, ty::TyVid), - RelateRange(ty::TyVid, usize), +struct Instantiate<'tcx> { + vid: ty::TyVid, + default: Option>, } struct Delegate<'tcx>(PhantomData<&'tcx ()>); -type Relation = (RelationDir, ty::TyVid); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum RelationDir { - SubtypeOf, SupertypeOf, EqTo, BiTo -} - -impl RelationDir { - fn opposite(self) -> RelationDir { - match self { - SubtypeOf => SupertypeOf, - SupertypeOf => SubtypeOf, - EqTo => EqTo, - BiTo => BiTo, - } - } -} - impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { TypeVariableTable { @@ -111,10 +87,6 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { - relations(self.values.get_mut(a.index as usize)) - } - pub fn default(&self, vid: ty::TyVid) -> Option> { match &self.values.get(vid.index as usize).value { &Known(_) => None, @@ -130,68 +102,37 @@ impl<'tcx> TypeVariableTable<'tcx> { &self.values.get(vid.index as usize).origin } - /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. + /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. - pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - let a = self.root_var(a); - let b = self.root_var(b); - if a != b { - if dir == EqTo { - // a and b must be equal which we mark in the unification table - let root = self.eq_relations.union(a, b); - // In addition to being equal, all relations from the variable which is no longer - // the root must be added to the root so they are not forgotten as the other - // variable should no longer be referenced (other than to get the root) - let other = if a == root { b } else { a }; - let count = { - let (relations, root_relations) = if other.index < root.index { - let (pre, post) = self.values.split_at_mut(root.index as usize); - (relations(&mut pre[other.index as usize]), relations(&mut post[0])) - } else { - let (pre, post) = self.values.split_at_mut(other.index as usize); - (relations(&mut post[0]), relations(&mut pre[root.index as usize])) - }; - root_relations.extend_from_slice(relations); - relations.len() - }; - self.values.record(RelateRange(root, count)); - } else { - self.relations(a).push((dir, b)); - self.relations(b).push((dir.opposite(), a)); - self.values.record(Relate(a, b)); - } - } + pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.eq_relations.union(a, b); } - /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the - /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)` - /// where `vid1` is some other variable id. + /// Instantiates `vid` with the type `ty`. /// /// Precondition: `vid` must be a root in the unification table - pub fn instantiate_and_push( - &mut self, - vid: ty::TyVid, - ty: Ty<'tcx>, - stack: &mut SmallVector<(Ty<'tcx>, RelationDir, ty::TyVid)>) - { + /// and has not previously been instantiated. + pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { debug_assert!(self.root_var(vid) == vid); - let old_value = { - let value_ptr = &mut self.values.get_mut(vid.index as usize).value; - mem::replace(value_ptr, Known(ty)) - }; + debug_assert!(self.probe(vid).is_none()); - let (relations, default) = match old_value { - Bounded { relations, default } => (relations, default), - Known(_) => bug!("Asked to instantiate variable that is \ - already instantiated") + let old_value = { + let vid_data = &mut self.values[vid.index as usize]; + mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty)) }; - for &(dir, vid) in &relations { - stack.push((ty, dir, vid)); + match old_value { + TypeVariableValue::Bounded { default } => { + self.values.record(Instantiate { vid: vid, default: default }); + } + TypeVariableValue::Known(old_ty) => { + bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", + vid, ty, old_ty) + } } - - self.values.record(SpecifyVar(vid, relations, default)); } pub fn new_var(&mut self, @@ -201,7 +142,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); let index = self.values.push(TypeVariableData { - value: Bounded { relations: vec![], default: default }, + value: Bounded { default: default }, origin: origin, diverging: diverging }); @@ -298,7 +239,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(SpecifyVar(vid, ..)) => { + sv::UndoLog::Other(Instantiate { vid, .. }) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. @@ -334,35 +275,12 @@ impl<'tcx> TypeVariableTable<'tcx> { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = UndoEntry<'tcx>; - - fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { - match action { - SpecifyVar(vid, relations, default) => { - values[vid.index as usize].value = Bounded { - relations: relations, - default: default - }; - } + type Undo = Instantiate<'tcx>; - Relate(a, b) => { - relations(&mut (*values)[a.index as usize]).pop(); - relations(&mut (*values)[b.index as usize]).pop(); - } - - RelateRange(i, n) => { - let relations = relations(&mut (*values)[i.index as usize]); - for _ in 0..n { - relations.pop(); - } - } - } - } -} - -fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { - match v.value { - Known(_) => bug!("var_sub_var: variable is known"), - Bounded { ref mut relations, .. } => relations + fn reverse(values: &mut Vec>, action: Instantiate<'tcx>) { + let Instantiate { vid, default } = action; + values[vid.index as usize].value = Bounded { + default: default + }; } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b002fd4dfc1a..9176a4c01575f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -32,6 +32,7 @@ #![feature(i128_type)] #![feature(libc)] #![feature(loop_break_value)] +#![feature(never_type)] #![feature(nonzero)] #![cfg_attr(stage0, feature(pub_restricted))] #![feature(quote)] diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index 662b9e894ba3a..2551ed0208af3 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let v = &[]; - //~^ NOTE consider giving `it` a type - let it = v.iter(); //~ ERROR cannot infer type for `_` + let v = &[]; //~ NOTE consider giving `v` a type + let it = v.iter(); //~ ERROR type annotations needed + //~^ NOTE cannot infer type for `_` } From e4b762b532f037d07be282d413c7a864e182b3fc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Mar 2017 09:58:21 -0400 Subject: [PATCH 637/662] add regression test for #30225 Fixes #30225 --- src/test/compile-fail/issue-30225.rs | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/test/compile-fail/issue-30225.rs diff --git a/src/test/compile-fail/issue-30225.rs b/src/test/compile-fail/issue-30225.rs new file mode 100644 index 0000000000000..7acbbfb8826df --- /dev/null +++ b/src/test/compile-fail/issue-30225.rs @@ -0,0 +1,48 @@ +// 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. + +// Regression test for #30225, which was an ICE that would trigger as +// a result of a poor interaction between trait result caching and +// type inference. Specifically, at that time, unification could cause +// unrelated type variables to become instantiated, if subtyping +// relationships existed. These relationships are now propagated +// through obligations and hence everything works out fine. + +trait Foo : Sized { + fn foo(self, u: Option, v: Option) {} +} + +struct A; +struct B; + +impl Foo for () {} // impl A +impl Foo for u32 {} // impl B, creating ambiguity + +fn toxic() { + // cache the resolution <() as Foo<$0,$1>> = impl A + let u = None; + let v = None; + Foo::foo((), u, v); +} + +fn bomb() { + let mut u = None; // type is Option<$0> + let mut v = None; // type is Option<$1> + let mut x = None; // type is Option<$2> + + Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>> + u = v; // mark $0 and $1 in a subtype relationship + //~^ ERROR mismatched types + x = Some(()); // set $2 = (), allowing impl selection + // to proceed for <() as Foo<$0, $1>> = impl A. + // kaboom, this *used* to trigge an ICE +} + +fn main() {} From d1033d06bae530881415bda6972c5c8a16d07ade Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 3 Apr 2017 15:59:34 -0400 Subject: [PATCH 638/662] add FIXME to #18653 --- src/librustc/infer/combine.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 825f279e78e4b..a23589e7f3f79 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -224,6 +224,9 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // Check whether `vid` has been instantiated yet. If not, // make a generalized form of `ty` and instantiate with // that. + // + // FIXME(#18653) -- we need to generalize nested type + // variables too. let b_ty = match b_ty { Some(t) => t, // ...already instantiated. None => { // ...not yet instantiated: From 77d9e38e9499df1dac393937d62d3bf626c51abb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 3 Apr 2017 16:14:05 -0400 Subject: [PATCH 639/662] add FIXME for bivariant lub/glb --- src/librustc/infer/glb.rs | 1 + src/librustc/infer/lub.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8c167e0a8ac91..a6dd18c113f1a 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -49,6 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 28ae1ae556b0b..d7e5c92b6e17b 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -49,6 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } From 14f1e3459f02e3ce45232a84cd923c86eef55cb5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 16:58:04 -0400 Subject: [PATCH 640/662] fix a bug in compiletest JSON parsing for duplicate errors In some cases, we give multiple primary spans, in which case we would report one `//~` annotation per primary span. That was very confusing because these things are reported to the user as a single error. UI tests would be better here. --- src/test/compile-fail/binop-move-semantics.rs | 2 -- src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs | 1 - .../compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs | 1 - src/test/compile-fail/issue-25579.rs | 1 - src/test/compile-fail/issue-38412.rs | 1 - src/test/compile-fail/lint-unused-imports.rs | 1 - src/tools/compiletest/src/json.rs | 1 + 7 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs index 0cc6ea3e984d9..cff0064497aff 100644 --- a/src/test/compile-fail/binop-move-semantics.rs +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -62,7 +62,6 @@ fn mut_plus_immut() { &mut f + &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable - //~^ cannot borrow `f` as immutable because it is also borrowed as mutable } fn immut_plus_mut() { @@ -71,7 +70,6 @@ fn immut_plus_mut() { &f + &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable - //~^ cannot borrow `f` as mutable because it is also borrowed as immutable } fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs index 56cbe0b187867..f09e7ffd7e4b7 100644 --- a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs @@ -109,7 +109,6 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { borrow(&*v); //~ ERROR cannot borrow if cond2 { x = &mut v; //~ ERROR cannot borrow - //~^ ERROR cannot borrow } } } diff --git a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs index f789d44016eb1..38e0e27a7b98e 100644 --- a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs +++ b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -19,7 +19,6 @@ fn main() { match 1 { 1 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time - //~| ERROR cannot borrow `x` as mutable more than once at a time 2 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time _ => { addr = &mut x; } diff --git a/src/test/compile-fail/issue-25579.rs b/src/test/compile-fail/issue-25579.rs index 849c9aa18c905..323ce3b0adf33 100644 --- a/src/test/compile-fail/issue-25579.rs +++ b/src/test/compile-fail/issue-25579.rs @@ -17,7 +17,6 @@ fn causes_ice(mut l: &mut Sexpression) { loop { match l { &mut Sexpression::Num(ref mut n) => {}, &mut Sexpression::Cons(ref mut expr) => { //~ ERROR cannot borrow `l.0` - //~| ERROR cannot borrow `l.0` l = &mut **expr; //~ ERROR cannot assign to `l` } }} diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index 3b62aaf2ab8e9..b4feadbacf740 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -11,7 +11,6 @@ fn main() { let Box(a) = loop { }; //~^ ERROR expected tuple struct/variant, found struct `Box` - //~| ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index f6f7c210f466a..5bb2ab75c53fd 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -21,7 +21,6 @@ use std::fmt::{}; // Should get errors for both 'Some' and 'None' use std::option::Option::{Some, None}; //~^ ERROR unused imports: `None`, `Some` -//~| ERROR unused imports: `None`, `Some` use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index d9da1bdc34858..06cbd9a3df416 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -97,6 +97,7 @@ fn push_expected_errors(expected_errors: &mut Vec, let primary_spans: Vec<_> = spans_in_this_file.iter() .cloned() .filter(|span| span.is_primary) + .take(1) // sometimes we have more than one showing up in the json; pick first .collect(); let primary_spans = if primary_spans.is_empty() { // subdiagnostics often don't have a span of their own; From 3a5bbf89b2229c629c6f01bdd87354cba136d133 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:16:57 -0400 Subject: [PATCH 641/662] avoid unneeded subtype obligations in lub/glb In some specific cases, the new scheme was failing to learn as much from a LUB/GLB operaiton as the old code, which caused coercion to go awry. A slight ordering hack fixes this. --- src/librustc/infer/lattice.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index f7b26a918b3a2..d4d090f0153d0 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -44,6 +44,10 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. + // + // Subtle hack: ordering *may* be significant here. This method + // relates `v` to `a` first, which may help us to avoid unecessary + // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } @@ -74,7 +78,29 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, Ok(v) } - (&ty::TyInfer(TyVar(..)), _) | + // If one side is known to be a variable and one is not, + // create a variable (`v`) to represent the LUB. Make sure to + // relate `v` to the non-type-variable first (by passing it + // first to `relate_bound`). Otherwise, we would produce a + // subtype obligation that must then be processed. + // + // Example: if the LHS is a type variable, and RHS is + // `Box`, then we current compare `v` to the RHS first, + // which will instantiate `v` with `Box`. Then when `v` + // is compared to the LHS, we instantiate LHS with `Box`. + // But if we did in reverse order, we would create a `v <: + // LHS` (or vice versa) constraint and then instantiate + // `v`. This would require further processing to achieve same + // end-result; in partiular, this screws up some of the logic + // in coercion, which expects LUB to figure out that the LHS + // is (e.g.) `Box`. A more obvious solution might be to + // iterate on the subtype obligations that are returned, but I + // think this suffices. -nmatsakis + (&ty::TyInfer(TyVar(..)), _) => { + let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); + this.relate_bound(v, b, a)?; + Ok(v) + } (_, &ty::TyInfer(TyVar(..))) => { let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; From bca56e82a1bbd775498257cc080f5ea27b214f49 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:17:58 -0400 Subject: [PATCH 642/662] generalize type variables too When we are generalizing a super/sub-type, we have to replace type variables with a fresh variable (and not just region variables). So if we know that `Box <: ?U`, for example, we instantiate `?U` with `Box` and then relate `Box` to `Box` (and hence require that `?T <: ?V`). This change has some complex interactions, however: First, the occurs check must be updated to detect constraints like `?T <: ?U` and `?U <: Box`. If we're not careful, we'll create a never-ending sequence of new variables. To address this, we add a second unification set into `type_variables` that tracks type variables related through **either** equality **or** subtyping, and use that during the occurs-check. Second, the "fudge regions if ok" code was expecting no new type variables to be created. It must be updated to create new type variables outside of the probe. This is relatively straight-forward under the new scheme, since type variables are now independent from one another, and any relations are moderated by pending subtype obliations and so forth. This part would be tricky to backport though. cc #18653 cc #40951 --- src/librustc/infer/combine.rs | 46 +++++--- src/librustc/infer/fudge.rs | 75 ++++++++---- src/librustc/infer/mod.rs | 6 +- src/librustc/infer/sub.rs | 8 +- src/librustc/infer/type_variable.rs | 108 +++++++++++++++++- src/librustc/traits/error_reporting.rs | 24 +++- src/test/run-pass/issue-40951.rs | 20 ++++ .../run-pass/type-infer-generalize-ty-var.rs | 60 ++++++++++ 8 files changed, 297 insertions(+), 50 deletions(-) create mode 100644 src/test/run-pass/issue-40951.rs create mode 100644 src/test/run-pass/type-infer-generalize-ty-var.rs diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index a23589e7f3f79..03ed654e3cce4 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -264,20 +264,27 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that - /// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also - /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok` - /// otherwise. + /// Attempts to generalize `ty` for the type variable `for_vid`. + /// This checks for cycle -- that is, whether the type `ty` + /// references `for_vid`. If `make_region_vars` is true, it will + /// also replace all regions with fresh variables. Returns + /// `TyError` in the case of a cycle, `Ok` otherwise. + /// + /// Preconditions: + /// + /// - `for_vid` is a "root vid" fn generalize(&self, ty: Ty<'tcx>, for_vid: ty::TyVid, make_region_vars: bool) -> RelateResult<'tcx, Ty<'tcx>> { + debug_assert!(self.infcx.type_variables.borrow_mut().root_var(for_vid) == for_vid); + let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, - for_vid: for_vid, + for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), make_region_vars: make_region_vars, cycle_detected: false }; @@ -293,7 +300,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, span: Span, - for_vid: ty::TyVid, + for_vid_sub_root: ty::TyVid, make_region_vars: bool, cycle_detected: bool, } @@ -305,17 +312,17 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { // Check to see whether the type we are genealizing references - // `vid`. At the same time, also update any type variables to - // the values that they are bound to. This is needed to truly - // check for cycles, but also just makes things readable. - // - // (In particular, you could have something like `$0 = Box<$1>` - // where `$1` has already been instantiated with `Box<$0>`) + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. match t.sty { ty::TyInfer(ty::TyVar(vid)) => { let mut variables = self.infcx.type_variables.borrow_mut(); let vid = variables.root_var(vid); - if vid == self.for_vid { + let sub_vid = variables.sub_root_var(vid); + if sub_vid == self.for_vid_sub_root { + // If sub-roots are equal, then `for_vid` and + // `vid` are related via subtyping. self.cycle_detected = true; self.tcx().types.err } else { @@ -324,7 +331,18 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx drop(variables); self.fold_ty(u) } - None => t, + None => { + if self.make_region_vars { + let origin = variables.origin(vid); + let new_var_id = variables.new_var(false, origin, None); + let u = self.tcx().mk_var(new_var_id); + debug!("generalize: replacing original vid={:?} with new={:?}", + vid, u); + u + } else { + t + } + } } } } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 806b94486615f..ab0ff32dcc3ec 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::{self, TyCtxt}; +use infer::type_variable::TypeVariableMap; +use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use super::InferCtxt; @@ -54,57 +55,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// the actual types (`?T`, `Option(&self, origin: &RegionVariableOrigin, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - let (region_vars, value) = self.probe(|snapshot| { - let vars_at_start = self.type_variables.borrow().num_vars(); + debug!("fudge_regions_if_ok(origin={:?})", origin); + let (type_variables, region_vars, value) = self.probe(|snapshot| { match f() { Ok(value) => { let value = self.resolve_type_vars_if_possible(&value); // At this point, `value` could in principle refer - // to regions that have been created during the - // snapshot (we assert below that `f()` does not - // create any new type variables, so there - // shouldn't be any of those). Once we exit - // `probe()`, those are going to be popped, so we - // will have to eliminate any references to them. - - assert_eq!(self.type_variables.borrow().num_vars(), vars_at_start, - "type variables were created during fudge_regions_if_ok"); + // to types/regions that have been created during + // the snapshot. Once we exit `probe()`, those are + // going to be popped, so we will have to + // eliminate any references to them. + + let type_variables = + self.type_variables.borrow_mut().types_created_since_snapshot( + &snapshot.type_snapshot); let region_vars = self.region_vars.vars_created_since_snapshot( &snapshot.region_vars_snapshot); - Ok((region_vars, value)) + Ok((type_variables, region_vars, value)) } Err(e) => Err(e), } })?; // At this point, we need to replace any of the now-popped - // region variables that appear in `value` with a fresh region - // variable. We can't do this during the probe because they - // would just get popped then too. =) + // type/region variables that appear in `value` with a fresh + // variable of the appropriate kind. We can't do this during + // the probe because they would just get popped then too. =) // Micro-optimization: if no variables have been created, then // `value` can't refer to any of them. =) So we can just return it. - if region_vars.is_empty() { + if type_variables.is_empty() && region_vars.is_empty() { return Ok(value); } let mut fudger = RegionFudger { infcx: self, + type_variables: &type_variables, region_vars: ®ion_vars, origin: origin }; @@ -115,6 +111,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + type_variables: &'a TypeVariableMap, region_vars: &'a Vec, origin: &'a RegionVariableOrigin, } @@ -124,6 +121,40 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { self.infcx.tcx } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::TyInfer(ty::InferTy::TyVar(vid)) => { + match self.type_variables.get(&vid) { + None => { + // This variable was created before the + // "fudging". Since we refresh all type + // variables to their binding anyhow, we know + // that it is unbound, so we can just return + // it. + debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_none()); + ty + } + + Some(info) => { + // This variable was created during the + // fudging; it was mapped the root + // `root_vid`. There are now two + // possibilities: either the root was creating + // during the fudging too, in which case we + // want a fresh variable, or it was not, in + // which case we can return it. + if self.type_variables.contains_key(&info.root_vid) { + self.infcx.next_ty_var(info.root_origin) + } else { + self.infcx.tcx.mk_var(info.root_vid) + } + } + } + } + _ => ty.super_fold_with(self), + } + } + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match *r { ty::ReVar(v) if self.region_vars.contains(&v) => { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 999ebbfa20fbf..e98792b120de2 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1036,9 +1036,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. }) }) } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index f1de9b043e36f..2a7dbbc026bc0 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -80,7 +80,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(_)), &ty::TyInfer(TyVar(_))) => { + (&ty::TyInfer(TyVar(a_vid)), &ty::TyInfer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental // capture. @@ -88,7 +88,11 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> assert!(!b.has_escaping_regions()); // can't make progress on `A <: B` if both A and B are - // type variables, so record an obligation. + // type variables, so record an obligation. We also + // have to record in the `type_variables` tracker that + // the two variables are equal modulo subtyping, which + // is important to the occurs check later on. + infcx.type_variables.borrow_mut().sub(a_vid, b_vid); self.fields.obligations.push( Obligation::new( self.fields.trace.cause.clone(), diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 298b2a97d5f36..a32404c1ac515 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -18,16 +18,39 @@ use std::cmp::min; use std::marker::PhantomData; use std::mem; use std::u32; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; pub struct TypeVariableTable<'tcx> { values: sv::SnapshotVec>, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X == ?Y`. eq_relations: ut::UnificationTable, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second + /// table exists only to help with the occurs check. In particular, + /// we want to report constraints like these as an occurs check + /// violation: + /// + /// ?1 <: ?3 + /// Box <: ?1 + /// + /// This works because `?1` and `?3` are unified in the + /// `sub_relations` relation (not in `eq_relations`). Then when we + /// process the `Box <: ?1` constraint, we do an occurs check + /// on `Box` and find a potential cycle. + /// + /// This is reasonable because, in Rust, subtypes have the same + /// "skeleton" and hence there is no possible type such that + /// (e.g.) `Box <: ?3` for any `?3`. + sub_relations: ut::UnificationTable, } /// Reasons to create a type inference variable -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), @@ -41,6 +64,14 @@ pub enum TypeVariableOrigin { DivergingBlockExpr(Span), DivergingFn(Span), LatticeVariable(Span), + Generalized(ty::TyVid), +} + +pub type TypeVariableMap = FxHashMap; + +pub struct TypeVariableInfo { + pub root_vid: ty::TyVid, + pub root_origin: TypeVariableOrigin, } struct TypeVariableData<'tcx> { @@ -70,6 +101,7 @@ pub struct Default<'tcx> { pub struct Snapshot { snapshot: sv::Snapshot, eq_snapshot: ut::Snapshot, + sub_snapshot: ut::Snapshot, } struct Instantiate<'tcx> { @@ -84,6 +116,7 @@ impl<'tcx> TypeVariableTable<'tcx> { TypeVariableTable { values: sv::SnapshotVec::new(), eq_relations: ut::UnificationTable::new(), + sub_relations: ut::UnificationTable::new(), } } @@ -109,6 +142,16 @@ impl<'tcx> TypeVariableTable<'tcx> { debug_assert!(self.probe(a).is_none()); debug_assert!(self.probe(b).is_none()); self.eq_relations.union(a, b); + self.sub_relations.union(a, b); + } + + /// Records that `a <: b`, depending on `dir`. + /// + /// Precondition: neither `a` nor `b` are known. + pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.sub_relations.union(a, b); } /// Instantiates `vid` with the type `ty`. @@ -141,6 +184,7 @@ impl<'tcx> TypeVariableTable<'tcx> { default: Option>,) -> ty::TyVid { debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); + self.sub_relations.new_key(()); let index = self.values.push(TypeVariableData { value: Bounded { default: default }, origin: origin, @@ -155,15 +199,41 @@ impl<'tcx> TypeVariableTable<'tcx> { self.values.len() } + /// Returns the "root" variable of `vid` in the `eq_relations` + /// equivalence table. All type variables that have been equated + /// will yield the same root variable (per the union-find + /// algorithm), so `root_var(a) == root_var(b)` implies that `a == + /// b` (transitively). pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations.find(vid) } + /// Returns the "root" variable of `vid` in the `sub_relations` + /// equivalence table. All type variables that have been are + /// related via equality or subtyping will yield the same root + /// variable (per the union-find algorithm), so `sub_root_var(a) + /// == sub_root_var(b)` implies that: + /// + /// exists X. (a <: X || X <: a) && (b <: X || X <: b) + pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + self.sub_relations.find(vid) + } + + /// True if `a` and `b` have same "sub-root" (i.e., exists some + /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. + pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { + self.sub_root_var(a) == self.sub_root_var(b) + } + pub fn probe(&mut self, vid: ty::TyVid) -> Option> { let vid = self.root_var(vid); self.probe_root(vid) } + pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + self.values.get(vid.index as usize).origin.clone() + } + /// Retrieves the type of `vid` given that it is currently a root in the unification table pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { debug_assert!(self.root_var(vid) == vid); @@ -189,6 +259,7 @@ impl<'tcx> TypeVariableTable<'tcx> { Snapshot { snapshot: self.values.start_snapshot(), eq_snapshot: self.eq_relations.snapshot(), + sub_snapshot: self.sub_relations.snapshot(), } } @@ -204,13 +275,40 @@ impl<'tcx> TypeVariableTable<'tcx> { } }); - self.values.rollback_to(s.snapshot); - self.eq_relations.rollback_to(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.rollback_to(snapshot); + self.eq_relations.rollback_to(eq_snapshot); + self.sub_relations.rollback_to(sub_snapshot); } pub fn commit(&mut self, s: Snapshot) { - self.values.commit(s.snapshot); - self.eq_relations.commit(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.commit(snapshot); + self.eq_relations.commit(eq_snapshot); + self.sub_relations.commit(sub_snapshot); + } + + /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are + /// ty-variables created during the snapshot, and the values + /// `{V2}` are the root variables that they were unified with, + /// along with their origin. + pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + let eq_relations = &mut self.eq_relations; + let values = &self.values; + + actions_since_snapshot + .iter() + .filter_map(|action| match action { + &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }), + _ => None, + }) + .map(|vid| { + let root_vid = eq_relations.find(vid); + let root_origin = values.get(vid.index as usize).origin.clone(); + (vid, TypeVariableInfo { root_vid, root_origin }) + }) + .collect() } pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec> { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8a303a5da1184..f7a7d0e2071f2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -69,6 +69,19 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { found_pattern: Option<&'a Pat>, } +impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn is_match(&self, ty: Ty<'tcx>) -> bool { + ty == *self.target_ty || match (&ty.sty, &self.target_ty.sty) { + (&ty::TyInfer(ty::TyVar(a_vid)), &ty::TyInfer(ty::TyVar(b_vid))) => + self.infcx.type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid), + + _ => false, + } + } +} + impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { NestedVisitorMap::None @@ -77,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn visit_local(&mut self, local: &'a Local) { if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) { let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let is_match = ty.walk().any(|t| t == *self.target_ty); + let is_match = ty.walk().any(|t| self.is_match(t)); if is_match && self.found_pattern.is_none() { self.found_pattern = Some(&*local.pat); @@ -564,8 +577,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ty::Predicate::Subtype(ref predicate) => { - // TODO - panic!("subtype requirement not satisfied {:?}", predicate) + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) } ty::Predicate::Equate(ref predicate) => { @@ -779,7 +794,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // no need to overload user in such cases } else { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); - assert!(a.is_ty_var() && b.is_ty_var()); // else other would've been instantiated + // both must be type variables, or the other would've been instantiated + assert!(a.is_ty_var() && b.is_ty_var()); self.need_type_info(obligation, a); } } diff --git a/src/test/run-pass/issue-40951.rs b/src/test/run-pass/issue-40951.rs new file mode 100644 index 0000000000000..adc7101b16aa1 --- /dev/null +++ b/src/test/run-pass/issue-40951.rs @@ -0,0 +1,20 @@ +// 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. + +// Regression test for #40951. + +const FOO: [&'static str; 1] = ["foo"]; + +fn find(t: &[T], element: &T) { } + +fn main() { + let x = format!("hi"); + find(&FOO, &&*x); +} diff --git a/src/test/run-pass/type-infer-generalize-ty-var.rs b/src/test/run-pass/type-infer-generalize-ty-var.rs new file mode 100644 index 0000000000000..d7fb85ca4842e --- /dev/null +++ b/src/test/run-pass/type-infer-generalize-ty-var.rs @@ -0,0 +1,60 @@ +// 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. + +// Test a scenario where we generate a constraint like `?1 <: &?2`. +// In such a case, it is important that we instantiate `?1` with `&?3` +// where `?3 <: ?2`, and not with `&?2`. This is a regression test for +// #18653. The important thing is that we build. + +use std::cell::RefCell; + +enum Wrap { + WrapSome(A), + WrapNone +} + +use Wrap::*; + +struct T; +struct U; + +trait Get { + fn get(&self) -> &T; +} + +impl Get for Wrap { + fn get(&self) -> &(MyShow + 'static) { + static x: usize = 42; + &x + } +} + +impl Get for Wrap { + fn get(&self) -> &usize { + static x: usize = 55; + &x + } +} + +trait MyShow { fn dummy(&self) { } } +impl<'a> MyShow for &'a (MyShow + 'a) { } +impl MyShow for usize { } +fn constrain<'a>(rc: RefCell<&'a (MyShow + 'a)>) { } + +fn main() { + let mut collection: Wrap<_> = WrapNone; + + { + let __arg0 = Get::get(&collection); + let __args_cell = RefCell::new(__arg0); + constrain(__args_cell); + } + collection = WrapSome(T); +} From 1c138ed1c79cfac39c47cc4119a464f9b638a9c6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:10:26 -0400 Subject: [PATCH 643/662] update various test cases that generate slightly different output For the most part, it seems to be better, but one side-effect is that I cannot seem to reproduce E0102 anymore. --- src/librustc_typeck/diagnostics.rs | 2 +- src/test/compile-fail/E0102.rs | 5 +++-- src/test/compile-fail/destructure-trait-ref.rs | 2 +- src/test/compile-fail/issue-12187-1.rs | 1 + src/test/compile-fail/issue-12187-2.rs | 1 + src/test/compile-fail/issue-7813.rs | 7 ++++--- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index fb951fd20e564..2d72052f1e5ad 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1378,7 +1378,7 @@ E0102: r##" You hit this error because the compiler lacks the information to determine the type of this variable. Erroneous code example: -```compile_fail,E0102 +```compile_fail,E0282 // could be an array of anything let x = []; // error: cannot determine a type for this local variable ``` diff --git a/src/test/compile-fail/E0102.rs b/src/test/compile-fail/E0102.rs index 1d64798bb8382..6a17ddebd1dc1 100644 --- a/src/test/compile-fail/E0102.rs +++ b/src/test/compile-fail/E0102.rs @@ -10,6 +10,7 @@ fn main() { let x = []; - //~^ ERROR E0102 - //~| NOTE cannot resolve type of variable + //~^ ERROR type annotations needed + //~| NOTE consider giving `x` a type + //~| NOTE cannot infer type for `_` } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 835ec8e4a5e7e..09bd3a2fc57d9 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -35,7 +35,7 @@ fn main() { // n == m let &x = &1isize as &T; //~ ERROR type `&T` cannot be dereferenced let &&x = &(&1isize as &T); //~ ERROR type `&T` cannot be dereferenced - let box x = box 1isize as Box; //~ ERROR `T: std::marker::Sized` is not satisfied + let box x = box 1isize as Box; //~ ERROR type `std::boxed::Box` cannot be dereferenced // n > m let &&x = &1isize as &T; diff --git a/src/test/compile-fail/issue-12187-1.rs b/src/test/compile-fail/issue-12187-1.rs index 346fae11070e1..6aeb9442c40ed 100644 --- a/src/test/compile-fail/issue-12187-1.rs +++ b/src/test/compile-fail/issue-12187-1.rs @@ -16,4 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` + //~| NOTE consider giving a type to pattern } diff --git a/src/test/compile-fail/issue-12187-2.rs b/src/test/compile-fail/issue-12187-2.rs index 848174d6fe1e0..d52ed06c4085d 100644 --- a/src/test/compile-fail/issue-12187-2.rs +++ b/src/test/compile-fail/issue-12187-2.rs @@ -16,4 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` + //~| NOTE consider giving a type to pattern } diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index 2551ed0208af3..a5f001b785cc9 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -9,7 +9,8 @@ // except according to those terms. fn main() { - let v = &[]; //~ NOTE consider giving `v` a type - let it = v.iter(); //~ ERROR type annotations needed - //~^ NOTE cannot infer type for `_` + let v = &[]; //~ ERROR type annotations needed + //~| NOTE consider giving `v` a type + //~| NOTE cannot infer type for `_` + let it = v.iter(); } From 761808ef40b1e2cc9b35f0891a66d2dcf3274834 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:11:05 -0400 Subject: [PATCH 644/662] just panic in rustdoc if we encounter a subtype predicate These are not user expressible anyhow. --- src/librustdoc/clean/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a194cd125462..fb8ba51853fe8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -838,7 +838,7 @@ impl Clean> for ty::Region { pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec}, - EqPredicate { lhs: Type, rhs: Type } + EqPredicate { lhs: Type, rhs: Type }, } impl Clean for hir::WherePredicate { @@ -906,12 +906,9 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { - fn clean(&self, cx: &DocContext) -> WherePredicate { - let ty::SubtypePredicate { a_is_expected: _, a, b } = *self; - WherePredicate::EqPredicate { // TODO This is obviously wrong :P - lhs: a.clean(cx), - rhs: b.clean(cx) - } + fn clean(&self, _cx: &DocContext) -> WherePredicate { + panic!("subtype predicates are an internal rustc artifact \ + and should not be seen by rustdoc") } } From 59babd80bde4ce2f96768e44047ba0e44afc8eac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:11:22 -0400 Subject: [PATCH 645/662] add some comments and `debug!` calls to "obligation forest" --- .../obligation_forest/mod.rs | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index a46238309bb46..3515e5c5ede35 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -43,7 +43,16 @@ pub trait ObligationProcessor { obligation: &mut Self::Obligation) -> Result>, Self::Error>; - fn process_backedge<'c, I>(&mut self, cycle: I, + /// As we do the cycle check, we invoke this callback when we + /// encounter an actual cycle. `cycle` is an iterator that starts + /// at the start of the cycle in the stack and walks **toward the + /// top**. + /// + /// In other words, if we had O1 which required O2 which required + /// O3 which required O1, we would give an iterator yielding O1, + /// O2, O3 (O1 is not yielded twice). + fn process_backedge<'c, I>(&mut self, + cycle: I, _marker: PhantomData<&'c Self::Obligation>) where I: Clone + Iterator; } @@ -239,8 +248,8 @@ impl ObligationForest { } } Entry::Vacant(v) => { - debug!("register_obligation_at({:?}, {:?}) - ok", - obligation, parent); + debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}", + obligation, parent, self.nodes.len()); v.insert(NodeIndex::new(self.nodes.len())); self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); @@ -376,6 +385,9 @@ impl ObligationForest { where P: ObligationProcessor { let mut stack = self.scratch.take().unwrap(); + debug_assert!(stack.is_empty()); + + debug!("process_cycles()"); for index in 0..self.nodes.len() { // For rustc-benchmarks/inflate-0.1.0 this state test is extremely @@ -389,6 +401,9 @@ impl ObligationForest { } } + debug!("process_cycles: complete"); + + debug_assert!(stack.is_empty()); self.scratch = Some(stack); } @@ -402,21 +417,6 @@ impl ObligationForest { NodeState::OnDfsStack => { let index = stack.iter().rposition(|n| *n == index).unwrap(); - // I need a Clone closure - #[derive(Clone)] - struct GetObligation<'a, O: 'a>(&'a [Node]); - impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { - type Output = &'a O; - extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { - extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)), PhantomData); } @@ -645,3 +645,20 @@ impl Node { } } } + +// I need a Clone closure +#[derive(Clone)] +struct GetObligation<'a, O: 'a>(&'a [Node]); + +impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { + type Output = &'a O; + extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} + +impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { + extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} From 0fae3324a2f58e921e2094a6971962c0b09c04ee Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:11:41 -0400 Subject: [PATCH 646/662] add some debug! to coercion --- src/librustc_typeck/check/coercion.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a5acd0c7e5300..2033eaf886166 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -195,8 +195,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Consider coercing the subtype to a DST let unsize = self.coerce_unsized(a, b); if unsize.is_ok() { + debug!("coerce: unsize successful"); return unsize; } + debug!("coerce: unsize failed"); // Examine the supertype and consider auto-borrowing. // @@ -745,7 +747,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); - debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); // Special-ish case: we can coerce any type `T` into the `!` // type, but only if the source expression diverges. From 7832db8031a9051d377e1da92bbcd56e366354c1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:12:00 -0400 Subject: [PATCH 647/662] fix long line --- src/librustc/traits/structural_impls.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index fcaa29be9632c..9d0b1035ade49 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,7 +130,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeSubtypeError(ref a, ref b) => write!(f, "CodeSubtypeError({:?}, {:?})", a, b), + super::CodeSubtypeError(ref a, ref b) => + write!(f, "CodeSubtypeError({:?}, {:?})", a, b), super::CodeAmbiguity => write!(f, "Ambiguity") } } From ed7b6c3724be948bc04aaf3ed4311c877bde6dd3 Mon Sep 17 00:00:00 2001 From: projektir Date: Wed, 12 Apr 2017 00:10:36 -0400 Subject: [PATCH 648/662] Minor nits in primitive str --- src/libcollections/str.rs | 37 +++++++++++++++++++++++------------- src/libstd/primitive_docs.rs | 8 ++++---- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b5572..f85336b8afbf4 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -318,8 +318,10 @@ impl str { /// Returns a subslice of `str`. /// - /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever - /// equivalent indexing operation would panic. + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None /// /// # Examples /// @@ -339,8 +341,10 @@ impl str { /// Returns a mutable subslice of `str`. /// - /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever - /// equivalent indexing operation would panic. + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None /// /// # Examples /// @@ -563,7 +567,7 @@ impl str { core_str::StrExt::split_at_mut(self, mid) } - /// Returns an iterator over the `char`s of a string slice. + /// Returns an iterator over the [`char`]s of a string slice. /// /// As a string slice consists of valid UTF-8, we can iterate through a /// string slice by [`char`]. This method returns such an iterator. @@ -1650,13 +1654,13 @@ impl str { /// Parses this string slice into another type. /// - /// Because `parse()` is so general, it can cause problems with type - /// inference. As such, `parse()` is one of the few times you'll see + /// Because `parse` is so general, it can cause problems with type + /// inference. As such, `parse` is one of the few times you'll see /// the syntax affectionately known as the 'turbofish': `::<>`. This /// helps the inference algorithm understand specifically which type /// you're trying to parse into. /// - /// `parse()` can parse any type that implements the [`FromStr`] trait. + /// `parse` can parse any type that implements the [`FromStr`] trait. /// /// [`FromStr`]: str/trait.FromStr.html /// @@ -1739,7 +1743,7 @@ impl str { /// /// `replacen` creates a new [`String`], and copies the data from this string slice into it. /// While doing so, it attempts to find matches of a pattern. If it finds any, it - /// replaces them with the replacement string slice at most `N` times. + /// replaces them with the replacement string slice at most `count` times. /// /// [`String`]: string/struct.String.html /// @@ -1885,7 +1889,9 @@ impl str { return s; } - /// Escapes each char in `s` with `char::escape_debug`. + /// Escapes each char in `s` with [`char::escape_debug`]. + /// + /// [`char::escape_debug`]: primitive.char.html#method.escape_debug #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1893,7 +1899,9 @@ impl str { self.chars().flat_map(|c| c.escape_debug()).collect() } - /// Escapes each char in `s` with `char::escape_default`. + /// Escapes each char in `s` with [`char::escape_default`]. + /// + /// [`char::escape_default`]: primitive.char.html#method.escape_default #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1901,7 +1909,9 @@ impl str { self.chars().flat_map(|c| c.escape_default()).collect() } - /// Escapes each char in `s` with `char::escape_unicode`. + /// Escapes each char in `s` with [`char::escape_unicode`]. + /// + /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1909,9 +1919,10 @@ impl str { self.chars().flat_map(|c| c.escape_unicode()).collect() } - /// Converts a `Box` into a [`String`] without copying or allocating. + /// Converts a [`Box`] into a [`String`] without copying or allocating. /// /// [`String`]: string/struct.String.html + /// [`Box`]: boxed/struct.Box.html /// /// # Examples /// diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5b2053e929a10..8ae987557dd0f 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -406,7 +406,7 @@ mod prim_slice { } /// /// This documentation describes a number of methods and trait implementations /// on the `str` type. For technical reasons, there is additional, separate -/// documentation in [the `std::str` module](str/index.html) as well. +/// documentation in the [`std::str`](str/index.html) module as well. /// /// # Examples /// @@ -425,7 +425,7 @@ mod prim_slice { } /// # Representation /// /// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`.as_ptr`] and [`len`] methods: +/// length. You can look at these with the [`as_ptr`] and [`len`] methods: /// /// ``` /// use std::slice; @@ -452,11 +452,11 @@ mod prim_slice { } /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`.as_ptr`]: #method.as_ptr +/// [`as_ptr`]: #method.as_ptr /// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `.as_slice()` +/// used to get a string slice under normal circumstances. Use `as_slice` /// instead. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str { } From 13c818fa27e4dd3994881fb2f45c2dea3d23363d Mon Sep 17 00:00:00 2001 From: projektir Date: Tue, 11 Apr 2017 22:29:42 -0400 Subject: [PATCH 649/662] Updating docs for std::sync::Weak #29377 --- src/liballoc/arc.rs | 66 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 28f6d97756f2c..182a107e3f769 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -165,18 +165,29 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} -/// A weak version of [`Arc`][arc]. +/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. /// -/// `Weak` pointers do not count towards determining if the inner value -/// should be dropped. +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. /// -/// The typical way to obtain a `Weak` pointer is to call -/// [`Arc::downgrade`][downgrade]. +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Arc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Arc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. /// -/// See the [`Arc`][arc] documentation for more details. +/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. /// -/// [arc]: struct.Arc.html -/// [downgrade]: struct.Arc.html#method.downgrade +/// [`Arc`]: struct.Arc.html +/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -766,14 +777,11 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { } impl Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. - /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -798,13 +806,13 @@ impl Weak { } impl Weak { - /// Upgrades the `Weak` pointer to an [`Arc`][arc], if possible. + /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending + /// the lifetime of the value if successful. /// - /// Returns [`None`][option] if the strong count has reached zero and the - /// inner value was destroyed. + /// Returns [`None`] if the value has since been dropped. /// - /// [arc]: struct.Arc.html - /// [option]: ../../std/option/enum.Option.html + /// [`Arc`]: struct.Arc.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -865,10 +873,7 @@ impl Weak { #[stable(feature = "arc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// weak reference count. + /// Makes a clone of the `Weak` pointer that points to the same value. /// /// # Examples /// @@ -900,14 +905,11 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -926,8 +928,6 @@ impl Default for Weak { impl Drop for Weak { /// Drops the `Weak` pointer. /// - /// This will decrement the weak reference count. - /// /// # Examples /// /// ``` From f39145169f24cc6dd4c17f5529fc02169d8fea0d Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Mon, 10 Apr 2017 20:53:20 +0800 Subject: [PATCH 650/662] COPYRIGHT: remove hoedown license Hoedown was removed in b96fef8411f Also cleanup src/tools/tidy/src/main.rs Signed-off-by: NODA, Kai --- COPYRIGHT | 22 ---------------------- src/tools/tidy/src/main.rs | 2 -- 2 files changed, 24 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index abe8998030871..19559fa2950ea 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -197,28 +197,6 @@ their own copyright notices and license terms: USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* Hoedown, the markdown parser, under src/rt/hoedown, is - licensed as follows. - - Copyright (c) 2008, Natacha Porté - Copyright (c) 2011, Vicent Martí - Copyright (c) 2013, Devin Torres and the Hoedown authors - - Permission to use, copy, modify, and distribute this - software for any purpose with or without fee is hereby - granted, provided that the above copyright notice and - this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR - ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA - OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * libbacktrace, under src/libbacktrace: Copyright (C) 2012-2014 Free Software Foundation, Inc. diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index dee37341051ed..17f8b62117ad4 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -82,11 +82,9 @@ fn filter_dirs(path: &Path) -> bool { "src/llvm", "src/libbacktrace", "src/compiler-rt", - "src/rt/hoedown", "src/rustllvm", "src/rust-installer", "src/liblibc", - "src/tools/cargo", "src/vendor", ]; skip.iter().any(|p| path.ends_with(p)) From 2e327a668e0f37fa9663ede580d354e28fc016bf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 05:42:02 -0400 Subject: [PATCH 651/662] fix nit --- src/librustc_borrowck/borrowck/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e0b4a23010d2f..142286bd834d0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -69,7 +69,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { *providers = Providers { - borrowck: borrowck, + borrowck, ..*providers }; } From c008cd70f5cb20cf22eb2cc9ae12f978296e8a45 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 6 Apr 2017 16:56:09 +0200 Subject: [PATCH 652/662] Make compiletest write test output to different files for different revisions. --- src/tools/compiletest/src/runtest.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 2865fa6a79253..7fb296c19f6ed 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1589,8 +1589,14 @@ actual:\n\ } fn dump_output(&self, out: &str, err: &str) { - self.dump_output_file(out, "out"); - self.dump_output_file(err, "err"); + let revision = if let Some(r) = self.revision { + format!("{}.", r) + } else { + String::new() + }; + + self.dump_output_file(out, &format!("{}out", revision)); + self.dump_output_file(err, &format!("{}err", revision)); self.maybe_dump_to_stdout(out, err); } From bc7af816f3b8712efa4e6643f9cdeb1d5ba5c78a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2017 13:00:17 +0200 Subject: [PATCH 653/662] ICH: Hash everything that gets encoded into crate metadata. --- src/librustc/ich/hcx.rs | 52 ++++ src/librustc/ich/impls_ty.rs | 291 +++++++++++++++++- src/librustc/ich/mod.rs | 4 +- src/librustc/lib.rs | 1 + src/librustc/middle/free_region.rs | 4 + src/librustc_data_structures/array_vec.rs | 6 + .../transitive_relation.rs | 46 +++ src/librustc_metadata/astencode.rs | 42 +-- src/librustc_metadata/encoder.rs | 60 ++-- src/librustc_metadata/index_builder.rs | 77 ++++- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/schema.rs | 58 ++++ 12 files changed, 576 insertions(+), 66 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 5ef30550f1155..3a6367c353c1e 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -13,8 +13,10 @@ use hir::def_id::DefId; use ich::{self, CachingCodemapView}; use session::config::DebugInfoLevel::NoDebugInfo; use ty; +use util::nodemap::NodeMap; use std::hash as std_hash; +use std::collections::{HashMap, HashSet}; use syntax::ast; use syntax::attr; @@ -296,3 +298,53 @@ impl<'a, 'tcx> HashStable> for Span { } } } + +pub fn hash_stable_hashmap<'a, 'tcx, K, V, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &HashMap, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + V: HashStable>, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = map.keys() + .map(|k| (extract_stable_key(hcx, k), k)) + .collect(); + keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone()); + keys.len().hash_stable(hcx, hasher); + for (stable_key, key) in keys { + stable_key.hash_stable(hcx, hasher); + map[key].hash_stable(hcx, hasher); + } +} + +pub fn hash_stable_hashset<'a, 'tcx, K, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + set: &HashSet, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = set.iter() + .map(|k| extract_stable_key(hcx, k)) + .collect(); + keys.sort_unstable(); + keys.hash_stable(hcx, hasher); +} + +pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &NodeMap) + where V: HashStable>, + W: StableHasherResult, +{ + hash_stable_hashmap(hcx, hasher, map, |hcx, node_id| { + hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id + }); +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11ec..c682f6b8668c3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -11,31 +11,37 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::ty in no particular order. -use ich::StableHashingContext; +use ich::{self, StableHashingContext, NodeIdHashingMode}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; use ty; - -impl<'a, 'tcx> HashStable> for ty::Ty<'tcx> { +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { - let type_hash = hcx.tcx().type_id_hash(*self); - type_hash.hash_stable(hcx, hasher); + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + .. + } = *self; + + sty.hash_stable(hcx, hasher); } } impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); -impl<'a, 'tcx, T> HashStable> for ty::Slice +impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice where T: HashStable> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { - (&**self).hash_stable(hcx, hasher); + (&self[..]).hash_stable(hcx, hasher); } } @@ -67,9 +73,13 @@ impl<'a, 'tcx> HashStable> for ty::Region { index.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } + ty::ReScope(code_extent) => { + code_extent.hash_stable(hcx, hasher); + } + ty::ReFree(ref free_region) => { + free_region.hash_stable(hcx, hasher); + } ty::ReLateBound(..) | - ty::ReFree(..) | - ty::ReScope(..) | ty::ReVar(..) | ty::ReSkolemized(..) => { bug!("TypeIdHasher: unexpected region {:?}", *self) @@ -127,7 +137,6 @@ impl_stable_hash_for!(enum ty::BorrowKind { MutBorrow }); - impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, @@ -223,7 +232,6 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx } } - impl<'a, 'tcx> HashStable> for ty::AdtFlags { fn hash_stable(&self, _: &mut StableHashingContext<'a, 'tcx>, @@ -303,7 +311,6 @@ for ::middle::const_val::ConstVal<'tcx> { impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); - impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, predicates @@ -413,3 +420,263 @@ impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { impl_stable_hash_for!(struct ty::DebruijnIndex { depth }); + +impl_stable_hash_for!(enum ty::cast::CastKind { + CoercionCast, + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast +}); + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtent +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + hcx.tcx().region_maps.code_extent_data(*self).hash_stable(hcx, hasher); + }); + } +} + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtentData +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::region::CodeExtentData; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + CodeExtentData::Misc(node_id) | + CodeExtentData::DestructionScope(node_id) => { + node_id.hash_stable(hcx, hasher); + } + CodeExtentData::CallSiteScope { fn_id, body_id } | + CodeExtentData::ParameterScope { fn_id, body_id } => { + fn_id.hash_stable(hcx, hasher); + body_id.hash_stable(hcx, hasher); + } + CodeExtentData::Remainder(block_remainder) => { + block_remainder.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::middle::region::BlockRemainder { + block, + first_statement_index +}); + +impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo { + custom_kind +}); + +impl_stable_hash_for!(struct ty::FreeRegion { + scope, + bound_region +}); + +impl_stable_hash_for!(enum ty::BoundRegion { + BrAnon(index), + BrNamed(def_id, name), + BrFresh(index), + BrEnv +}); + +impl<'a, 'tcx> HashStable> for ty::TypeVariants<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use ty::TypeVariants::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + TyBool | + TyChar | + TyStr | + TyNever => { + // Nothing more to hash. + } + TyInt(int_ty) => { + int_ty.hash_stable(hcx, hasher); + } + TyUint(uint_ty) => { + uint_ty.hash_stable(hcx, hasher); + } + TyFloat(float_ty) => { + float_ty.hash_stable(hcx, hasher); + } + TyAdt(adt_def, substs) => { + adt_def.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyArray(inner_ty, len) => { + inner_ty.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + } + TySlice(inner_ty) => { + inner_ty.hash_stable(hcx, hasher); + } + TyRawPtr(pointee_ty) => { + pointee_ty.hash_stable(hcx, hasher); + } + TyRef(region, pointee_ty) => { + region.hash_stable(hcx, hasher); + pointee_ty.hash_stable(hcx, hasher); + } + TyFnDef(def_id, substs, ref sig) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + sig.hash_stable(hcx, hasher); + } + TyFnPtr(ref sig) => { + sig.hash_stable(hcx, hasher); + } + TyDynamic(ref existential_predicates, region) => { + existential_predicates.hash_stable(hcx, hasher); + region.hash_stable(hcx, hasher); + } + TyClosure(def_id, closure_substs) => { + def_id.hash_stable(hcx, hasher); + closure_substs.hash_stable(hcx, hasher); + } + TyTuple(inner_tys, from_diverging_type_var) => { + inner_tys.hash_stable(hcx, hasher); + from_diverging_type_var.hash_stable(hcx, hasher); + } + TyProjection(ref projection_ty) => { + projection_ty.hash_stable(hcx, hasher); + } + TyAnon(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyParam(param_ty) => { + param_ty.hash_stable(hcx, hasher); + } + + TyError | + TyInfer(..) => { + bug!("ty::TypeVariants::hash_stable() - Unexpected variant.") + } + } + } +} + +impl_stable_hash_for!(struct ty::ParamTy { + idx, + name +}); + +impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { + ty, + mutbl +}); + +impl<'a, 'tcx> HashStable> for ty::ExistentialPredicate<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ExistentialPredicate::Trait(ref trait_ref) => { + trait_ref.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::Projection(ref projection) => { + projection.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + def_id.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> { + def_id, + substs +}); + +impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { + trait_ref, + item_name, + ty +}); + + +impl<'a, 'tcx> HashStable> for ty::TypeckTables<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TypeckTables { + ref type_relative_path_defs, + ref node_types, + ref item_substs, + ref adjustments, + ref method_map, + ref upvar_capture_map, + ref closure_tys, + ref closure_kinds, + ref liberated_fn_sigs, + ref fru_field_types, + + ref cast_kinds, + lints: _, + ref used_trait_imports, + tainted_by_errors, + ref free_region_map, + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); + ich::hash_stable_nodemap(hcx, hasher, node_types); + ich::hash_stable_nodemap(hcx, hasher, item_substs); + ich::hash_stable_nodemap(hcx, hasher, adjustments); + + ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| { + let ty::MethodCall { + expr_id, + autoderef + } = *method_call; + + let def_id = hcx.tcx().hir.local_def_id(expr_id); + (hcx.def_path_hash(def_id), autoderef) + }); + + ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { + let ty::UpvarId { + var_id, + closure_expr_id + } = *up_var_id; + + let var_def_id = hcx.tcx().hir.local_def_id(var_id); + let closure_def_id = hcx.tcx().hir.local_def_id(closure_expr_id); + (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) + }); + + ich::hash_stable_nodemap(hcx, hasher, closure_tys); + ich::hash_stable_nodemap(hcx, hasher, closure_kinds); + ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs); + ich::hash_stable_nodemap(hcx, hasher, fru_field_types); + ich::hash_stable_nodemap(hcx, hasher, cast_kinds); + + ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { + hcx.tcx().def_path_hash(*def_id) + }); + + tainted_by_errors.hash_stable(hcx, hasher); + free_region_map.hash_stable(hcx, hasher); + }) + } +} diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index f932c90a331e1..d70ed051ac410 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -12,8 +12,8 @@ pub use self::fingerprint::Fingerprint; pub use self::caching_codemap_view::CachingCodemapView; -pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; - +pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap, + hash_stable_hashset, hash_stable_nodemap}; mod fingerprint; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b002fd4dfc1a..1f96330d51da5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -42,6 +42,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(discriminant_value)] +#![feature(sort_unstable)] extern crate arena; extern crate core; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab40098..a8eb6a1074383 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -180,3 +180,7 @@ fn lub() { map.relate_free_regions(frs[1], frs[2]); assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2])); } + +impl_stable_hash_for!(struct FreeRegionMap { + relation +}); diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index adb2219722602..848e5a076bb9a 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -40,6 +40,12 @@ unsafe impl Array for [T; 8] { const LEN: usize = 8; } +unsafe impl Array for [T; 32] { + type Element = T; + type PartialStorage = [ManuallyDrop; 32]; + const LEN: usize = 32; +} + pub struct ArrayVec { count: usize, values: A::PartialStorage diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 2bce7faf08cec..2631108aeb5fa 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,11 +9,14 @@ // except according to those terms. use bitvec::BitMatrix; +use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; + + #[derive(Clone)] pub struct TransitiveRelation { // List of elements. This is used to map from a T to a usize. We @@ -334,6 +337,49 @@ impl Decodable for TransitiveRelation } } +impl HashStable for TransitiveRelation + where T: HashStable + PartialEq + Debug +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + // We are assuming here that the relation graph has been built in a + // deterministic way and we can just hash it the way it is. + let TransitiveRelation { + ref elements, + ref edges, + // "closure" is just a copy of the data above + closure: _ + } = *self; + + elements.hash_stable(hcx, hasher); + edges.hash_stable(hcx, hasher); + } +} + +impl HashStable for Edge { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Edge { + ref source, + ref target, + } = *self; + + source.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + } +} + +impl HashStable for Index { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Index(idx) = *self; + idx.hash_stable(hcx, hasher); + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 459132eb9c613..d9008ce555cc1 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -10,14 +10,12 @@ use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use encoder::EncodeContext; +use index_builder::EntryBuilder; use schema::*; use rustc::hir; use rustc::ty; -use rustc_serialize::Encodable; - #[derive(RustcEncodable, RustcDecodable)] pub struct Ast<'tcx> { pub body: Lazy, @@ -26,7 +24,14 @@ pub struct Ast<'tcx> { pub rvalue_promotable_to_static: bool, } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl_stable_hash_for!(struct Ast<'tcx> { + body, + tables, + nested_bodies, + rvalue_promotable_to_static +}); + +impl<'a, 'b, 'tcx> EntryBuilder<'a, 'b, 'tcx> { pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy> { let body = self.tcx.hir.body(body_id); let lazy_body = self.lazy(body); @@ -34,15 +39,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tables = self.tcx.body_tables(body_id); let lazy_tables = self.lazy(tables); - let nested_pos = self.position(); - let nested_count = { - let mut visitor = NestedBodyEncodingVisitor { - ecx: self, - count: 0, - }; - visitor.visit_body(body); - visitor.count + let mut visitor = NestedBodyCollector { + tcx: self.tcx, + bodies_found: Vec::new(), }; + visitor.visit_body(body); + let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found); let rvalue_promotable_to_static = self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id]; @@ -50,27 +52,25 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(&Ast { body: lazy_body, tables: lazy_tables, - nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count), + nested_bodies: lazy_nested_bodies, rvalue_promotable_to_static: rvalue_promotable_to_static }) } } -struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> { - ecx: &'a mut EncodeContext<'b, 'tcx>, - count: usize, +struct NestedBodyCollector<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + bodies_found: Vec<&'tcx hir::Body>, } -impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> { +impl<'a, 'tcx: 'a> Visitor<'tcx> for NestedBodyCollector<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } fn visit_nested_body(&mut self, body: hir::BodyId) { - let body = self.ecx.tcx.hir.body(body); - body.encode(self.ecx).unwrap(); - self.count += 1; - + let body = self.tcx.hir.body(body); + self.bodies_found.push(body); self.visit_body(body); } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 38d774992a551..a74ce3f650226 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -15,6 +15,7 @@ use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; +use rustc::ich; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -42,7 +43,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc::hir::intravisit; -use super::index_builder::{FromId, IndexBuilder, Untracked}; +use super::index_builder::{FromId, IndexBuilder, Untracked, EntryBuilder}; pub struct EncodeContext<'a, 'tcx: 'a> { opaque: opaque::Encoder<'a>, @@ -54,6 +55,8 @@ pub struct EncodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + + pub metadata_hashes: Vec<(DefIndex, ich::Fingerprint)>, } macro_rules! encoder_methods { @@ -172,7 +175,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn lazy_seq(&mut self, iter: I) -> LazySeq + pub fn lazy_seq(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: Encodable { @@ -184,7 +187,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq + pub fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: 'b + Encodable { @@ -233,10 +236,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Ok(()) } +} +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { let tcx = self.tcx; - self.lazy_seq(tcx.item_variances(def_id).iter().cloned()) + self.lazy_seq_from_slice(&tcx.item_variances(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { @@ -305,7 +310,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ModData { reexports: match tcx.export_map.get(&id) { - Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports), + Some(exports) if *vis == hir::Public => { + self.lazy_seq_from_slice(exports.as_slice()) + } _ => LazySeq::empty(), }, }; @@ -339,14 +346,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, - EncodeContext::encode_field, + EntryBuilder::encode_field, (adt_def_id, Untracked((variant_index, field_index)))); } } } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { /// Encode data for the given field of the given variant of the /// given ADT. The indices of the variant/field are untracked: /// this is ok because we will have to lookup the adt-def by its @@ -907,7 +914,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let def = self.tcx.lookup_adt_def(def_id); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, - EncodeContext::encode_enum_variant_info, + EntryBuilder::encode_enum_variant_info, (def_id, Untracked(i))); } } @@ -918,7 +925,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { if !struct_def.is_struct() { let ctor_def_id = self.tcx.hir.local_def_id(struct_def.id()); self.record(ctor_def_id, - EncodeContext::encode_struct_ctor, + EntryBuilder::encode_struct_ctor, (def_id, ctor_def_id)); } } @@ -928,14 +935,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemImpl(..) => { for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, - EncodeContext::encode_info_for_impl_item, + EntryBuilder::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, - EncodeContext::encode_info_for_trait_item, + EntryBuilder::encode_info_for_trait_item, item_def_id); } } @@ -943,7 +950,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_foreign_item(&mut self, (def_id, nitem): (DefId, &hir::ForeignItem)) -> Entry<'tcx> { @@ -1002,7 +1009,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { match item.node { hir::ItemExternCrate(_) | hir::ItemUse(..) => (), // ignore these - _ => self.index.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), + _ => self.index.record(def_id, EntryBuilder::encode_info_for_item, (def_id, item)), } self.index.encode_addl_info_for_item(item); } @@ -1010,7 +1017,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_foreign_item(self, ni); let def_id = self.index.tcx.hir.local_def_id(ni.id); self.index.record(def_id, - EncodeContext::encode_info_for_foreign_item, + EntryBuilder::encode_info_for_foreign_item, (def_id, ni)); } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { @@ -1023,7 +1030,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { } fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) { let def_id = self.index.tcx.hir.local_def_id(macro_def.id); - self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def); + self.index.record(def_id, EntryBuilder::encode_info_for_macro_def, macro_def); } } @@ -1032,14 +1039,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for ty_param in &generics.ty_params { let def_id = self.tcx.hir.local_def_id(ty_param.id); let has_default = Untracked(ty_param.default.is_some()); - self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default)); + self.record(def_id, EntryBuilder::encode_info_for_ty_param, (def_id, has_default)); } } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { if let hir::TyImplTrait(_) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); - self.record(def_id, EncodeContext::encode_info_for_anon_ty, def_id); + self.record(def_id, EntryBuilder::encode_info_for_anon_ty, def_id); } } @@ -1047,14 +1054,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { match expr.node { hir::ExprClosure(..) => { let def_id = self.tcx.hir.local_def_id(expr.id); - self.record(def_id, EncodeContext::encode_info_for_closure, def_id); + self.record(def_id, EntryBuilder::encode_info_for_closure, def_id); } _ => {} } } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty_param(&mut self, (def_id, Untracked(has_default)): (DefId, Untracked)) -> Entry<'tcx> { @@ -1133,11 +1140,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + self.lazy_seq_from_slice(attrs) + } +} + +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(&mut self) -> Index { let krate = self.tcx.hir.krate(); let mut index = IndexBuilder::new(self); index.record(DefId::local(CRATE_DEF_INDEX), - EncodeContext::encode_info_for_mod, + EntryBuilder::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); @@ -1147,10 +1160,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { visitor.index.into_items() } - fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { - self.lazy_seq_ref(attrs) - } - fn encode_crate_deps(&mut self) -> LazySeq { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore @@ -1298,7 +1307,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None => LazySeq::empty(), } } +} +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_crate_root(&mut self) -> Lazy { let mut i = self.position(); let crate_deps = self.encode_crate_deps(); @@ -1448,6 +1459,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), + metadata_hashes: Vec::new(), }; // Encode the rustc version string in a predictable location. diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index a811f72bc956c..389ada12da81e 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -59,14 +59,19 @@ use encoder::EncodeContext; use index::Index; use schema::*; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::ich::{StableHashingContext, Fingerprint}; use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; +use rustc_serialize::Encodable; + +use rustc::dep_graph::DepNode; + /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { @@ -112,16 +117,29 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// holds, and that it is therefore not gaining "secret" access to /// bits of HIR or other state that would not be trackd by the /// content system. - pub fn record(&mut self, - id: DefId, - op: fn(&mut EncodeContext<'b, 'tcx>, DATA) -> Entry<'tcx>, - data: DATA) + pub fn record<'x, DATA>(&'x mut self, + id: DefId, + op: fn(&mut EntryBuilder<'x, 'b, 'tcx>, DATA) -> Entry<'tcx>, + data: DATA) where DATA: DepGraphRead { let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); data.read(self.tcx); - let entry = op(&mut self.ecx, data); - self.items.record(id, self.ecx.lazy(&entry)); + + assert!(id.is_local()); + let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx; + let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx; + let mut entry_builder = EntryBuilder { + tcx: tcx, + ecx: ecx, + hasher: StableHasher::new(), + hcx: StableHashingContext::new(tcx), + }; + + let entry = op(&mut entry_builder, data); + let entry = entry_builder.ecx.lazy(&entry); + entry_builder.finish(id); + self.items.record(id, entry); } pub fn into_items(self) -> Index { @@ -223,3 +241,48 @@ impl DepGraphRead for FromId { tcx.hir.read(self.0); } } + +pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> { + pub tcx: TyCtxt<'b, 'tcx, 'tcx>, + ecx: &'a mut EncodeContext<'b, 'tcx>, + hasher: StableHasher, + hcx: StableHashingContext<'b, 'tcx>, +} + +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { + + pub fn finish(self, def_id: DefId) { + let hash = self.hasher.finish(); + self.ecx.metadata_hashes.push((def_id.index, hash)); + } + + pub fn lazy(&mut self, value: &T) -> Lazy + where T: Encodable + HashStable> + { + value.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy(value) + } + + pub fn lazy_seq(&mut self, iter: I) -> LazySeq + where I: IntoIterator, + T: Encodable + HashStable> + { + let items: Vec = iter.into_iter().collect(); + items.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq(items) + } + + pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq + where T: Encodable + HashStable> + { + slice.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq_ref(slice.iter()) + } + + pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq + where T: Encodable + HashStable> + { + slice.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) + } +} diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2fbdb8c0de676..b9e142ac65072 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -27,6 +27,7 @@ #![feature(rustc_private)] #![feature(specialization)] #![feature(staged_api)] +#![feature(discriminant_value)] #[macro_use] extern crate log; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index abb482a50ebc2..6ffa31c072709 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -28,6 +28,9 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable, + StableHasherResult}; + pub fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) @@ -100,6 +103,15 @@ impl Clone for Lazy { impl serialize::UseSpecializedEncodable for Lazy {} impl serialize::UseSpecializedDecodable for Lazy {} +impl HashStable for Lazy { + fn hash_stable(&self, + _: &mut CTX, + _: &mut StableHasher) { + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. + } +} + /// A sequence of type T referred to by its absolute position /// in the metadata and length, and which can be decoded lazily. /// The sequence is a single node for the purposes of `Lazy`. @@ -148,6 +160,15 @@ impl Clone for LazySeq { impl serialize::UseSpecializedEncodable for LazySeq {} impl serialize::UseSpecializedDecodable for LazySeq {} +impl HashStable for LazySeq { + fn hash_stable(&self, + _: &mut CTX, + _: &mut StableHasher) { + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. + } +} + /// Encoding / decoding state for `Lazy` and `LazySeq`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum LazyState { @@ -251,17 +272,23 @@ pub struct ModData { pub reexports: LazySeq, } +impl_stable_hash_for!(struct ModData { reexports }); + #[derive(RustcEncodable, RustcDecodable)] pub struct MacroDef { pub body: String, } +impl_stable_hash_for!(struct MacroDef { body }); + #[derive(RustcEncodable, RustcDecodable)] pub struct FnData { pub constness: hir::Constness, pub arg_names: LazySeq, } +impl_stable_hash_for!(struct FnData { constness, arg_names }); + #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, @@ -273,6 +300,13 @@ pub struct VariantData<'tcx> { pub struct_ctor: Option, } +impl_stable_hash_for!(struct VariantData<'tcx> { + ctor_kind, + discr, + evaluated_discr, + struct_ctor +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct TraitData<'tcx> { pub unsafety: hir::Unsafety, @@ -281,6 +315,13 @@ pub struct TraitData<'tcx> { pub super_predicates: Lazy>, } +impl_stable_hash_for!(struct TraitData<'tcx> { + unsafety, + paren_sugar, + has_default_impl, + super_predicates +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, @@ -291,6 +332,14 @@ pub struct ImplData<'tcx> { pub trait_ref: Option>>, } +impl_stable_hash_for!(struct ImplData<'tcx> { + polarity, + parent_impl, + coerce_unsized_info, + trait_ref +}); + + /// Describes whether the container of an associated item /// is a trait or an impl and whether, in a trait, it has /// a default, or an in impl, whether it's marked "default". @@ -302,6 +351,13 @@ pub enum AssociatedContainer { ImplFinal, } +impl_stable_hash_for!(enum ::schema::AssociatedContainer { + TraitRequired, + TraitWithDefault, + ImplDefault, + ImplFinal +}); + impl AssociatedContainer { pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { match *self { @@ -335,9 +391,11 @@ pub struct MethodData { pub container: AssociatedContainer, pub has_self: bool, } +impl_stable_hash_for!(struct MethodData { fn_data, container, has_self }); #[derive(RustcEncodable, RustcDecodable)] pub struct ClosureData<'tcx> { pub kind: ty::ClosureKind, pub ty: Lazy>, } +impl_stable_hash_for!(struct ClosureData<'tcx> { kind, ty }); From ca2dce9b48e65ae2b286fbd10e459536ecccb2d8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2017 23:39:02 +0200 Subject: [PATCH 654/662] ICH: Replace old, transitive metadata hashing with direct hashing approach. Instead of collecting all potential inputs to some metadata entry and hashing those, we directly hash the values we are storing in metadata. This is more accurate and doesn't suffer from quadratic blow-up when many entries have the same dependencies. --- src/librustc/ich/impls_ty.rs | 32 ++--- src/librustc/middle/cstore.rs | 23 +++- src/librustc/ty/mod.rs | 17 +++ src/librustc/ty/util.rs | 30 +++-- src/librustc_data_structures/blake2b.rs | 34 ++++- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/stable_hasher.rs | 7 +- src/librustc_driver/driver.rs | 1 + src/librustc_incremental/persist/data.rs | 14 +- .../persist/dirty_clean.rs | 64 ++++++--- src/librustc_incremental/persist/preds/mod.rs | 28 +++- src/librustc_incremental/persist/save.rs | 81 ++---------- src/librustc_metadata/cstore_impl.rs | 8 +- src/librustc_metadata/encoder.rs | 48 +++++-- src/librustc_metadata/index_builder.rs | 93 +++++++++++--- src/librustc_metadata/schema.rs | 90 ++++++++++++- src/librustc_trans/back/link.rs | 5 +- src/librustc_trans/base.rs | 11 +- src/librustc_trans/lib.rs | 2 +- src/test/incremental/hashes/enum_defs.rs | 92 ++++++++++--- src/test/incremental/hashes/extern_mods.rs | 40 ++++-- .../incremental/hashes/function_interfaces.rs | 10 +- src/test/incremental/hashes/inherent_impls.rs | 20 ++- src/test/incremental/hashes/struct_defs.rs | 90 ++++++++++--- src/test/incremental/hashes/trait_defs.rs | 121 +++++++++++------- src/test/incremental/hashes/trait_impls.rs | 58 +++------ .../unchecked_dirty_clean_metadata.rs | 10 -- 27 files changed, 689 insertions(+), 341 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index c682f6b8668c3..46d1e7ef0c7c4 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -16,24 +16,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; +use syntax_pos::symbol::InternedString; use ty; -impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, - hasher: &mut StableHasher) { - let ty::TyS { - ref sty, - - // The other fields just provide fast access to information that is - // also contained in `sty`, so no need to hash them. - .. - } = *self; - - sty.hash_stable(hcx, hasher); - } -} - impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice @@ -288,9 +273,14 @@ for ::middle::const_val::ConstVal<'tcx> { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - ConstVal::Struct(ref _name_value_map) => { - // BTreeMap>), - panic!("Ordering still unstable") + ConstVal::Struct(ref name_value_map) => { + let mut values: Vec<(InternedString, &ConstVal)> = + name_value_map.iter() + .map(|(name, val)| (name.as_str(), val)) + .collect(); + + values.sort_unstable_by_key(|&(ref name, _)| name.clone()); + values.hash_stable(hcx, hasher); } ConstVal::Tuple(ref value) => { value.hash_stable(hcx, hasher); @@ -632,6 +622,8 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ref fru_field_types, ref cast_kinds, + + // FIXME(#41184): This is still ignored at the moment. lints: _, ref used_trait_imports, tainted_by_errors, @@ -672,7 +664,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ich::hash_stable_nodemap(hcx, hasher, cast_kinds); ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { - hcx.tcx().def_path_hash(*def_id) + hcx.def_path_hash(*def_id) }); tainted_by_errors.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 694321812836b..81cf24e58dda4 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -27,6 +27,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData}; use hir::svh::Svh; +use ich; use middle::lang_items; use ty::{self, TyCtxt}; use session::Session; @@ -161,6 +162,20 @@ pub struct ExternCrate { pub path_len: usize, } +pub struct EncodedMetadata { + pub raw_data: Vec, + pub hashes: Vec, +} + +/// The hash for some metadata that (when saving) will be exported +/// from this crate, or which (when importing) was exported by an +/// upstream crate. +#[derive(Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +pub struct EncodedMetadataHash { + pub def_index: DefIndex, + pub hash: ich::Fingerprint, +} + /// A store of Rust crates, through with their metadata /// can be accessed. pub trait CrateStore { @@ -258,7 +273,8 @@ pub trait CrateStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec; + reachable: &NodeSet) + -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; } @@ -417,7 +433,10 @@ impl CrateStore for DummyCrateStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec { vec![] } + reachable: &NodeSet) + -> EncodedMetadata { + bug!("encode_metadata") + } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a2c356c20db09..23f35d3bdd792 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -452,6 +452,23 @@ impl<'tcx> Hash for TyS<'tcx> { } } +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + flags: _, + region_depth: _, + } = *self; + + sty.hash_stable(hcx, hasher); + } +} + pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9a6..c650ffe302762 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,7 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use infer::InferCtxt; -// use hir::map as hir_map; +use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; @@ -25,8 +25,8 @@ use util::nodemap::FxHashMap; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; - +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use std::cell::RefCell; use std::cmp; use std::hash::Hash; @@ -187,6 +187,22 @@ impl<'tcx> ParameterEnvironment<'tcx> { } } +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { + let mut hasher = StableHasher::new(); + let mut hcx = StableHashingContext::new(self); + + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ty.hash_stable(hcx, &mut hasher); + }); + }); + hasher.finish() + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { @@ -339,14 +355,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = TypeIdHasher::new(self); - hasher.visit_ty(ty); - hasher.finish() - } - /// Calculate the destructor of a given type. pub fn calculate_dtor( self, diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 9d97a83f693c3..bdef9fefd41e4 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -29,16 +29,23 @@ pub struct Blake2bCtx { t: [u64; 2], c: usize, outlen: u16, - finalized: bool + finalized: bool, + + #[cfg(debug_assertions)] + fnv_hash: u64, } +#[cfg(debug_assertions)] impl ::std::fmt::Debug for Blake2bCtx { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - try!(write!(fmt, "hash: ")); - for v in &self.h { - try!(write!(fmt, "{:x}", v)); - } - Ok(()) + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "{:x}", self.fnv_hash) + } +} + +#[cfg(not(debug_assertions))] +impl ::std::fmt::Debug for Blake2bCtx { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "Enable debug_assertions() for more info.") } } @@ -157,6 +164,9 @@ fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { c: 0, outlen: outlen as u16, finalized: false, + + #[cfg(debug_assertions)] + fnv_hash: 0xcbf29ce484222325, }; ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); @@ -194,6 +204,16 @@ fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) { checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); ctx.c += bytes_to_copy; } + + #[cfg(debug_assertions)] + { + // compute additional FNV hash for simpler to read debug output + const MAGIC_PRIME: u64 = 0x00000100000001b3; + + for &byte in data { + ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME); + } + } } fn blake2b_final(ctx: &mut Blake2bCtx) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 72c533a74618b..00c46d992bfd5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -40,6 +40,7 @@ #![feature(discriminant_value)] #![feature(specialization)] #![feature(manually_drop)] +#![feature(struct_field_attributes)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index dc412a0763ef7..95f063976d491 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -40,13 +40,18 @@ fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize { /// This hasher currently always uses the stable Blake2b algorithm /// and allows for variable output lengths through its type /// parameter. -#[derive(Debug)] pub struct StableHasher { state: Blake2bHasher, bytes_hashed: u64, width: PhantomData, } +impl ::std::fmt::Debug for StableHasher { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{:?}", self.state) + } +} + pub trait StableHasherResult: Sized { fn finish(hasher: StableHasher) -> Self; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bdb05d06b0b10..eeacf79514a87 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1083,6 +1083,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "serialize dep graph", || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map, + &translation.metadata.hashes, translation.link.crate_hash)); translation } diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index d900907395656..8a1af5dd08d74 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -13,6 +13,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; use rustc::ich::Fingerprint; +use rustc::middle::cstore::EncodedMetadataHash; use std::sync::Arc; use rustc_data_structures::fx::FxHashMap; @@ -98,7 +99,7 @@ pub struct SerializedMetadataHashes { /// where `X` refers to some item in this crate. That `X` will be /// a `DefPathIndex` that gets retracted to the current `DefId` /// (matching the one found in this structure). - pub hashes: Vec, + pub hashes: Vec, /// For each DefIndex (as it occurs in SerializedMetadataHash), this /// map stores the DefPathIndex (as it occurs in DefIdDirectory), so @@ -112,14 +113,3 @@ pub struct SerializedMetadataHashes { /// the DefIndex. pub index_map: FxHashMap } - -/// The hash for some metadata that (when saving) will be exported -/// from this crate, or which (when importing) was exported by an -/// upstream crate. -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedMetadataHash { - pub def_index: DefIndex, - - /// the hash itself, computed by `calculate_item_hash` - pub hash: Fingerprint, -} diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index d931f64d579e1..af5c1f05bd1fc 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -215,9 +215,11 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } } -pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &FxHashMap, - current_metadata_hashes: &FxHashMap) { +pub fn check_dirty_clean_metadata<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + prev_metadata_hashes: &FxHashMap, + current_metadata_hashes: &FxHashMap) +{ if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } @@ -230,7 +232,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, current_metadata_hashes: current_metadata_hashes, checked_attrs: FxHashSet(), }; - krate.visit_all_item_likes(&mut dirty_clean_visitor); + intravisit::walk_crate(&mut dirty_clean_visitor, krate); let mut all_attrs = FindAllAttrs { tcx: tcx, @@ -246,30 +248,58 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { +pub struct DirtyCleanMetadataVisitor<'a, 'tcx: 'a, 'm> { tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_metadata_hashes: &'m FxHashMap, current_metadata_hashes: &'m FxHashMap, checked_attrs: FxHashSet, } -impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { +impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { + + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.tcx.hir) + } + fn visit_item(&mut self, item: &'tcx hir::Item) { self.check_item(item.id, item.span); + intravisit::walk_item(self, item); + } - if let hir::ItemEnum(ref def, _) = item.node { - for v in &def.variants { - self.check_item(v.node.data.id(), v.span); - } + fn visit_variant_data(&mut self, + variant_data: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _parent_id: ast::NodeId, + span: Span) { + if self.tcx.hir.find(variant_data.id()).is_some() { + // VariantData that represent structs or tuples don't have a + // separate entry in the HIR map and checking them would error, + // so only check if this is an enum or union variant. + self.check_item(variant_data.id(), span); } + + intravisit::walk_struct_def(self, variant_data); } - fn visit_trait_item(&mut self, item: &hir::TraitItem) { + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { self.check_item(item.id, item.span); + intravisit::walk_trait_item(self, item); } - fn visit_impl_item(&mut self, item: &hir::ImplItem) { + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { self.check_item(item.id, item.span); + intravisit::walk_impl_item(self, item); + } + + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) { + self.check_item(i.id, i.span); + intravisit::walk_foreign_item(self, i); + } + + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { + self.check_item(s.id, s.span); + intravisit::walk_struct_field(self, s); } } @@ -281,13 +311,15 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { for attr in self.tcx.get_attrs(def_id).iter() { if attr.check_name(ATTR_DIRTY_METADATA) { if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - self.assert_state(false, def_id, item_span); + if self.checked_attrs.insert(attr.id) { + self.assert_state(false, def_id, item_span); + } } } else if attr.check_name(ATTR_CLEAN_METADATA) { if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - self.assert_state(true, def_id, item_span); + if self.checked_attrs.insert(attr.id) { + self.assert_state(true, def_id, item_span); + } } } } diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index fe8cf72996e15..e769641a4cadf 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -44,16 +44,18 @@ impl<'q> Predecessors<'q> { pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { let tcx = hcx.tcx; - let collect_for_metadata = tcx.sess.opts.debugging_opts.incremental_cc || - tcx.sess.opts.debugging_opts.query_dep_graph; - // Find the set of "start nodes". These are nodes that we will // possibly query later. let is_output = |node: &DepNode| -> bool { match *node { DepNode::WorkProduct(_) => true, - DepNode::MetaData(ref def_id) => collect_for_metadata && def_id.is_local(), - + DepNode::MetaData(ref def_id) => { + // We do *not* create dep-nodes for the current crate's + // metadata anymore, just for metadata that we import/read + // from other crates. + debug_assert!(!def_id.is_local()); + false + } // if -Z query-dep-graph is passed, save more extended data // to enable better unit testing DepNode::TypeckTables(_) | @@ -75,6 +77,22 @@ impl<'q> Predecessors<'q> { .or_insert_with(|| hcx.hash(input).unwrap()); } + if tcx.sess.opts.debugging_opts.query_dep_graph { + // Not all inputs might have been reachable from an output node, + // but we still want their hash for our unit tests. + let hir_nodes = query.graph.all_nodes().iter().filter_map(|node| { + match node.data { + DepNode::Hir(_) => Some(&node.data), + _ => None, + } + }); + + for node in hir_nodes { + hashes.entry(node) + .or_insert_with(|| hcx.hash(node).unwrap()); + } + } + let bootstrap_outputs: Vec<&'q DepNode> = (0 .. graph.len_nodes()) .map(NodeIndex) diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 1591503865e81..1864009fbdf21 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -12,13 +12,12 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; +use rustc::middle::cstore::EncodedMetadataHash; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::{NodeIndex, INCOMING}; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; -use std::hash::Hash; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; @@ -32,10 +31,10 @@ use super::fs::*; use super::dirty_clean; use super::file_format; use super::work_product; -use calculate_svh::IchHasher; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, + metadata_hashes: &[EncodedMetadataHash], svh: Svh) { debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); @@ -56,16 +55,16 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let preds = Predecessors::new(&query, &mut hcx); let mut current_metadata_hashes = FxHashMap(); + // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, + // since metadata-encoding might add new entries to the + // DefIdDirectory (which is saved in the dep-graph file). if sess.opts.debugging_opts.incremental_cc || sess.opts.debugging_opts.query_dep_graph { - // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, - // since metadata-encoding might add new entries to the - // DefIdDirectory (which is saved in the dep-graph file). save_in(sess, metadata_hash_export_path(sess), |e| encode_metadata_hashes(tcx, svh, - &preds, + metadata_hashes, &mut builder, &mut current_metadata_hashes, e)); @@ -241,80 +240,16 @@ pub fn encode_dep_graph(preds: &Predecessors, pub fn encode_metadata_hashes(tcx: TyCtxt, svh: Svh, - preds: &Predecessors, + metadata_hashes: &[EncodedMetadataHash], builder: &mut DefIdDirectoryBuilder, current_metadata_hashes: &mut FxHashMap, encoder: &mut Encoder) -> io::Result<()> { - // For each `MetaData(X)` node where `X` is local, accumulate a - // hash. These are the metadata items we export. Downstream - // crates will want to see a hash that tells them whether we might - // have changed the metadata for a given item since they last - // compiled. - // - // (I initially wrote this with an iterator, but it seemed harder to read.) let mut serialized_hashes = SerializedMetadataHashes { - hashes: vec![], + hashes: metadata_hashes.to_vec(), index_map: FxHashMap() }; - for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() { - let index = NodeIndex(index); - let def_id = match *target.data { - DepNode::MetaData(def_id) if def_id.is_local() => def_id, - _ => continue, - }; - - // To create the hash for each item `X`, we don't hash the raw - // bytes of the metadata (though in principle we - // could). Instead, we walk the predecessors of `MetaData(X)` - // from the dep-graph. This corresponds to all the inputs that - // were read to construct the metadata. To create the hash for - // the metadata, we hash (the hash of) all of those inputs. - debug!("save: computing metadata hash for {:?}", def_id); - - // Create a vector containing a pair of (source-id, hash). - // The source-id is stored as a `DepNode`, where the u64 - // is the det. hash of the def-path. This is convenient - // because we can sort this to get a stable ordering across - // compilations, even if the def-ids themselves have changed. - let mut hashes: Vec<(DepNode, Fingerprint)> = - preds.reduced_graph - .depth_traverse(index, INCOMING) - .map(|index| preds.reduced_graph.node_data(index)) - .filter(|dep_node| HashContext::is_hashable(dep_node)) - .map(|dep_node| { - let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))) - .unwrap(); - let hash = preds.hashes[dep_node]; - (hash_dep_node, hash) - }) - .collect(); - - hashes.sort(); - let mut state = IchHasher::new(); - hashes.hash(&mut state); - let hash = state.finish(); - - debug!("save: metadata hash for {:?} is {}", def_id, hash); - - if tcx.sess.opts.debugging_opts.incremental_dump_hash { - println!("metadata hash for {:?} is {}", def_id, hash); - for pred_index in preds.reduced_graph.depth_traverse(index, INCOMING) { - let dep_node = preds.reduced_graph.node_data(pred_index); - if HashContext::is_hashable(&dep_node) { - println!("metadata hash for {:?} depends on {:?} with hash {}", - def_id, dep_node, preds.hashes[dep_node]); - } - } - } - - serialized_hashes.hashes.push(SerializedMetadataHash { - def_index: def_id.index, - hash: hash, - }); - } - if tcx.sess.opts.debugging_opts.query_dep_graph { for serialized_hash in &serialized_hashes.hashes { let def_id = DefId::local(serialized_hash.def_index); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 37984e4c3718f..3239dfb937b5e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -14,8 +14,9 @@ use locator; use schema; use rustc::dep_graph::DepTrackingMapConfig; -use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate}; -use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; +use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, + ExternCrate, NativeLibrary, LinkMeta, + LinkagePreference, LoadedMacro, EncodedMetadata}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::session::Session; @@ -498,7 +499,8 @@ impl CrateStore for cstore::CStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec + reachable: &NodeSet) + -> EncodedMetadata { encoder::encode_metadata(tcx, self, link_meta, reachable) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a74ce3f650226..ffe68094c6afc 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -12,10 +12,10 @@ use cstore; use index::Index; use schema::*; -use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; +use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, + EncodedMetadata, EncodedMetadataHash}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; -use rustc::ich; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -56,7 +56,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, - pub metadata_hashes: Vec<(DefIndex, ich::Fingerprint)>, + pub metadata_hashes: Vec, } macro_rules! encoder_methods { @@ -240,13 +240,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { + debug!("EntryBuilder::encode_item_variances({:?})", def_id); let tcx = self.tcx; self.lazy_seq_from_slice(&tcx.item_variances(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.item_type(def_id)) + let ty = tcx.item_type(def_id); + debug!("EntryBuilder::encode_item_type({:?}) => {:?}", def_id, ty); + self.lazy(&ty) } /// Encode data for the given variant of the given ADT. The @@ -261,6 +264,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; let def_id = variant.did; + debug!("EntryBuilder::encode_enum_variant_info({:?})", def_id); let data = VariantData { ctor_kind: variant.ctor_kind, @@ -307,6 +311,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; let def_id = tcx.hir.local_def_id(id); + debug!("EntryBuilder::encode_info_for_mod({:?})", def_id); let data = ModData { reexports: match tcx.export_map.get(&id) { @@ -370,6 +375,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let field = &variant.fields[field_index]; let def_id = field.did; + debug!("EntryBuilder::encode_field({:?})", def_id); + let variant_id = tcx.hir.as_local_node_id(variant.did).unwrap(); let variant_data = tcx.hir.expect_variant_data(variant_id); @@ -394,6 +401,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { + debug!("EntryBuilder::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; let variant = tcx.lookup_adt_def(adt_def_id).struct_variant(); @@ -436,16 +444,19 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_generics(&mut self, def_id: DefId) -> Lazy { + debug!("EntryBuilder::encode_generics({:?})", def_id); let tcx = self.tcx; self.lazy(tcx.item_generics(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { + debug!("EntryBuilder::encode_predicates({:?})", def_id); let tcx = self.tcx; self.lazy(&tcx.item_predicates(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -528,6 +539,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_impl_item({:?})", def_id); let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.hir.expect_impl_item(node_id); let impl_item = self.tcx.associated_item(def_id); @@ -614,11 +626,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_mir(&mut self, def_id: DefId) -> Option>> { + debug!("EntryBuilder::encode_mir({:?})", def_id); self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow())) } // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq { + debug!("EntryBuilder::encode_inherent_implementations({:?})", def_id); match self.tcx.maps.inherent_impls.borrow().get(&def_id) { None => LazySeq::empty(), Some(implementations) => { @@ -631,18 +645,19 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_stability(&mut self, def_id: DefId) -> Option> { + debug!("EntryBuilder::encode_stability({:?})", def_id); self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab)) } fn encode_deprecation(&mut self, def_id: DefId) -> Option> { + debug!("EntryBuilder::encode_deprecation({:?})", def_id); self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; - debug!("encoding info for item at {}", - tcx.sess.codemap().span_to_string(item.span)); + debug!("EntryBuilder::encode_info_for_item({:?})", def_id); let kind = match item.node { hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, @@ -956,7 +971,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; - debug!("writing foreign item {}", tcx.node_path_str(nitem.id)); + debug!("EntryBuilder::encode_info_for_foreign_item({:?})", def_id); let kind = match nitem.node { hir::ForeignItemFn(_, ref names, _) => { @@ -1065,6 +1080,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty_param(&mut self, (def_id, Untracked(has_default)): (DefId, Untracked)) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_ty_param({:?})", def_id); let tcx = self.tcx; Entry { kind: EntryKind::Type, @@ -1091,6 +1107,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_anon_ty({:?})", def_id); let tcx = self.tcx; Entry { kind: EntryKind::Type, @@ -1113,6 +1130,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_closure({:?})", def_id); let tcx = self.tcx; let data = ClosureData { @@ -1141,6 +1159,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because + // we really on the HashStable specialization for [Attribute] + // to properly filter things out. self.lazy_seq_from_slice(attrs) } } @@ -1442,14 +1463,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, link_meta: &LinkMeta, exported_symbols: &NodeSet) - -> Vec { + -> EncodedMetadata +{ let mut cursor = Cursor::new(vec![]); cursor.write_all(METADATA_HEADER).unwrap(); // Will be filed with the root position after encoding everything. cursor.write_all(&[0, 0, 0, 0]).unwrap(); - let root = { + let (root, metadata_hashes) = { let mut ecx = EncodeContext { opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, @@ -1467,7 +1489,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Encode all the entries and extra information in the crate, // culminating in the `CrateRoot` which points to all of it. - ecx.encode_crate_root() + let root = ecx.encode_crate_root(); + (root, ecx.metadata_hashes) }; let mut result = cursor.into_inner(); @@ -1479,7 +1502,10 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result[header + 2] = (pos >> 8) as u8; result[header + 3] = (pos >> 0) as u8; - result + EncodedMetadata { + raw_data: result, + hashes: metadata_hashes, + } } pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 389ada12da81e..01f948866b850 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -62,16 +62,16 @@ use schema::*; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ich::{StableHashingContext, Fingerprint}; +use rustc::middle::cstore::EncodedMetadataHash; use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; +use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_serialize::Encodable; -use rustc::dep_graph::DepNode; - /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { @@ -123,20 +123,36 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { data: DATA) where DATA: DepGraphRead { - let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); - data.read(self.tcx); - assert!(id.is_local()); let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx; + + // We don't track this since we are explicitly computing the incr. comp. + // hashes anyway. In theory we could do some tracking here and use it to + // avoid rehashing things (and instead cache the hashes) but it's + // unclear whether that would be a win since hashing is cheap enough. + let _task = tcx.dep_graph.in_ignore(); + + let compute_ich = (tcx.sess.opts.debugging_opts.query_dep_graph || + tcx.sess.opts.debugging_opts.incremental_cc) && + tcx.sess.opts.build_dep_graph(); + let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx; let mut entry_builder = EntryBuilder { tcx: tcx, ecx: ecx, - hasher: StableHasher::new(), - hcx: StableHashingContext::new(tcx), + hcx: if compute_ich { + Some((StableHashingContext::new(tcx), StableHasher::new())) + } else { + None + } }; let entry = op(&mut entry_builder, data); + + if let Some((ref mut hcx, ref mut hasher)) = entry_builder.hcx { + entry.hash_stable(hcx, hasher); + } + let entry = entry_builder.ecx.lazy(&entry); entry_builder.finish(id); self.items.record(id, entry); @@ -245,21 +261,28 @@ impl DepGraphRead for FromId { pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> { pub tcx: TyCtxt<'b, 'tcx, 'tcx>, ecx: &'a mut EncodeContext<'b, 'tcx>, - hasher: StableHasher, - hcx: StableHashingContext<'b, 'tcx>, + hcx: Option<(StableHashingContext<'b, 'tcx>, StableHasher)>, } impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { pub fn finish(self, def_id: DefId) { - let hash = self.hasher.finish(); - self.ecx.metadata_hashes.push((def_id.index, hash)); + if let Some((_, hasher)) = self.hcx { + let hash = hasher.finish(); + self.ecx.metadata_hashes.push(EncodedMetadataHash { + def_index: def_id.index, + hash: hash, + }); + } } pub fn lazy(&mut self, value: &T) -> Lazy where T: Encodable + HashStable> { - value.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + value.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy(value) } @@ -267,22 +290,58 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { where I: IntoIterator, T: Encodable + HashStable> { - let items: Vec = iter.into_iter().collect(); - items.hash_stable(&mut self.hcx, &mut self.hasher); - self.ecx.lazy_seq(items) + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + let iter = iter.into_iter(); + let (lower_bound, upper_bound) = iter.size_hint(); + + if upper_bound == Some(lower_bound) { + lower_bound.hash_stable(hcx, hasher); + let mut num_items_hashed = 0; + let ret = self.ecx.lazy_seq(iter.inspect(|item| { + item.hash_stable(hcx, hasher); + num_items_hashed += 1; + })); + + // Sometimes items in a sequence are filtered out without being + // hashed (e.g. for &[ast::Attribute]) and this code path cannot + // handle that correctly, so we want to make sure we didn't hit + // it by accident. + if lower_bound != num_items_hashed { + bug!("Hashed a different number of items ({}) than expected ({})", + num_items_hashed, + lower_bound); + } + debug!("metadata-hash: {:?}", hasher); + ret + } else { + // Collect into a vec so we know the length of the sequence + let items: AccumulateVec<[T; 32]> = iter.collect(); + items.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + self.ecx.lazy_seq(items) + } + } else { + self.ecx.lazy_seq(iter) + } } pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq where T: Encodable + HashStable> { - slice.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + slice.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy_seq_ref(slice.iter()) } pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq where T: Encodable + HashStable> { - slice.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + slice.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 6ffa31c072709..53d6a9ec10df2 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,6 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::ich::StableHashingContext; use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; @@ -27,6 +28,7 @@ use syntax::symbol::Symbol; use syntax_pos::{self, Span}; use std::marker::PhantomData; +use std::mem; use rustc_data_structures::stable_hasher::{StableHasher, HashStable, StableHasherResult}; @@ -107,8 +109,8 @@ impl HashStable for Lazy { fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. } } @@ -164,8 +166,8 @@ impl HashStable for LazySeq { fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. } } @@ -240,6 +242,23 @@ pub struct Entry<'tcx> { pub mir: Option>>, } +impl_stable_hash_for!(struct Entry<'tcx> { + kind, + visibility, + span, + attributes, + children, + stability, + deprecation, + ty, + inherent_impls, + variances, + generics, + predicates, + ast, + mir +}); + #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum EntryKind<'tcx> { Const(u8), @@ -267,6 +286,69 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer, u8), } +impl<'a, 'tcx> HashStable> for EntryKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + EntryKind::ImmStatic | + EntryKind::MutStatic | + EntryKind::ForeignImmStatic | + EntryKind::ForeignMutStatic | + EntryKind::ForeignMod | + EntryKind::Field | + EntryKind::Type => { + // Nothing else to hash here. + } + EntryKind::Const(qualif) => { + qualif.hash_stable(hcx, hasher); + } + EntryKind::Enum(ref repr_options) => { + repr_options.hash_stable(hcx, hasher); + } + EntryKind::Variant(ref variant_data) => { + variant_data.hash_stable(hcx, hasher); + } + EntryKind::Struct(ref variant_data, ref repr_options) | + EntryKind::Union(ref variant_data, ref repr_options) => { + variant_data.hash_stable(hcx, hasher); + repr_options.hash_stable(hcx, hasher); + } + EntryKind::Fn(ref fn_data) | + EntryKind::ForeignFn(ref fn_data) => { + fn_data.hash_stable(hcx, hasher); + } + EntryKind::Mod(ref mod_data) => { + mod_data.hash_stable(hcx, hasher); + } + EntryKind::MacroDef(ref macro_def) => { + macro_def.hash_stable(hcx, hasher); + } + EntryKind::Closure(closure_data) => { + closure_data.hash_stable(hcx, hasher); + } + EntryKind::Trait(ref trait_data) => { + trait_data.hash_stable(hcx, hasher); + } + EntryKind::DefaultImpl(ref impl_data) | + EntryKind::Impl(ref impl_data) => { + impl_data.hash_stable(hcx, hasher); + } + EntryKind::Method(ref method_data) => { + method_data.hash_stable(hcx, hasher); + } + EntryKind::AssociatedType(associated_container) => { + associated_container.hash_stable(hcx, hasher); + } + EntryKind::AssociatedConst(associated_container, qualif) => { + associated_container.hash_stable(hcx, hasher); + qualif.hash_stable(hcx, hasher); + } + } + } +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq, diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 66380079a8b29..0ffa7a79408e1 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -443,7 +443,10 @@ fn archive_config<'a>(sess: &'a Session, } fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) { - let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata)); + let result = fs::File::create(out_filename).and_then(|mut f| { + f.write_all(&trans.metadata.raw_data) + }); + if let Err(e) = result { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 574b345218be9..f76e816bcf0c9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -36,6 +36,7 @@ use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; +use middle::cstore::EncodedMetadata; use rustc::ty::{self, Ty, TyCtxt}; use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; @@ -724,7 +725,8 @@ fn contains_null(s: &str) -> bool { } fn write_metadata(cx: &SharedCrateContext, - exported_symbols: &NodeSet) -> Vec { + exported_symbols: &NodeSet) + -> EncodedMetadata { use flate; #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -748,7 +750,10 @@ fn write_metadata(cx: &SharedCrateContext, }).max().unwrap(); if kind == MetadataKind::None { - return Vec::new(); + return EncodedMetadata { + raw_data: vec![], + hashes: vec![], + }; } let cstore = &cx.tcx().sess.cstore; @@ -761,7 +766,7 @@ fn write_metadata(cx: &SharedCrateContext, assert!(kind == MetadataKind::Compressed); let mut compressed = cstore.metadata_encoding_version().to_vec(); - compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); + compressed.extend_from_slice(&flate::deflate_bytes(&metadata.raw_data)); let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 5c3b17c889760..628d46f8e7059 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -168,7 +168,7 @@ pub struct CrateTranslation { pub modules: Vec, pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, - pub metadata: Vec, + pub metadata: middle::cstore::EncodedMetadata, pub exported_symbols: back::symbol_export::ExportedSymbols, pub no_builtins: bool, pub windows_subsystem: Option, diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 048ccb529a24f..37c6ef58f5e56 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -38,8 +38,13 @@ enum EnumVisibility { A } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -pub enum EnumVisibility { A } +pub enum EnumVisibility { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + A +} @@ -56,7 +61,10 @@ enum EnumChangeNameCStyleVariant { #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeNameCStyleVariant { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] Variant1, + #[rustc_metadata_clean(cfg="cfail3")] Variant2Changed, } @@ -259,10 +267,13 @@ enum EnumChangeFieldTypeTupleStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeTupleStyleVariant { - Variant1(u32, u64), + Variant1(u32, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u64), } @@ -277,11 +288,16 @@ enum EnumChangeFieldTypeStructStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, - Variant2 { a: u32, b: u64 }, + Variant2 { + a: u32, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + b: u64 + }, } @@ -312,10 +328,16 @@ enum EnumChangeOrderTupleStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeOrderTupleStyleVariant { - Variant1(u64, u32), + Variant1( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u64, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u32), } @@ -611,11 +633,23 @@ enum EnumSwapUsageTypeParameters { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageTypeParameters { - Variant1 { a: B }, - Variant2 { a: A }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: B + }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant2 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: A + }, } @@ -630,11 +664,23 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { - Variant1 { a: &'b u32 }, - Variant2 { b: &'a u32 }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: &'b u32 + }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant2 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + b: &'a u32 + }, } @@ -653,10 +699,16 @@ mod change_field_type_indirectly_tuple_style { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum TupleStyle { - Variant1(FieldType) + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + FieldType + ) } } @@ -671,10 +723,16 @@ mod change_field_type_indirectly_struct_style { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum StructStyle { - Variant1 { a: FieldType } + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: FieldType + } } } diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 03e621fedbeb4..1d26e6c07d15b 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -53,9 +53,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_parameter_name(d: i64) -> i32; } @@ -70,9 +72,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_parameter_type(c: i32) -> i32; } @@ -87,9 +91,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_return_type(c: i32) -> i8; } @@ -104,9 +110,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn add_parameter(c: i32, d: i32) -> i32; } @@ -121,9 +129,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn add_return_type(c: i32) -> i32; } @@ -138,9 +148,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn make_function_variadic(c: i32, ...); } @@ -155,9 +167,11 @@ extern "C" { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern "rust-call" { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_calling_convention(c: i32); } @@ -172,9 +186,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn make_function_public(c: i32); } @@ -246,9 +262,11 @@ mod indirectly_change_parameter_type { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn indirectly_change_parameter_type(c: c_int); } } @@ -264,9 +282,11 @@ mod indirectly_change_return_type { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn indirectly_change_return_type() -> c_int; } } diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 93d94cd1a19c4..2fe3f0d5d1fe0 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -50,7 +50,7 @@ fn add_return_type() {} #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] // The type doesn't change, so metadata is the same #[rustc_metadata_clean(cfg="cfail3")] fn add_return_type() -> () {} @@ -154,7 +154,7 @@ fn lifetime_parameter() {} #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +// #[rustc_metadata_dirty(cfg="cfail2")] -- Unused lifetime params don't show up in the type? #[rustc_metadata_clean(cfg="cfail3")] fn lifetime_parameter<'a>() {} @@ -315,16 +315,16 @@ fn return_impl_trait() -> impl Clone { #[cfg(cfail1)] fn change_return_impl_trait() -> impl Clone { - 0 + 0u32 } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] // The actual type is the same, so: clean #[rustc_metadata_clean(cfg="cfail3")] fn change_return_impl_trait() -> impl Copy { - 0 + 0u32 } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index fd9ac61046e3a..899aefa24a033 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -107,7 +107,7 @@ impl Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -126,7 +126,7 @@ impl Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -171,7 +171,7 @@ impl Foo { impl Foo { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_method_to_impl1(&self) { } @@ -219,9 +219,7 @@ impl Foo { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] - // At the moment we explicitly ignore argument names in metadata, since they - // are not used in downstream crates (except in rustdoc) - #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_name(&self, b: i64) { } } @@ -287,9 +285,7 @@ impl Foo { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] - // At the moment we explicitly ignore argument names in metadata, since they - // are not used in downstream crates (except in rustdoc) - #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } } @@ -373,7 +369,7 @@ impl Foo { impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type. #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -544,7 +540,7 @@ impl Bar { impl Bar { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_impl_parameter(&self) { } } @@ -565,7 +561,7 @@ impl Bar { impl Bar { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_trait_bound_to_impl_parameter(&self) { } } diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index 2d79987823f20..17a5dc1678367 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -62,9 +62,13 @@ struct TupleStructFieldType(i32); #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct TupleStructFieldType(u32); +struct TupleStructFieldType( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u32 +); // Tuple Struct Add Field ------------------------------------------------------ @@ -77,7 +81,13 @@ struct TupleStructAddField(i32); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct TupleStructAddField(i32, u32); +struct TupleStructAddField( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + i32, + #[rustc_metadata_clean(cfg="cfail3")] + u32 +); // Tuple Struct Field Visibility ----------------------------------------------- @@ -101,9 +111,13 @@ struct RecordStructFieldType { x: f32 } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructFieldType { x: u64 } +struct RecordStructFieldType { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + x: u64 +} // Record Struct Field Name ---------------------------------------------------- @@ -129,7 +143,12 @@ struct RecordStructAddField { x: f32 } #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructAddField { x: f32, y: () } +struct RecordStructAddField { + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + x: f32, + #[rustc_metadata_clean(cfg="cfail3")] + y: () } // Record Struct Field Visibility ---------------------------------------------- @@ -142,7 +161,11 @@ struct RecordStructFieldVisibility { x: f32 } #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructFieldVisibility { pub x: f32 } +struct RecordStructFieldVisibility { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub x: f32 +} // Add Lifetime Parameter ------------------------------------------------------ @@ -168,7 +191,14 @@ struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddLifetimeParameterBound<'a, 'b: 'a>(&'a f32, &'b f64); +struct AddLifetimeParameterBound<'a, 'b: 'a>( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'a f32, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'b f64 +); #[cfg(cfail1)] struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); @@ -178,7 +208,13 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64) +struct AddLifetimeParameterBoundWhereClause<'a, 'b>( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'a f32, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'b f64) where 'b: 'a; @@ -192,7 +228,16 @@ struct AddTypeParameter(T1, T1); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameter(T1, T2); +struct AddTypeParameter( + // The field contains the parent's Generics, so it's dirty even though its + // type hasn't changed. + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T1, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T2 +); // Add Type Parameter Bound ---------------------------------------------------- @@ -205,7 +250,11 @@ struct AddTypeParameterBound(T); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameterBound(T); +struct AddTypeParameterBound( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T +); #[cfg(cfail1)] @@ -216,7 +265,11 @@ struct AddTypeParameterBoundWhereClause(T); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameterBoundWhereClause(T) where T: Sync; +struct AddTypeParameterBoundWhereClause( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T +) where T: Sync; // Empty struct ---------------------------------------------------------------- @@ -234,6 +287,7 @@ struct Visibility; #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub struct Visibility; @@ -252,9 +306,13 @@ mod tuple_struct_change_field_type_indirectly { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - struct TupleStruct(FieldType); + struct TupleStruct( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + FieldType + ); } @@ -267,9 +325,11 @@ mod record_struct_change_field_type_indirectly { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] struct RecordStruct { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] _x: FieldType } } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 94698506ec53f..61a2be054a51a 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -100,7 +100,7 @@ trait TraitAddReturnType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -121,7 +121,7 @@ trait TraitChangeReturnType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -142,7 +142,7 @@ trait TraitAddParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -164,7 +164,7 @@ trait TraitChangeMethodParameterName { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. @@ -194,7 +194,7 @@ trait TraitChangeMethodParameterType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -215,7 +215,7 @@ trait TraitChangeMethodParameterTypeRef { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterTypeRef { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -236,7 +236,7 @@ trait TraitChangeMethodParametersOrder { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParametersOrder { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -257,9 +257,13 @@ trait TraitAddMethodDefaultImplementation { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddMethodDefaultImplementation { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] fn method() { } } @@ -293,7 +297,7 @@ trait TraitChangeModeSelfRefToMut { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeModeSelfRefToMut { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -335,7 +339,7 @@ trait TraitChangeModeSelfOwnToRef { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeModeSelfOwnToRef { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -356,7 +360,7 @@ trait TraitAddUnsafeModifier { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddUnsafeModifier { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -377,7 +381,7 @@ trait TraitAddExternModifier { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddExternModifier { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -398,7 +402,7 @@ trait TraitChangeExternCToRustIntrinsic { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeExternCToRustIntrinsic { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -419,7 +423,7 @@ trait TraitAddTypeParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddTypeParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -440,12 +444,12 @@ trait TraitAddLifetimeParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddLifetimeParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] // Unused lifetimes don't seem to show up in type? #[rustc_metadata_clean(cfg="cfail3")] fn method<'a>(); } @@ -465,7 +469,7 @@ trait TraitAddTraitBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddTraitBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -486,7 +490,7 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddBuiltinBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -507,7 +511,7 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -528,7 +532,7 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondTraitBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -549,7 +553,7 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -570,7 +574,7 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -585,7 +589,12 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { // Add associated type ------------------------------------------------------------ #[cfg(cfail1)] trait TraitAddAssociatedType { - fn mathod(); + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } #[cfg(not(cfail1))] @@ -596,7 +605,7 @@ trait TraitAddAssociatedType { trait TraitAddAssociatedType { type Associated; - fn mathod(); + fn method(); } @@ -606,9 +615,12 @@ trait TraitAddAssociatedType { trait TraitAddTraitBoundToAssociatedType { type Associated; - fn mathod(); + fn method(); } + +// Apparently the type bound contributes to the predicates of the trait, but +// does not change the associated item itself. #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] @@ -617,11 +629,11 @@ trait TraitAddTraitBoundToAssociatedType { trait TraitAddTraitBoundToAssociatedType { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type Associated: ReferencedTrait0; - fn mathod(); + fn method(); } @@ -631,7 +643,7 @@ trait TraitAddTraitBoundToAssociatedType { trait TraitAddLifetimeBoundToAssociatedType<'a> { type Associated; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] @@ -642,11 +654,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type Associated: 'a; - fn mathod(); + fn method(); } @@ -656,18 +668,22 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { trait TraitAddDefaultToAssociatedType { type Associated; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddDefaultToAssociatedType { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] type Associated = ReferenceType0; - fn mathod(); + fn method(); } @@ -675,7 +691,7 @@ trait TraitAddDefaultToAssociatedType { // Add associated constant -------------------------------------------------------- #[cfg(cfail1)] trait TraitAddAssociatedConstant { - fn mathod(); + fn method(); } #[cfg(not(cfail1))] @@ -686,7 +702,7 @@ trait TraitAddAssociatedConstant { trait TraitAddAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } @@ -696,18 +712,26 @@ trait TraitAddAssociatedConstant { trait TraitAddInitializerToAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddInitializerToAssociatedConstant { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] const Value: u32 = 1; - fn mathod(); + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } @@ -717,13 +741,13 @@ trait TraitAddInitializerToAssociatedConstant { trait TraitChangeTypeOfAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeTypeOfAssociatedConstant { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -732,7 +756,11 @@ trait TraitChangeTypeOfAssociatedConstant { #[rustc_metadata_clean(cfg="cfail3")] const Value: f64; - fn mathod(); + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } @@ -1111,9 +1139,6 @@ trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } - -// EDIT: Some more cases ---------------------------------------------------------- - // Change return type of method indirectly by modifying a use statement------------ mod change_return_type_of_method_indirectly_use { #[cfg(cfail1)] @@ -1123,7 +1148,7 @@ mod change_return_type_of_method_indirectly_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1145,7 +1170,7 @@ mod change_method_parameter_type_indirectly_by_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeArgType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1167,7 +1192,7 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1190,7 +1215,7 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameterWhere { #[rustc_dirty(label="Hir", cfg="cfail2")] diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index 30e376f04fb87..06c8eb6a878f0 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -120,7 +120,7 @@ impl ChangeMethodBodyTraitInlined for Foo { #[rustc_metadata_clean(cfg="cfail3")] #[inline] fn method_name() { - () + panic!() } } @@ -144,7 +144,7 @@ pub trait ChangeMethodSelfnessTrait { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -176,16 +176,14 @@ pub trait RemoveMethodSelfnessTrait { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn method_name() { - () - } + fn method_name() {} } // Change Method Selfmutness ----------------------------------------------------------- @@ -208,16 +206,14 @@ pub trait ChangeMethodSelfmutnessTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeMethodSelfmutnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn method_name(&mut self) { - () - } + fn method_name(&mut self) {} } // Change item kind ----------------------------------------------------------- @@ -317,16 +313,20 @@ impl ChangeHasValueTrait for Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub trait ChangeHasValueTrait { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] fn method_name() { } } #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeHasValueTrait for Foo { fn method_name() { } @@ -346,32 +346,16 @@ impl AddDefaultTrait for Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl AddDefaultTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] default fn method_name() { } } -// Remove default - -pub trait RemoveDefaultTrait { - fn method_name(); -} - -#[cfg(cfail1)] -impl RemoveDefaultTrait for Foo { - default fn method_name() { } -} - -#[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] -#[rustc_metadata_clean(cfg="cfail3")] -impl RemoveDefaultTrait for Foo { - fn method_name() { } -} - // Add arguments #[cfg(cfail1)] @@ -392,7 +376,7 @@ pub trait AddArgumentTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl AddArgumentTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -422,7 +406,7 @@ pub trait ChangeArgumentTypeTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeArgumentTypeTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -504,7 +488,7 @@ impl AddLifetimeBoundToImplParameter for T { impl AddLifetimeBoundToImplParameter for T { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn id(self) -> Self { self } } @@ -529,7 +513,7 @@ impl AddTraitBoundToImplParameter for T { impl AddTraitBoundToImplParameter for T { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn id(self) -> Self { self } } diff --git a/src/test/incremental/unchecked_dirty_clean_metadata.rs b/src/test/incremental/unchecked_dirty_clean_metadata.rs index 4017b4d4ba9ae..917c2c9dbce4f 100644 --- a/src/test/incremental/unchecked_dirty_clean_metadata.rs +++ b/src/test/incremental/unchecked_dirty_clean_metadata.rs @@ -33,13 +33,3 @@ fn main() { } } -struct _Struct { - #[rustc_metadata_dirty(cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute - _field1: i32, - - #[rustc_metadata_clean(cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute - _field2: i32, -} - From 71a9e106690627e657a466938e578608d8bcd04a Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 12 Apr 2017 22:51:32 +0800 Subject: [PATCH 655/662] Fixed invalid 128-bit division on 32-bit target. Fixed issue #41228. Added test cases to cover all special-cased branches of udivmodti4. --- src/libcompiler_builtins/lib.rs | 2 +- src/test/run-pass/i128.rs | 5 ++++ src/test/run-pass/u128.rs | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 58aba11e4394f..09b3d63950705 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -180,7 +180,7 @@ pub mod reimpls { sr = sr.wrapping_add(1); // 1 <= sr <= u64::bits() - 1 - q = n.wrapping_shl(64u32.wrapping_sub(sr)); + q = n.wrapping_shl(128u32.wrapping_sub(sr)); r = n.wrapping_shr(sr); } else { if d.high() == 0 { diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index dc4f0774b9771..c5057f70c065a 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -104,4 +104,9 @@ fn main() { assert_eq!(l.checked_sub(l), Some(0)); assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127)); assert_eq!(o.checked_shl(b(128)), None); + + // https://github.com/rust-lang/rust/issues/41228 + assert_eq!(b(-87559967289969187895646876466835277875_i128) / + b(84285771033834995895337664386045050880_i128), + -1i128); } diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index ac3dfcdfde155..cfd616c56b4f0 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -77,4 +77,49 @@ fn main() { assert_eq!(o.checked_sub(b(18)), None); assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127)); assert_eq!(o.checked_shl(b(128)), None); + + // Test cases for all udivmodti4 branches. + // case "0X/0X" + assert_eq!(b(0x69545bd57727c050_u128) / + b(0x3283527a3350d88c_u128), + 2u128); + // case "0X/KX" + assert_eq!(b(0x0_8003c9c50b473ae6_u128) / + b(0x1_283e8838c30fa8f4_u128), + 0u128); + // case "K0/K0" + assert_eq!(b(0xc43f42a207978720_u128 << 64) / + b(0x098e62b74c23cf1a_u128 << 64), + 20u128); + // case "KK/K0" for power-of-two D. + assert_eq!(b(0xa9008fb6c9d81e42_0e25730562a601c8_u128) / + b(1u128 << 120), + 169u128); + // case "KK/K0" with N >= D (https://github.com/rust-lang/rust/issues/41228). + assert_eq!(b(0xe4d26e59f0640328_06da5b06efe83a41_u128) / + b(0x330fcb030ea4447c_u128 << 64), + 4u128); + assert_eq!(b(3u128 << 64 | 1) / + b(3u128 << 64), + 1u128); + // case "KK/K0" with N < D. + assert_eq!(b(0x6655c9fb66ca2884_e2d1dfd470158c62_u128) / + b(0xb35b667cab7e355b_u128 << 64), + 0u128); + // case "KX/0K" for power-of-two D. + assert_eq!(b(0x3e49dd84feb2df59_7b2f97d93a253969_u128) / + b(1u128 << 4), + 0x03e49dd84feb2df5_97b2f97d93a25396_u128); + // case "KX/0K" in general. + assert_eq!(b(0x299692b3a1dae5bd_6162e6f489d2620e_u128) / + b(0x900b6f027571d6f7_u128), + 0x49e95f54b0442578_u128); + // case "KX/KK" with N >= D. + assert_eq!(b(0xc7b889180b67b07d_bc1a3c88783d35b5_u128) / + b(0x1d7e69f53160b9e2_60074771e852f244_u128), + 6u128); + // case "KX/KK" with N < D. + assert_eq!(b(0x679289ac23bb334f_36144401cf882172_u128) / + b(0x7b0b271b64865f05_f54a7b72746c062f_u128), + 0u128); } From fa437f49af90e1a78771f2262d51ddd01b668199 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 12:36:43 -0400 Subject: [PATCH 656/662] do not consult union-find during `fudge_regions_if_ok` --- src/librustc/infer/fudge.rs | 16 ++++------------ src/librustc/infer/type_variable.rs | 14 +++----------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index ab0ff32dcc3ec..72b23a3bc181c 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -135,19 +135,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { ty } - Some(info) => { + Some(&origin) => { // This variable was created during the - // fudging; it was mapped the root - // `root_vid`. There are now two - // possibilities: either the root was creating - // during the fudging too, in which case we - // want a fresh variable, or it was not, in - // which case we can return it. - if self.type_variables.contains_key(&info.root_vid) { - self.infcx.next_ty_var(info.root_origin) - } else { - self.infcx.tcx.mk_var(info.root_vid) - } + // fudging. Recreate it with a fresh variable + // here. + self.infcx.next_ty_var(origin) } } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index a32404c1ac515..34bb9feb5c921 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -67,12 +67,7 @@ pub enum TypeVariableOrigin { Generalized(ty::TyVid), } -pub type TypeVariableMap = FxHashMap; - -pub struct TypeVariableInfo { - pub root_vid: ty::TyVid, - pub root_origin: TypeVariableOrigin, -} +pub type TypeVariableMap = FxHashMap; struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, @@ -294,8 +289,6 @@ impl<'tcx> TypeVariableTable<'tcx> { /// along with their origin. pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); - let eq_relations = &mut self.eq_relations; - let values = &self.values; actions_since_snapshot .iter() @@ -304,9 +297,8 @@ impl<'tcx> TypeVariableTable<'tcx> { _ => None, }) .map(|vid| { - let root_vid = eq_relations.find(vid); - let root_origin = values.get(vid.index as usize).origin.clone(); - (vid, TypeVariableInfo { root_vid, root_origin }) + let origin = self.values.get(vid.index as usize).origin.clone(); + (vid, origin) }) .collect() } From 1cc7621dec567ded8965fd6c01d80104cfec4d68 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 12:51:19 -0400 Subject: [PATCH 657/662] simplify code to remove now unused "stack" and fix comments --- src/librustc/infer/combine.rs | 139 ++++++++++------------------ src/librustc/infer/type_variable.rs | 7 +- 2 files changed, 54 insertions(+), 92 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 03ed654e3cce4..b73079b02bdd9 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -47,7 +47,6 @@ use ty::relate::{RelateResult, TypeRelation}; use traits::PredicateObligations; use syntax::ast; -use syntax::util::small_vector::SmallVector; use syntax_pos::Span; #[derive(Clone)] @@ -174,6 +173,15 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Glb::new(self, a_is_expected) } + /// Here dir is either EqTo, SubtypeOf, or SupertypeOf. The + /// idea is that we should ensure that the type `a_ty` is equal + /// to, a subtype of, or a supertype of (respectively) the type + /// to which `b_vid` is bound. + /// + /// Since `b_vid` has not yet been instantiated with a type, we + /// will first instantiate `b_vid` with a *generalized* version + /// of `a_ty`. Generalization introduces other inference + /// variables wherever subtyping could occur. pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, @@ -183,92 +191,49 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { { use self::RelationDir::*; - // We use SmallVector here instead of Vec because this code is hot and - // it's rare that the stack length exceeds 1. - let mut stack = SmallVector::new(); - stack.push((a_ty, dir, b_vid)); - loop { - // For each turn of the loop, we extract a tuple - // - // (a_ty, dir, b_vid) - // - // to relate. Here dir is either SubtypeOf or - // SupertypeOf. The idea is that we should ensure that - // the type `a_ty` is a subtype or supertype (respectively) of the - // type to which `b_vid` is bound. - // - // If `b_vid` has not yet been instantiated with a type - // (which is always true on the first iteration, but not - // necessarily true on later iterations), we will first - // instantiate `b_vid` with a *generalized* version of - // `a_ty`. Generalization introduces other inference - // variables wherever subtyping could occur (at time of - // this writing, this means replacing free regions with - // region variables). - let (a_ty, dir, b_vid) = match stack.pop() { - None => break, - Some(e) => e, - }; - // Get the actual variable that b_vid has been inferred to - let (b_vid, b_ty) = { - let mut variables = self.infcx.type_variables.borrow_mut(); - let b_vid = variables.root_var(b_vid); - (b_vid, variables.probe_root(b_vid)) - }; - - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", - a_ty, - dir, - b_vid); - - // Check whether `vid` has been instantiated yet. If not, - // make a generalized form of `ty` and instantiate with - // that. - // - // FIXME(#18653) -- we need to generalize nested type - // variables too. - let b_ty = match b_ty { - Some(t) => t, // ...already instantiated. - None => { // ...not yet instantiated: - // Generalize type if necessary. - let generalized_ty = match dir { - EqTo => self.generalize(a_ty, b_vid, false), - SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), - }?; - debug!("instantiate(a_ty={:?}, dir={:?}, \ - b_vid={:?}, generalized_ty={:?})", - a_ty, dir, b_vid, - generalized_ty); - self.infcx.type_variables - .borrow_mut() - .instantiate(b_vid, generalized_ty); - generalized_ty - } - }; - - // The original triple was `(a_ty, dir, b_vid)` -- now we have - // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`: - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - match dir { - EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), - SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( - ty::Contravariant, &a_ty, &b_ty), - }?; - } + // Get the actual variable that b_vid has been inferred to + debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_none()); + + debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); + + // Generalize type of `a_ty` appropriately depending on the + // direction. As an example, assume: + // + // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an + // inference variable, + // - and `dir` == `SubtypeOf`. + // + // Then the generalized form `b_ty` would be `&'?2 ?3`, where + // `'?2` and `?3` are fresh region/type inference + // variables. (Down below, we will relate `a_ty <: b_ty`, + // adding constraints like `'x: '?2` and `?1 <: ?3`.) + let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?; + debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", + a_ty, dir, b_vid, b_ty); + self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty); + + // Finally, relate `b_ty` to `a_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + match dir { + EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), + SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, &a_ty, &b_ty), + }?; Ok(()) } /// Attempts to generalize `ty` for the type variable `for_vid`. /// This checks for cycle -- that is, whether the type `ty` - /// references `for_vid`. If `make_region_vars` is true, it will - /// also replace all regions with fresh variables. Returns - /// `TyError` in the case of a cycle, `Ok` otherwise. + /// references `for_vid`. If `is_eq_relation` is false, it will + /// also replace all regions/unbound-type-variables with fresh + /// variables. Returns `TyError` in the case of a cycle, `Ok` + /// otherwise. /// /// Preconditions: /// @@ -276,16 +241,14 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { fn generalize(&self, ty: Ty<'tcx>, for_vid: ty::TyVid, - make_region_vars: bool) + is_eq_relation: bool) -> RelateResult<'tcx, Ty<'tcx>> { - debug_assert!(self.infcx.type_variables.borrow_mut().root_var(for_vid) == for_vid); - let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), - make_region_vars: make_region_vars, + is_eq_relation: is_eq_relation, cycle_detected: false }; let u = ty.fold_with(&mut generalize); @@ -301,7 +264,7 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, span: Span, for_vid_sub_root: ty::TyVid, - make_region_vars: bool, + is_eq_relation: bool, cycle_detected: bool, } @@ -332,7 +295,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx self.fold_ty(u) } None => { - if self.make_region_vars { + if !self.is_eq_relation { let origin = variables.origin(vid); let new_var_id = variables.new_var(false, origin, None); let u = self.tcx().mk_var(new_var_id); @@ -379,7 +342,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx ty::ReScope(..) | ty::ReVar(..) | ty::ReFree(..) => { - if !self.make_region_vars { + if self.is_eq_relation { return r; } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 34bb9feb5c921..4ae2a8026409d 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -151,11 +151,10 @@ impl<'tcx> TypeVariableTable<'tcx> { /// Instantiates `vid` with the type `ty`. /// - /// Precondition: `vid` must be a root in the unification table - /// and has not previously been instantiated. + /// Precondition: `vid` must not have been previously instantiated. pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { - debug_assert!(self.root_var(vid) == vid); - debug_assert!(self.probe(vid).is_none()); + let vid = self.root_var(vid); + debug_assert!(self.probe_root(vid).is_none()); let old_value = { let vid_data = &mut self.values[vid.index as usize]; From cb3c4d022a048d9c4d1306eaacd9b72303f1871a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:03:04 +0200 Subject: [PATCH 658/662] rustc_trans: don't emit ZST allocas that are only assigned to. --- src/librustc_trans/mir/analyze.rs | 3 +- src/librustc_trans/mir/mod.rs | 20 +++---------- src/librustc_trans/mir/operand.rs | 18 +++++++++++- src/librustc_trans/mir/rvalue.rs | 49 +++++++++++++++++-------------- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index a3968650043ba..889f9dc4cded5 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -19,7 +19,6 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; use super::MirContext; -use super::rvalue; pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let mir = mircx.mir; @@ -93,7 +92,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); - if !rvalue::rvalue_creates_operand(rvalue) { + if !self.cx.rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index); } } else { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c51e1fb002803..99d8cd594ecdd 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,17 +11,16 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; -use rustc::ty::TypeFoldable; use session::config::FullDebugInfo; use base; use builder::Builder; -use common::{self, CrateContext, C_null, Funclet}; +use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::{self, Instance}; use abi::FnType; @@ -171,23 +170,12 @@ enum LocalRef<'tcx> { impl<'tcx> LocalRef<'tcx> { fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) -> LocalRef<'tcx> { + ty: Ty<'tcx>) -> LocalRef<'tcx> { if common::type_is_zero_size(ccx, ty) { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - let llty = type_of::type_of(ccx, ty); - let val = if common::type_is_imm_pair(ccx, ty) { - let fields = llty.field_types(); - OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) - } else { - OperandValue::Immediate(C_null(llty)) - }; - let op = OperandRef { - val: val, - ty: ty - }; - LocalRef::Operand(Some(op)) + LocalRef::Operand(Some(OperandRef::new_zst(ccx, ty))) } else { LocalRef::Operand(None) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 771a88238b2b7..c31142323c85f 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; use base; -use common; +use common::{self, CrateContext, C_null}; use builder::Builder; use value::Value; use type_of; @@ -79,6 +79,22 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> { } impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) -> OperandRef<'tcx> { + assert!(common::type_is_zero_size(ccx, ty)); + let llty = type_of::type_of(ccx, ty); + let val = if common::type_is_imm_pair(ccx, ty) { + let fields = llty.field_types(); + OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) + } else { + OperandValue::Immediate(C_null(llty)) + }; + OperandRef { + val: val, + ty: ty + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 8f7cb914c4735..aa41720d717a7 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } _ => { - assert!(rvalue_creates_operand(rvalue)); + assert!(self.rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); bcx @@ -171,7 +171,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -466,8 +466,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - bug!("cannot generate operand from rvalue {:?}", rvalue); - + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + (bcx, OperandRef::new_zst(self.ccx, self.monomorphize(&ty))) } } } @@ -650,26 +652,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { OperandValue::Pair(val, of) } -} -pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { - match *rvalue { - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::Box(..) | - mir::Rvalue::Use(..) => // (*) - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => - false, - } + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::CheckedBinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | + mir::Rvalue::Box(..) | + mir::Rvalue::Use(..) => // (*) + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + let ty = self.monomorphize(&ty); + common::type_is_zero_size(self.ccx, ty) + } + } - // (*) this is only true if the type is suitable + // (*) this is only true if the type is suitable + } } #[derive(Copy, Clone)] From 9b5c577dbd45ff3b11f9d7aab6990cc1ee9194fb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:08:09 +0200 Subject: [PATCH 659/662] rustc_trans: avoid a separate entry BB if START_BLOCK has no backedges. --- src/librustc_trans/debuginfo/metadata.rs | 3 +- src/librustc_trans/mir/mod.rs | 17 +++++---- src/test/codegen/naked-functions.rs | 47 +++++++++++++++++++----- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ccb693aa41f4c..2d1c95114ebd6 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -784,7 +784,8 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, }; debug!("compile_unit_metadata: {:?}", compile_unit_name); - let producer = format!("rustc version {}", + // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. + let producer = format!("clang LLVM (rustc version {})", (option_env!("CFG_VERSION")).expect("CFG_VERSION")); let compile_unit_name = compile_unit_name.as_ptr(); diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 99d8cd594ecdd..3d8c5085462a8 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -195,15 +195,17 @@ pub fn trans_mir<'a, 'tcx: 'a>( debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir); - let bcx = Builder::new_block(ccx, llfn, "entry-block"); + let bcx = Builder::new_block(ccx, llfn, "start"); let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block + // Allocate a `Block` for every basic block, except + // the start block, if nothing loops back to it. + let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); let block_bcxs: IndexVec = mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - bcx.build_sibling_block("start").llbb() + if bb == mir::START_BLOCK && !reentrant_start_block { + bcx.llbb() } else { bcx.build_sibling_block(&format!("{:?}", bb)).llbb() } @@ -289,9 +291,10 @@ pub fn trans_mir<'a, 'tcx: 'a>( .collect() }; - // Branch to the START block - let start_bcx = mircx.blocks[mir::START_BLOCK]; - bcx.br(start_bcx); + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bcx.br(mircx.blocks[mir::START_BLOCK]); + } // Up until here, IR instructions for this function have explicitly not been annotated with // source code location, so we don't step into call setup code. From here on, source location diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 9de74f72005e3..9883ca6b35d04 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -20,7 +20,8 @@ #[no_mangle] #[naked] fn naked_empty() { - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret void } // CHECK: Function Attrs: naked uwtable @@ -28,9 +29,10 @@ fn naked_empty() { #[naked] // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) fn naked_with_args(a: isize) { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret void } // CHECK: Function Attrs: naked uwtable @@ -38,7 +40,8 @@ fn naked_with_args(a: isize) { #[no_mangle] #[naked] fn naked_with_return() -> isize { - // CHECK: ret i{{[0-9]+}} 0 + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret i{{[0-9]+}} 0 0 } @@ -47,9 +50,10 @@ fn naked_with_return() -> isize { #[no_mangle] #[naked] fn naked_with_args_and_return(a: isize) -> isize { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a } @@ -58,14 +62,37 @@ fn naked_with_args_and_return(a: isize) -> isize { #[no_mangle] #[naked] fn naked_recursive() { - // CHECK: call void @naked_empty() + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: call void @naked_empty() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb1 + // CHECK: bb1: + naked_empty(); - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb2 + // CHECK: bb2: + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb3 + // CHECK: bb3: + + // CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb4 + // CHECK: bb4: + naked_with_args( - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) naked_with_args_and_return( - // CHECK: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) naked_with_return() ) ); + // CHECK-NEXT: ret void } From 7ec27ae63d762234ad768fb605bd40bbbc52c7a0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 1 Apr 2017 19:33:45 -0700 Subject: [PATCH 660/662] Add ToOwned::clone_into (unstable as toowned_clone_into) to_owned generalizes clone; this generalizes clone_from. Use to_owned to give it a default impl. Customize the impl for [T], str, and T:Clone. Use it in Cow::clone_from to reuse resources when cloning Owned into Owned. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../unstable-book/src/toowned-clone-into.md | 7 ++++ src/libcollections/borrow.rs | 38 +++++++++++++++++++ src/libcollections/slice.rs | 13 +++++++ src/libcollections/str.rs | 6 +++ src/libcollections/tests/cow_str.rs | 10 +++++ src/libcollections/vec.rs | 11 +----- 7 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 src/doc/unstable-book/src/toowned-clone-into.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4e5..2e9810c438d0e 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -193,6 +193,7 @@ - [thread_local](thread-local.md) - [thread_local_internals](thread-local-internals.md) - [thread_local_state](thread-local-state.md) +- [toowned_clone_into](toowned-clone-into.md) - [trace_macros](trace-macros.md) - [trusted_len](trusted-len.md) - [try_from](try-from.md) diff --git a/src/doc/unstable-book/src/toowned-clone-into.md b/src/doc/unstable-book/src/toowned-clone-into.md new file mode 100644 index 0000000000000..eccc7e0e4dda0 --- /dev/null +++ b/src/doc/unstable-book/src/toowned-clone-into.md @@ -0,0 +1,7 @@ +# `toowned_clone_into` + +The tracking issue for this feature is: [#41263] + +[#41263]: https://github.com/rust-lang/rust/issues/41263 + +------------------------ diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 65056121f05a0..0de52b6696fcf 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -60,6 +60,29 @@ pub trait ToOwned { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn to_owned(&self) -> Self::Owned; + + /// Uses borrowed data to replace owned data, usually by cloning. + /// + /// This is borrow-generalized version of `Clone::clone_from`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(toowned_clone_into)] + /// let mut s: String = String::new(); + /// "hello".clone_into(&mut s); + /// + /// let mut v: Vec = Vec::new(); + /// [1, 2][..].clone_into(&mut v); + /// ``` + #[unstable(feature = "toowned_clone_into", + reason = "recently added", + issue = "41263")] + fn clone_into(&self, target: &mut Self::Owned) { + *target = self.to_owned(); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -70,6 +93,10 @@ impl ToOwned for T fn to_owned(&self) -> T { self.clone() } + + fn clone_into(&self, target: &mut T) { + target.clone_from(self); + } } /// A clone-on-write smart pointer. @@ -141,6 +168,17 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> } } } + + fn clone_from(&mut self, source: &Cow<'a, B>) { + if let Owned(ref mut dest) = *self { + if let Owned(ref o) = *source { + o.borrow().clone_into(dest); + return; + } + } + + *self = source.clone(); + } } impl<'a, B: ?Sized> Cow<'a, B> diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6cff315a6ccd9..f7e0f0395e7ff 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1527,6 +1527,19 @@ impl ToOwned for [T] { fn to_owned(&self) -> Vec { panic!("not available with cfg(test)") } + + fn clone_into(&self, target: &mut Vec) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + let len = target.len(); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(&self[..len]); + + // target.len <= self.len due to the truncate above, so the + // slice here is always in-bounds. + target.extend_from_slice(&self[len..]); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b5572..8d4b3a247e294 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -199,6 +199,12 @@ impl ToOwned for str { fn to_owned(&self) -> String { unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) } } + + fn clone_into(&self, target: &mut String) { + let mut b = mem::replace(target, String::new()).into_bytes(); + self.as_bytes().clone_into(&mut b); + *target = unsafe { String::from_utf8_unchecked(b) } + } } /// Methods for string slices. diff --git a/src/libcollections/tests/cow_str.rs b/src/libcollections/tests/cow_str.rs index b29245121daad..aa87ee84b3e97 100644 --- a/src/libcollections/tests/cow_str.rs +++ b/src/libcollections/tests/cow_str.rs @@ -139,3 +139,13 @@ fn check_cow_add_assign_str() { assert_eq!("Hi, World!", owned); assert_eq!("Hello, World!", borrowed); } + +#[test] +fn check_cow_clone_from() { + let mut c1: Cow = Cow::Owned(String::with_capacity(25)); + let s: String = "hi".to_string(); + assert!(s.capacity() < 25); + let c2: Cow = Cow::Owned(s); + c1.clone_from(&c2); + assert!(c1.into_owned().capacity() >= 25); +} \ No newline at end of file diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c258ac2bdea9b..3d11b4f80fb63 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1396,16 +1396,7 @@ impl Clone for Vec { } fn clone_from(&mut self, other: &Vec) { - // drop anything in self that will not be overwritten - self.truncate(other.len()); - let len = self.len(); - - // reuse the contained values' allocations/resources. - self.clone_from_slice(&other[..len]); - - // self.len <= other.len due to the truncate above, so the - // slice here is always in-bounds. - self.extend_from_slice(&other[len..]); + other.as_slice().clone_into(self); } } From f84cc0c0d0ff24e4cce5d05be3afd0347eb9d012 Mon Sep 17 00:00:00 2001 From: projektir Date: Wed, 12 Apr 2017 21:33:49 -0400 Subject: [PATCH 661/662] Updating docs for std::rc::Rc --- src/liballoc/rc.rs | 66 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 561ccaa5ef5ca..fed718e9be4c6 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -922,18 +922,29 @@ impl From for Rc { } } -/// A weak version of [`Rc`][rc]. +/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Rc`]`>`. /// -/// `Weak` pointers do not count towards determining if the inner value -/// should be dropped. +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. /// -/// The typical way to obtain a `Weak` pointer is to call -/// [`Rc::downgrade`][downgrade]. +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Rc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Rc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. /// -/// See the [module-level documentation](./index.html) for more details. +/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. /// -/// [rc]: struct.Rc.html -/// [downgrade]: struct.Rc.html#method.downgrade +/// [`Rc`]: struct.Rc.html +/// [`Rc::downgrade`]: struct.Rc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -948,14 +959,11 @@ impl !marker::Sync for Weak {} impl, U: ?Sized> CoerceUnsized> for Weak {} impl Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. - /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -980,13 +988,13 @@ impl Weak { } impl Weak { - /// Upgrades the `Weak` pointer to an [`Rc`][rc], if possible. + /// Attempts to upgrade the `Weak` pointer to an [`Rc`], extending + /// the lifetime of the value if successful. /// - /// Returns [`None`][option] if the strong count has reached zero and the - /// inner value was destroyed. + /// Returns [`None`] if the value has since been dropped. /// - /// [rc]: struct.Rc.html - /// [option]: ../../std/option/enum.Option.html + /// [`Rc`]: struct.Rc.html + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -1021,8 +1029,6 @@ impl Weak { impl Drop for Weak { /// Drops the `Weak` pointer. /// - /// This will decrement the weak reference count. - /// /// # Examples /// /// ``` @@ -1061,10 +1067,7 @@ impl Drop for Weak { #[stable(feature = "rc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// weak reference count. + /// Makes a clone of the `Weak` pointer that points to the same value. /// /// # Examples /// @@ -1091,14 +1094,11 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. - /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// From cdedecb7baa55a7e9c1aa78d5d7313b94e3e84b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 12 Apr 2017 20:48:18 -0700 Subject: [PATCH 662/662] travis: Enable rust-analysis package for more targets This commit enables the `rust-analysis` package to be produced for all targets that are part of the `dist-*` suite of docker images on Travis. Currently these packages are showing up with `available = false` in the `channel-rust-nightly.toml` manifest where we'd prefer to have them show up for all targets. Unfortunately rustup isn't handling the `available = false` section well right now, so this should also inadvertently fix the nightly regression. --- src/bootstrap/step.rs | 1 + src/ci/docker/cross/Dockerfile | 1 + src/ci/docker/dist-android/Dockerfile | 1 + src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 3 ++- src/ci/docker/dist-x86_64-musl/Dockerfile | 3 ++- 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 596cbcf01bb80..bdc2a30663cbb 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -700,6 +700,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("dist-analysis", "analysis") + .default(build.config.extended) .dep(|s| s.name("dist-std")) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 7c1984410078f..02d4eaf534acd 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -74,6 +74,7 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ ENV STAGING_DIR=/tmp ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ --target=$TARGETS \ --musl-root-arm=/usr/local/arm-linux-musleabi \ --musl-root-armhf=/usr/local/arm-linux-musleabihf \ diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 31f4b8b777be5..99c176aa820c7 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -42,6 +42,7 @@ ENV TARGETS=$TARGETS,armv7-linux-androideabi ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ + --enable-extended \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index 4a401bbb3031f..294460ed7604e 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -44,5 +44,5 @@ ENV \ ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia -ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index d2727cbdb3508..1ef3e569cb4bf 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -31,7 +31,8 @@ RUN curl -o /usr/local/bin/sccache \ ENV RUST_CONFIGURE_ARGS \ --target=i686-unknown-linux-musl,i586-unknown-linux-gnu \ - --musl-root-i686=/musl-i686 + --musl-root-i686=/musl-i686 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index a41c0cca3b5f0..f462ccbb9119a 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -31,7 +31,8 @@ RUN curl -o /usr/local/bin/sccache \ ENV RUST_CONFIGURE_ARGS \ --target=x86_64-unknown-linux-musl \ - --musl-root-x86_64=/musl-x86_64 + --musl-root-x86_64=/musl-x86_64 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our