From 59435072f58e1d622e1664f0a7e44830891c958f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 2 May 2016 18:51:24 -0500 Subject: [PATCH 001/150] fix built-in target detection previously the logic was accepting wrong triples (like `x86_64_unknown-linux-musl`) as valid ones (like `x86_64-unknown-linux-musl`) if they contained an underscore instead of a dash. fixes #33329 --- src/librustc_back/target/mod.rs | 3 +-- src/test/run-make/issue-33329/Makefile | 3 +++ src/test/run-make/issue-33329/main.rs | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/test/run-make/issue-33329/Makefile create mode 100644 src/test/run-make/issue-33329/main.rs diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 3f75201aad2cc..a13a94e12e5d6 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -71,10 +71,9 @@ macro_rules! supported_targets { // this would use a match if stringify! were allowed in pattern position fn load_specific(target: &str) -> Option { - let target = target.replace("-", "_"); if false { } $( - else if target == stringify!($module) { + else if target == $triple { let mut t = $module::target(); t.options.is_builtin = true; debug!("Got builtin target: {:?}", t); diff --git a/src/test/run-make/issue-33329/Makefile b/src/test/run-make/issue-33329/Makefile new file mode 100644 index 0000000000000..cd00ebc2d0a67 --- /dev/null +++ b/src/test/run-make/issue-33329/Makefile @@ -0,0 +1,3 @@ +all: + $(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | \ + grep "error: Error loading target specification: Could not find specification for target" diff --git a/src/test/run-make/issue-33329/main.rs b/src/test/run-make/issue-33329/main.rs new file mode 100644 index 0000000000000..e06c0a5ec2a4c --- /dev/null +++ b/src/test/run-make/issue-33329/main.rs @@ -0,0 +1,11 @@ +// 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 main() {} From ec616d584676e5083c68ed1367b94e9e824d8945 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 4 May 2016 22:15:47 -0500 Subject: [PATCH 002/150] refactor: if -> match --- src/librustc_back/target/mod.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index a13a94e12e5d6..d7c68d9f2a98d 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -69,19 +69,18 @@ macro_rules! supported_targets { /// List of supported targets pub const TARGETS: &'static [&'static str] = &[$($triple),*]; - // this would use a match if stringify! were allowed in pattern position fn load_specific(target: &str) -> Option { - if false { } - $( - else if target == $triple { - let mut t = $module::target(); - t.options.is_builtin = true; - debug!("Got builtin target: {:?}", t); - return Some(t); - } - )* - - None + match target { + $( + $triple => { + let mut t = $module::target(); + t.options.is_builtin = true; + debug!("Got builtin target: {:?}", t); + Some(t) + }, + )+ + _ => None + } } ) } From dbe6a09a8b8ab8c2c2b422df1e10db8306b1a481 Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 24 Jun 2016 15:27:22 -0700 Subject: [PATCH 003/150] First commit, fix ABI string docs in reference.md --- src/doc/reference.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index fb8ea0f5661d3..d564b19e1001c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1631,14 +1631,41 @@ the Rust ABI and the foreign ABI. A number of [attributes](#ffi-attributes) control the behavior of external blocks. By default external blocks assume that the library they are calling uses the -standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as -shown here: +standard C ABI on the specific platform. Other ABIs may be specified using an +`abi` string, as shown here: ```ignore // Interface to the Windows API extern "stdcall" { } ``` +There are three ABI strings which are cross-platform, and which all compilers +are guaranteed to support: + +* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any + Rust code. +* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default + your C compiler supports. +* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in + which case it's `"stdcall"`, or what you should use to link to the Windows API + itself + +There are also some platform-specific ABI strings: + +* `extern "cdecl"` -- The default for x86\_32 C code. +* `extern "stdcall"` -- The default for the Win32 API on x86\_32. +* `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "aapcs"` -- The default for ARM. +* `extern "fastcall"` +* `extern "vectorcall"` + +Finally, there are some rustc-specific ABI strings: + +* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics. +* `extern "rust-call"` -- The ABI of the Fn::call trait functions. +* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for + example, `sqrt` -- have this ABI. You should never have to deal with it. + The `link` attribute allows the name of the library to be specified. When specified the compiler will attempt to link against the native library of the specified name. From 1e899fde015c29f53642b6b8e582a8547b6e3b1d Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 25 Jun 2016 11:53:46 -0700 Subject: [PATCH 004/150] Add vectorcall and fastcall explanation --- src/doc/reference.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index d564b19e1001c..fa6014a3d6cee 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1656,8 +1656,10 @@ There are also some platform-specific ABI strings: * `extern "stdcall"` -- The default for the Win32 API on x86\_32. * `extern "win64"` -- The default for C code on x86\_64 Windows. * `extern "aapcs"` -- The default for ARM. -* `extern "fastcall"` -* `extern "vectorcall"` +* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's + `__fastcall` and GCC and clang's `__attribute__((fastcall))` +* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's + `__vectorcall` and clang's `__attribute__((vectorcall))` Finally, there are some rustc-specific ABI strings: From 3d03f7541e37fe4728149f6466d4c8aba51d7ec0 Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 1 Jul 2016 23:33:44 -0700 Subject: [PATCH 005/150] Add more docs - mostly warnings - to std::mem::transmute --- src/libcore/intrinsics.rs | 99 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index edb965c1962e3..1b52ea33d375a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,18 +278,109 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Unsafely transforms a value of one type into a value of another type. + /// Bitcasts a value of one type to another. Both types must have the same + /// size. /// - /// Both types must have the same size. + /// `transmute::(t)` is semantically equivalent to the following: + /// + /// ``` + /// fn transmute(t: T) -> U { + /// let u: U = std::mem::uninitialized(); + /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// std::mem::size_of::()); + /// std::mem::forget(t); + /// u + /// } + /// ``` + /// + /// `transmute` is incredibly unsafe. There are an incredible number of ways + /// to cause undefined behavior with this function. `transmute` should be + /// the absolute last resort. + /// + /// The following is more complete documentation. Read it before using + /// `transmute`: + /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) /// /// # Examples /// /// ``` /// use std::mem; /// - /// let array: &[u8] = unsafe { mem::transmute("Rust") }; - /// assert_eq!(array, [82, 117, 115, 116]); + /// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // this is not a good way to do this. + /// // use .as_bytes() + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// ``` + /// + /// There are very few good cases for `transmute`. Most can be achieved + /// through other means. Some commone uses, and the less unsafe way, are as + /// follows: + /// + /// ``` + /// // Turning a *mut T into an &mut T + /// let ptr: *mut i32 = &mut 0; + /// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_casted = &mut *ptr; + /// ``` + /// /// ``` + /// // Turning an &mut T into an &mut U + /// let ptr = &mut 0; + /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); + /// // There is a better way, using `as` and reborrowing: + /// let val_casts = &mut *(ptr as *mut T as *mut U); + /// ``` + /// + /// ``` + /// // Copying an `&mut T` to reslice: + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); + /// (slice[0..index], slice2[index..len]) + /// } + /// // or: + /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! + /// (slice[0..index], slice2[index..len]) + /// } + /// ``` + /// + /// There are valid uses of transmute. + /// + /// ``` + /// // getting the bitpattern of a floating point type + /// let x = std::mem::transmute::(0.0/0.0) + /// + /// // turning a pointer into a function pointer + /// // in file.c: `int foo(void) { ... }` + /// let handle: *mut libc::c_void = libc::dlopen( + /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); + /// let foo: *mut libc::c_void = libc::dlsym( + /// handle, + /// b"foo\0".as_ptr() as *const libc::c_char); + /// let foo = std::mem::transmute::<*mut libc::c_void, + /// extern fn() -> libc::c_int>(foo); + /// println!("{}", foo()); + /// + /// // extending an invariant lifetime; this is advanced, very unsafe rust + /// struct T<'a>(&'a i32); + /// let value = 0; + /// let t = T::new(&value); + /// let ptr = &mut t; + /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// ``` + /// + /// But these are few and far between. #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 233b45f0d714e0fd48b297a531bc57138d524a3a Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 1 Jul 2016 23:57:10 -0700 Subject: [PATCH 006/150] Fix up some things which scott mentioned --- src/libcore/intrinsics.rs | 81 ++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1b52ea33d375a..c7ea5e9da640b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,65 +278,74 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Bitcasts a value of one type to another. Both types must have the same - /// size. + /// 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, may be an + /// invalid value, or else you'll have UB on your hands. /// /// `transmute::(t)` is semantically equivalent to the following: /// /// ``` + /// // assuming that T and U are the same size /// fn transmute(t: T) -> U { - /// let u: U = std::mem::uninitialized(); - /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// std::mem::size_of::()); - /// std::mem::forget(t); - /// u + /// let u: U = std::mem::uninitialized(); + /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// std::mem::size_of::()); + /// std::mem::forget(t); + /// u /// } /// ``` /// - /// `transmute` is incredibly unsafe. There are an incredible number of ways - /// to cause undefined behavior with this function. `transmute` should be + /// `transmute` is incredibly unsafe. There are a vast number of ways to + /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// /// The following is more complete documentation. Read it before using /// `transmute`: /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) /// - /// # Examples + /// # Alternatives + /// + /// There are very few good cases for `transmute`. Most can be achieved + /// through other means. Some more or less common uses, and a better way, + /// are as follows: /// /// ``` /// use std::mem; /// - /// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // this is not a good way to do this. - /// // use .as_bytes() - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// ``` + /// // turning a pointer into a usize + /// let ptr = &0; + /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); + /// // now with more `as` + /// let ptr_num_cast = ptr as *const i32 as usize; /// - /// There are very few good cases for `transmute`. Most can be achieved - /// through other means. Some commone uses, and the less unsafe way, are as - /// follows: /// - /// ``` /// // Turning a *mut T into an &mut T /// let ptr: *mut i32 = &mut 0; - /// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows /// let ref_casted = &mut *ptr; - /// ``` /// - /// ``` + /// /// // Turning an &mut T into an &mut U /// let ptr = &mut 0; /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // There is a better way, using `as` and reborrowing: - /// let val_casts = &mut *(ptr as *mut T as *mut U); - /// ``` + /// // Reborrowing continues to play a role here, but now we add `as` casts + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// + /// + /// // Turning an `&str` into an `&[u8]` + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // this is not a good way to do this. + /// // use .as_bytes() + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// /// - /// ``` /// // Copying an `&mut T` to reslice: /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { @@ -345,7 +354,7 @@ extern "rust-intrinsic" { /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); /// (slice[0..index], slice2[index..len]) /// } - /// // or: + /// // Again, use `as` and reborrowing /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -355,12 +364,15 @@ extern "rust-intrinsic" { /// } /// ``` /// - /// There are valid uses of transmute. + /// # Examples + /// + /// There are valid uses of transmute, though they are few and far between. /// /// ``` /// // getting the bitpattern of a floating point type /// let x = std::mem::transmute::(0.0/0.0) /// + /// /// // turning a pointer into a function pointer /// // in file.c: `int foo(void) { ... }` /// let handle: *mut libc::c_void = libc::dlopen( @@ -372,6 +384,7 @@ extern "rust-intrinsic" { /// extern fn() -> libc::c_int>(foo); /// println!("{}", foo()); /// + /// /// // extending an invariant lifetime; this is advanced, very unsafe rust /// struct T<'a>(&'a i32); /// let value = 0; @@ -379,8 +392,6 @@ extern "rust-intrinsic" { /// let ptr = &mut t; /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); /// ``` - /// - /// But these are few and far between. #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 6928bbba3a51db12aceb90d3c99dbec1383ce2dc Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 00:00:04 -0700 Subject: [PATCH 007/150] Fix some other small nits --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index c7ea5e9da640b..3cc113f5e0a7a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -316,7 +316,7 @@ extern "rust-intrinsic" { /// // turning a pointer into a usize /// let ptr = &0; /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); - /// // now with more `as` + /// // Use `as` casts instead /// let ptr_num_cast = ptr as *const i32 as usize; /// /// @@ -330,15 +330,15 @@ extern "rust-intrinsic" { /// // Turning an &mut T into an &mut U /// let ptr = &mut 0; /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Reborrowing continues to play a role here, but now we add `as` casts + /// // Now let's put together `as` and reborrowing /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); /// /// /// // Turning an `&str` into an `&[u8]` + /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, [82, 117, 115, 116]); - /// // this is not a good way to do this. - /// // use .as_bytes() + /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, [82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string From 2413b52b886bc9ba4db6c5bc5eb0712c6e4f554a Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 00:07:36 -0700 Subject: [PATCH 008/150] More nits :P --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3cc113f5e0a7a..d2bf9d94399ea 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -280,7 +280,8 @@ extern "rust-intrinsic" { /// 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, may be an - /// invalid value, or else you'll have UB on your hands. + /// [invalid value] + /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). /// /// `transmute::(t)` is semantically equivalent to the following: /// @@ -300,9 +301,8 @@ extern "rust-intrinsic" { /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// - /// The following is more complete documentation. Read it before using - /// `transmute`: - /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) + /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has + /// more complete documentation. Read it before using `transmute`. /// /// # Alternatives /// From 377bbfe96b9d5f20ca6aec84f68ad8161f307ab5 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 08:45:01 -0700 Subject: [PATCH 009/150] Add a new alternative --- src/libcore/intrinsics.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d2bf9d94399ea..5bd35ae1ac25c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -346,6 +346,29 @@ extern "rust-intrinsic" { /// assert_eq!(b"Rust", [82, 117, 116, 116]); /// /// + /// // Turning a Vec<&T> into a Vec> + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute; Undefined Behavior + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig); + /// // The suggested, safe way + /// let v_collected = v_orig.into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// // This is equivalent to the original, but safer, and reuses the same + /// // Vec internals. Therefore the new inner type must have the exact same + /// // size, and the same or lesser alignment, as the old type. + /// // The same caveats exist for this method as transmute, for the original + /// // inner type (`&i32`) to the converted inner type (`Option<&i32>`), so + /// // read the nomicon page linked above. + /// + /// /// // Copying an `&mut T` to reslice: /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { From 9e94ebf268385686299b6838b41e8e04a874259f Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 22:55:30 -0700 Subject: [PATCH 010/150] Make sure the documentation compiles --- src/libcore/intrinsics.rs | 169 +++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 77 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5bd35ae1ac25c..ce87bd3ba326c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -287,12 +287,12 @@ extern "rust-intrinsic" { /// /// ``` /// // assuming that T and U are the same size - /// fn transmute(t: T) -> U { - /// let u: U = std::mem::uninitialized(); + /// unsafe fn transmute(t: T) -> U { + /// let u: U = mem::uninitialized(); /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, /// &mut u as *mut U as *mut u8, - /// std::mem::size_of::()); - /// std::mem::forget(t); + /// mem::size_of::()); + /// mem::forget(t); /// u /// } /// ``` @@ -314,76 +314,85 @@ extern "rust-intrinsic" { /// use std::mem; /// /// // turning a pointer into a usize - /// let ptr = &0; - /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// + /// { + /// let ptr = &0; + /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// // Use `as` casts instead + /// let ptr_num_cast = ptr as *const i32 as usize; + /// } /// /// // Turning a *mut T into an &mut T - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows - /// let ref_casted = &mut *ptr; - /// + /// { + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows + /// let ref_casted = &mut *ptr; + /// } /// /// // Turning an &mut T into an &mut U - /// let ptr = &mut 0; - /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); - /// + /// { + /// let ptr = &mut 0; + /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// // Now let's put together `as` and reborrowing + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// } /// /// // Turning an `&str` into an `&[u8]` - /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// + /// { + /// // this is not a good way to do this. + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// } /// /// // Turning a Vec<&T> into a Vec> - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// // Using transmute; Undefined Behavior - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig); - /// // The suggested, safe way - /// let v_collected = v_orig.into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB - /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); - /// // This is equivalent to the original, but safer, and reuses the same - /// // Vec internals. Therefore the new inner type must have the exact same - /// // size, and the same or lesser alignment, as the old type. - /// // The same caveats exist for this method as transmute, for the original - /// // inner type (`&i32`) to the converted inner type (`Option<&i32>`), so - /// // read the nomicon page linked above. + /// { + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute; Undefined Behavior + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig.clone()); + /// // The suggested, safe way + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon page linked above. + /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// } /// /// /// // Copying an `&mut T` to reslice: - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// { + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); + /// (slice[0..index], slice2[index..len]) + /// } + /// // Again, use `as` and reborrowing + /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); - /// (slice[0..index], slice2[index..len]) - /// } - /// // Again, use `as` and reborrowing - /// fn split_at_mut_casts(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! + /// (slice[0..index], slice2[index..len]) + /// } /// } /// ``` /// @@ -393,27 +402,33 @@ extern "rust-intrinsic" { /// /// ``` /// // getting the bitpattern of a floating point type - /// let x = std::mem::transmute::(0.0/0.0) + /// { + /// let x = mem::transmute::(0.0/0.0) + /// } /// /// /// // turning a pointer into a function pointer - /// // in file.c: `int foo(void) { ... }` - /// let handle: *mut libc::c_void = libc::dlopen( - /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); - /// let foo: *mut libc::c_void = libc::dlsym( - /// handle, - /// b"foo\0".as_ptr() as *const libc::c_char); - /// let foo = std::mem::transmute::<*mut libc::c_void, - /// extern fn() -> libc::c_int>(foo); - /// println!("{}", foo()); + /// { + /// // in file.c: `int foo(void) { ... }` + /// let handle: *mut libc::c_void = libc::dlopen( + /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); + /// let foo: *mut libc::c_void = libc::dlsym( + /// handle, + /// b"foo\0".as_ptr() as *const libc::c_char); + /// let foo = mem::transmute::<*mut libc::c_void, + /// extern fn() -> libc::c_int>(foo); + /// println!("{}", foo()); + /// } /// /// /// // extending an invariant lifetime; this is advanced, very unsafe rust - /// struct T<'a>(&'a i32); - /// let value = 0; - /// let t = T::new(&value); - /// let ptr = &mut t; - /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// { + /// struct T<'a>(&'a i32); + /// let value = 0; + /// let t = T::new(&value); + /// let ptr = &mut t; + /// let ptr_extended = mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 7ec44e6c7b0e5fb2ddbc281aa74b515f8ea4e16b Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 10:40:59 -0700 Subject: [PATCH 011/150] Fix tests --- src/libcore/intrinsics.rs | 238 ++++++++++++++++++++++---------------- 1 file changed, 138 insertions(+), 100 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ce87bd3ba326c..fd23598a84715 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -286,12 +286,13 @@ extern "rust-intrinsic" { /// `transmute::(t)` is semantically equivalent to the following: /// /// ``` + /// use std::{mem, ptr}; /// // assuming that T and U are the same size /// unsafe fn transmute(t: T) -> U { - /// let u: U = mem::uninitialized(); - /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// mem::size_of::()); + /// let mut u: U = mem::uninitialized(); + /// ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// mem::size_of::()); /// mem::forget(t); /// u /// } @@ -310,88 +311,115 @@ extern "rust-intrinsic" { /// through other means. Some more or less common uses, and a better way, /// are as follows: /// + /// Turning a pointer into a `usize`: + /// ``` + /// let ptr = &0; + /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// // Use `as` casts instead + /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` - /// use std::mem; - /// - /// // turning a pointer into a usize - /// { - /// let ptr = &0; - /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// } - /// - /// // Turning a *mut T into an &mut T - /// { - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows - /// let ref_casted = &mut *ptr; - /// } /// - /// // Turning an &mut T into an &mut U - /// { - /// let ptr = &mut 0; - /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); - /// } + /// Turning a `*mut T` into an `&mut T`: + /// ``` + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows + /// let ref_casted = &mut *ptr; + /// ``` /// - /// // Turning an `&str` into an `&[u8]` - /// { - /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// } + /// Turning an `&mut T` into an `&mut U`: + /// ``` + /// let ptr = &mut 0; + /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// // Now let's put together `as` and reborrowing + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// ``` /// - /// // Turning a Vec<&T> into a Vec> - /// { - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// // Using transmute; Undefined Behavior - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig.clone()); - /// // The suggested, safe way - /// let v_collected = v_orig.clone() - /// .into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB - /// // This is equivalent to the original, but safer, and reuses the - /// // same Vec internals. Therefore the new inner type must have the - /// // exact same size, and the same or lesser alignment, as the old - /// // type. The same caveats exist for this method as transmute, for - /// // the original inner type (`&i32`) to the converted inner type - /// // (`Option<&i32>`), so read the nomicon page linked above. - /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); - /// } + /// Turning an `&str` into an `&[u8]`: + /// ``` + /// // this is not a good way to do this. + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// ``` /// + /// Turning a `Vec<&T>` into a `Vec>`: + /// ``` + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute: this is Undefined Behavior, and a bad idea + /// // However, it is no-copy + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig.clone()); + /// // This is the suggested, safe way + /// // It does copy the entire Vector, though, into a new array + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon page linked above. + /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// ``` /// - /// // Copying an `&mut T` to reslice: - /// { - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); + /// Implemententing `split_at_mut`: + /// ``` + /// use std::{slice, mem}; + /// // There are multiple ways to do this; and there are multiple problems + /// // with the following, transmute, way + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// unsafe { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); - /// (slice[0..index], slice2[index..len]) + /// // first: transmute is not typesafe; all it checks is that T and + /// // U are of the same size. Second, right here, you have two + /// // mutable references pointing to the same memory + /// (&mut slice[0..index], &mut slice2[index..len]) /// } - /// // Again, use `as` and reborrowing - /// fn split_at_mut_casts(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// } + /// // This gets rid of the typesafety problems; `&mut *` will *only* give + /// // you an &mut T from an &mut T or *mut T + /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// unsafe { + /// let slice2 = &mut *(slice as *mut [T]); + /// // however, you still have two mutable references pointing to + /// // the same memory + /// (&mut slice[0..index], &mut slice2[index..len]) + /// } + /// } + /// // This is how the standard library does it. This is the best method, if + /// // you need to do something like this + /// fn split_at_stdlib(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = self.len(); + /// let ptr = self.as_mut_ptr(); + /// unsafe { + /// assert!(mid <= len); + /// // This now has three mutable references pointing at the same + /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. + /// // However, `slice` is never used after `let ptr = ...`, and so + /// // one can treat it as "dead", and therefore, you only have two + /// // real mutable slices. + /// (slice::from_raw_parts_mut(ptr, mid), + /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) /// } /// } /// ``` @@ -400,39 +428,49 @@ extern "rust-intrinsic" { /// /// There are valid uses of transmute, though they are few and far between. /// + /// Getting the bitpattern of a floating point type: + /// ``` + /// let bitpattern = std::mem::transmute::(1.0); + /// assert_eq!(bitpattern, 0x3F800000); /// ``` - /// // getting the bitpattern of a floating point type - /// { - /// let x = mem::transmute::(0.0/0.0) + /// + /// Turning a pointer into a function pointer (this isn't guaranteed to + /// work in Rust, although, for example, Linux does make this guarantee): + /// ``` + /// fn foo() -> i32 { + /// 0 /// } + /// let pointer = foo as *const (); + /// let function = std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// assert_eq!(function(), 0); + /// ``` /// + /// Extending a lifetime, or shortening an invariant an invariant lifetime; + /// this is advanced, very unsafe rust: + /// ``` + /// use std::mem; /// - /// // turning a pointer into a function pointer - /// { - /// // in file.c: `int foo(void) { ... }` - /// let handle: *mut libc::c_void = libc::dlopen( - /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); - /// let foo: *mut libc::c_void = libc::dlsym( - /// handle, - /// b"foo\0".as_ptr() as *const libc::c_char); - /// let foo = mem::transmute::<*mut libc::c_void, - /// extern fn() -> libc::c_int>(foo); - /// println!("{}", foo()); + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// mem::transmute::, R<'static>>(ptr); /// } /// - /// - /// // extending an invariant lifetime; this is advanced, very unsafe rust - /// { - /// struct T<'a>(&'a i32); - /// let value = 0; - /// let t = T::new(&value); - /// let ptr = &mut t; - /// let ptr_extended = mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// unsafe fn shorten_invariant<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b R<'c> { + /// let ref_to_original = + /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( + /// ref_to_extended); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; + /// Gives the address for the return value of the enclosing function. + /// + /// Using this intrinsic in a function that does not use an out pointer + /// will trigger a compiler error. + pub fn return_address() -> *const u8; + /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` /// implements `Copy`. From ede39aeb331bf6efb3739d22a60c1844e9c2c3d6 Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Wed, 29 Jun 2016 10:40:25 +0300 Subject: [PATCH 012/150] feat: reinterpret `precision` field for strings This commit changes the behavior of formatting string arguments with both width and precision fields set. Documentation says that the `width` field is the "minimum width" that the format should take up. If the value's string does not fill up this many characters, then the padding specified by fill/alignment will be used to take up the required space. This is true for all formatted types except string, which is truncated down to `precision` number of chars and then all of `fill`, `align` and `width` fields are completely ignored. For example: `format!("{:/^10.8}", "1234567890);` emits "12345678". In the contrast Python version works as the expected: ```python >>> '{:/^10.8}'.format('1234567890') '/12345678/' ``` This commit gives back the `Python` behavior by changing the `precision` field meaning to the truncation and nothing more. The result string *will* be prepended/appended up to the `width` field with the proper `fill` char. However, this is the breaking change. Also updated `std::fmt` docs about string precision. Signed-off-by: Evgeny Safronov --- src/libcollections/fmt.rs | 6 ++++-- src/libcore/fmt/mod.rs | 18 +++++++++++------- src/test/run-pass/ifmt.rs | 3 ++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 6f77d79ab0bfe..356bb96741e4f 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -408,8 +408,8 @@ //! ## Precision //! //! For non-numeric types, this can be considered a "maximum width". If the resulting string is -//! longer than this width, then it is truncated down to this many characters and only those are -//! emitted. +//! longer than this width, then it is truncated down to this many characters and that truncated +//! value is emitted with proper `fill`, `alignment` and `width` if those parameters are set. //! //! For integral types, this is ignored. //! @@ -469,6 +469,7 @@ //! ``` //! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); //! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); +//! println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); //! ``` //! //! print two significantly different things: @@ -476,6 +477,7 @@ //! ```text //! Hello, `1234.560` has 3 fractional digits //! Hello, `123` has 3 characters +//! Hello, ` 123` has 3 right-aligned characters //! ``` //! //! # Escaping diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 4ac134c2b59c8..a36f7e42c9c47 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -983,15 +983,19 @@ impl<'a> Formatter<'a> { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the - // string being formatted - if let Some(max) = self.precision { - // If there's a maximum width and our string is longer than - // that, then we must always have truncation. This is the only - // case where the maximum length will matter. + // string being formatted. + let s = if let Some(max) = self.precision { + // If our string is longer that the precision, then we must have + // truncation. However other flags like `fill`, `width` and `align` + // must act as always. if let Some((i, _)) = s.char_indices().skip(max).next() { - return self.buf.write_str(&s[..i]) + &s[..i] + } else { + &s } - } + } else { + &s + }; // The `width` field is more of a `min-width` parameter at this point. match self.width { // If we're under the maximum length, and there's no minimum length diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 27cafeacc203d..1cc52c930344c 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -125,7 +125,7 @@ pub fn main() { t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); t!(format!("{:2.4}", "aaaaa"), "aaaa"); t!(format!("{:2.4}", "aaaa"), "aaaa"); t!(format!("{:2.4}", "aaa"), "aaa"); @@ -140,6 +140,7 @@ pub fn main() { t!(format!("{:a$}", "a", a=4), "a "); t!(format!("{:-#}", "a"), "a"); t!(format!("{:+#}", "a"), "a"); + t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); // Some float stuff t!(format!("{:}", 1.0f32), "1"); From 8c7668a903fb31f8bd767ed5c2a1e1fd3c778915 Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 15:15:33 -0700 Subject: [PATCH 013/150] Fix nits --- src/libcore/intrinsics.rs | 41 ++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fd23598a84715..1ccdbb3411c8d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -312,30 +312,34 @@ extern "rust-intrinsic" { /// are as follows: /// /// Turning a pointer into a `usize`: + /// /// ``` /// let ptr = &0; /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead + /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` /// /// Turning a `*mut T` into an `&mut T`: + /// /// ``` /// let ptr: *mut i32 = &mut 0; /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows + /// // Use a reborrow instead /// let ref_casted = &mut *ptr; /// ``` /// /// Turning an `&mut T` into an `&mut U`: + /// /// ``` /// let ptr = &mut 0; /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing + /// // Now, put together `as` and reborrowing /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); /// ``` /// /// Turning an `&str` into an `&[u8]`: + /// /// ``` /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; @@ -349,20 +353,21 @@ extern "rust-intrinsic" { /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: + /// /// ``` /// let store = [0, 1, 2, 3]; /// let v_orig = store.iter().collect::>(); - /// // Using transmute: this is Undefined Behavior, and a bad idea - /// // However, it is no-copy + /// // Using transmute: this is Undefined Behavior, and a bad idea. + /// // However, it is no-copy. /// let v_transmuted = mem::transmute::, Vec>>( /// v_orig.clone()); - /// // This is the suggested, safe way - /// // It does copy the entire Vector, though, into a new array + /// // This is the suggested, safe way. + /// // It does copy the entire Vector, though, into a new array. /// let v_collected = v_orig.clone() /// .into_iter() /// .map(|r| Some(r)) /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB + /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the /// // same Vec internals. Therefore the new inner type must have the /// // exact same size, and the same or lesser alignment, as the old @@ -375,11 +380,12 @@ extern "rust-intrinsic" { /// mem::forget(v_orig); /// ``` /// - /// Implemententing `split_at_mut`: + /// Implementing `split_at_mut`: + /// /// ``` /// use std::{slice, mem}; /// // There are multiple ways to do this; and there are multiple problems - /// // with the following, transmute, way + /// // with the following, transmute, way. /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -388,12 +394,12 @@ extern "rust-intrinsic" { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); /// // first: transmute is not typesafe; all it checks is that T and /// // U are of the same size. Second, right here, you have two - /// // mutable references pointing to the same memory + /// // mutable references pointing to the same memory. /// (&mut slice[0..index], &mut slice2[index..len]) /// } /// } /// // This gets rid of the typesafety problems; `&mut *` will *only* give - /// // you an &mut T from an &mut T or *mut T + /// // you an `&mut T` from an `&mut T` or `*mut T`. /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -401,7 +407,7 @@ extern "rust-intrinsic" { /// unsafe { /// let slice2 = &mut *(slice as *mut [T]); /// // however, you still have two mutable references pointing to - /// // the same memory + /// // the same memory. /// (&mut slice[0..index], &mut slice2[index..len]) /// } /// } @@ -415,9 +421,9 @@ extern "rust-intrinsic" { /// assert!(mid <= len); /// // This now has three mutable references pointing at the same /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. - /// // However, `slice` is never used after `let ptr = ...`, and so - /// // one can treat it as "dead", and therefore, you only have two - /// // real mutable slices. + /// // `slice` is never used after `let ptr = ...`, and so one can + /// // treat it as "dead", and therefore, you only have two real + /// // mutable slices. /// (slice::from_raw_parts_mut(ptr, mid), /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) /// } @@ -429,6 +435,7 @@ extern "rust-intrinsic" { /// There are valid uses of transmute, though they are few and far between. /// /// Getting the bitpattern of a floating point type: + /// /// ``` /// let bitpattern = std::mem::transmute::(1.0); /// assert_eq!(bitpattern, 0x3F800000); @@ -436,6 +443,7 @@ extern "rust-intrinsic" { /// /// Turning a pointer into a function pointer (this isn't guaranteed to /// work in Rust, although, for example, Linux does make this guarantee): + /// /// ``` /// fn foo() -> i32 { /// 0 @@ -447,6 +455,7 @@ extern "rust-intrinsic" { /// /// Extending a lifetime, or shortening an invariant an invariant lifetime; /// this is advanced, very unsafe rust: + /// /// ``` /// use std::mem; /// From 15a49fefcb29590554d69081a7e26fcf4bfa0f65 Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 15:42:48 -0700 Subject: [PATCH 014/150] Tone it down a little --- src/libcore/intrinsics.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ccdbb3411c8d..fd2d9cdb0d4b9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -283,7 +283,7 @@ extern "rust-intrinsic" { /// [invalid value] /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). /// - /// `transmute::(t)` is semantically equivalent to the following: + /// `transmute` is semantically equivalent to the following: /// /// ``` /// use std::{mem, ptr}; @@ -303,7 +303,7 @@ extern "rust-intrinsic" { /// the absolute last resort. /// /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has - /// more complete documentation. Read it before using `transmute`. + /// additional documentation. /// /// # Alternatives /// @@ -343,13 +343,13 @@ extern "rust-intrinsic" { /// ``` /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); + /// assert_eq!(slice, &[82, 117, 115, 116]); /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); + /// assert_eq!(slice, &[82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// assert_eq!(b"Rust", &[82, 117, 116, 116]); /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: @@ -373,7 +373,7 @@ extern "rust-intrinsic" { /// // exact same size, and the same or lesser alignment, as the old /// // type. The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type - /// // (`Option<&i32>`), so read the nomicon page linked above. + /// // (`Option<&i32>`), so read the nomicon pages linked above. /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), /// v_orig.len(), /// v_orig.capacity()); @@ -441,7 +441,7 @@ extern "rust-intrinsic" { /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// - /// Turning a pointer into a function pointer (this isn't guaranteed to + /// Turning a pointer into a function pointer (this is not guaranteed to /// work in Rust, although, for example, Linux does make this guarantee): /// /// ``` @@ -453,8 +453,8 @@ extern "rust-intrinsic" { /// assert_eq!(function(), 0); /// ``` /// - /// Extending a lifetime, or shortening an invariant an invariant lifetime; - /// this is advanced, very unsafe rust: + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: /// /// ``` /// use std::mem; @@ -464,11 +464,10 @@ extern "rust-intrinsic" { /// mem::transmute::, R<'static>>(ptr); /// } /// - /// unsafe fn shorten_invariant<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b R<'c> { - /// let ref_to_original = - /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( - /// ref_to_extended); + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( + /// ref_to_extended) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] From 451af791dadf5a38da2fe63d578c083b95d6c10a Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 16:04:58 -0700 Subject: [PATCH 015/150] Fix links, change example to english --- src/libcore/intrinsics.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fd2d9cdb0d4b9..875fa08f78980 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,32 +278,21 @@ extern "rust-intrinsic" { /// 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 + /// 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, may be an - /// [invalid value] - /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). + /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html). /// - /// `transmute` is semantically equivalent to the following: - /// - /// ``` - /// use std::{mem, ptr}; - /// // assuming that T and U are the same size - /// unsafe fn transmute(t: T) -> U { - /// let mut u: U = mem::uninitialized(); - /// ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// mem::size_of::()); - /// mem::forget(t); - /// u - /// } - /// ``` + /// `transmute` is semantically equivalent to a bitwise move of one type + /// into another. It copies the bits from the destination type into the + /// source type, then forgets the original. If you know C or C++, it's like + /// `memcpy` under the hood. /// /// `transmute` is incredibly unsafe. There are a vast number of ways to /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// - /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has - /// additional documentation. + /// The [nomicon](../../nomicon/transmutes.html) has additional + /// documentation. /// /// # Alternatives /// From 7eabff5b5ade1cdef3e4b4d3479c45798425ff6a Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 23:54:34 -0700 Subject: [PATCH 016/150] Hopefully, it now works --- src/libcore/intrinsics.rs | 73 ++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 875fa08f78980..953173f8aace8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -304,7 +304,9 @@ extern "rust-intrinsic" { /// /// ``` /// let ptr = &0; - /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// let ptr_num_transmute = unsafe { + /// std::mem::transmute::<&i32, usize>(ptr) + /// }; /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` @@ -313,43 +315,49 @@ extern "rust-intrinsic" { /// /// ``` /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_transmuted = unsafe { + /// std::mem::transmute::<*mut i32, &mut i32>(ptr) + /// }; /// // Use a reborrow instead - /// let ref_casted = &mut *ptr; + /// let ref_casted = unsafe { &mut *ptr }; /// ``` /// /// Turning an `&mut T` into an `&mut U`: /// /// ``` /// let ptr = &mut 0; - /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// let val_transmuted = unsafe { + /// std::mem::transmute::<&mut i32, &mut u32>(ptr) + /// }; /// // Now, put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// /// Turning an `&str` into an `&[u8]`: /// /// ``` /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, &[82, 117, 115, 116]); /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, &[82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string /// // literal - /// assert_eq!(b"Rust", &[82, 117, 116, 116]); + /// assert_eq!(b"Rust", &[82, 117, 115, 116]); /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: /// /// ``` /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); + /// let mut v_orig = store.iter().collect::>(); /// // Using transmute: this is Undefined Behavior, and a bad idea. /// // However, it is no-copy. - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig.clone()); + /// let v_transmuted = unsafe { + /// std::mem::transmute::, Vec>>( + /// v_orig.clone()) + /// }; /// // This is the suggested, safe way. /// // It does copy the entire Vector, though, into a new array. /// let v_collected = v_orig.clone() @@ -363,10 +371,12 @@ extern "rust-intrinsic" { /// // type. The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type /// // (`Option<&i32>`), so read the nomicon pages linked above. - /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); + /// let v_from_raw = unsafe { + /// Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()) + /// }; + /// std::mem::forget(v_orig); /// ``` /// /// Implementing `split_at_mut`: @@ -375,39 +385,39 @@ extern "rust-intrinsic" { /// use std::{slice, mem}; /// // There are multiple ways to do this; and there are multiple problems /// // with the following, transmute, way. - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); - /// assert!(index < len); + /// assert!(mid <= len); /// unsafe { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); /// // first: transmute is not typesafe; all it checks is that T and /// // U are of the same size. Second, right here, you have two /// // mutable references pointing to the same memory. - /// (&mut slice[0..index], &mut slice2[index..len]) + /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } /// // This gets rid of the typesafety problems; `&mut *` will *only* give /// // you an `&mut T` from an `&mut T` or `*mut T`. - /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// fn split_at_mut_casts(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); - /// assert!(index < len); + /// assert!(mid <= len); /// unsafe { /// let slice2 = &mut *(slice as *mut [T]); /// // however, you still have two mutable references pointing to /// // the same memory. - /// (&mut slice[0..index], &mut slice2[index..len]) + /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } /// // This is how the standard library does it. This is the best method, if /// // you need to do something like this - /// fn split_at_stdlib(slice: &mut [T], index: usize) + /// fn split_at_stdlib(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { - /// let len = self.len(); - /// let ptr = self.as_mut_ptr(); + /// let len = slice.len(); + /// assert!(mid <= len); /// unsafe { - /// assert!(mid <= len); + /// let ptr = slice.as_mut_ptr(); /// // This now has three mutable references pointing at the same /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. /// // `slice` is never used after `let ptr = ...`, and so one can @@ -426,7 +436,9 @@ extern "rust-intrinsic" { /// Getting the bitpattern of a floating point type: /// /// ``` - /// let bitpattern = std::mem::transmute::(1.0); + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// @@ -438,7 +450,9 @@ extern "rust-intrinsic" { /// 0 /// } /// let pointer = foo as *const (); - /// let function = std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; /// assert_eq!(function(), 0); /// ``` /// @@ -446,17 +460,14 @@ extern "rust-intrinsic" { /// advanced, very unsafe rust: /// /// ``` - /// use std::mem; - /// /// struct R<'a>(&'a i32); /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// mem::transmute::, R<'static>>(ptr); + /// std::mem::transmute::, R<'static>>(r) /// } /// /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) /// -> &'b mut R<'c> { - /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( - /// ref_to_extended) + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] From 8aeb9303e954502f67f4af7c5c7e79f6d4f706eb Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 8 Jul 2016 22:12:36 +1000 Subject: [PATCH 017/150] add a non blocking iterator for the mpsc::Receiver Currently, the `mpsc::Receiver` offers methods for receiving values in both blocking (`recv`) and non-blocking (`try_recv`) flavours. However only blocking iteration over values is supported. This commit adds a non-blocking iterator to complement the `try_recv` method, just as the blocking iterator complements the `recv` method. --- src/libstd/sync/mpsc/mod.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 34bc210b3c823..30ce9c3f382b7 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -311,6 +311,16 @@ pub struct Iter<'a, T: 'a> { rx: &'a Receiver } +/// 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. +/// +/// This Iterator will never block the caller in order to wait for data to +/// become available. Instead, it will return `None`. +pub struct TryIter<'a, T: 'a> { + rx: &'a Receiver +} + /// 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 /// returned when the corresponding channel has hung up. @@ -982,6 +992,15 @@ impl Receiver { pub fn iter(&self) -> Iter { Iter { rx: self } } + + /// 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 + /// user by waiting for values. + pub fn try_iter(&self) -> TryIter { + TryIter { rx: self } + } + } impl select::Packet for Receiver { @@ -1077,6 +1096,12 @@ impl<'a, T> Iterator for Iter<'a, T> { fn next(&mut self) -> Option { self.rx.recv().ok() } } +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { self.rx.try_recv().ok() } +} + #[stable(feature = "receiver_into_iter", since = "1.1.0")] impl<'a, T> IntoIterator for &'a Receiver { type Item = T; From b354887180b665441dd6e3ea51b2651085de88f9 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sat, 9 Jul 2016 00:21:26 +1000 Subject: [PATCH 018/150] Add a test for Receiver::try_iter --- src/libstd/sync/mpsc/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 30ce9c3f382b7..51a820b2e91c3 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1839,6 +1839,34 @@ mod tests { assert_eq!(count_rx.recv().unwrap(), 4); } + #[test] + fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move|| { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + drop(response_rx); + drop(request_tx); + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + response_tx.send(2).unwrap(); + } + + assert_eq!(t.join().unwrap(), 6); + } + #[test] fn test_recv_into_iter_owned() { let mut iter = { From b02b38e1c4f7c8075c92d41e9e08bf2a20982f66 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sat, 9 Jul 2016 00:35:08 +1000 Subject: [PATCH 019/150] Add the unstable attribute to the new mpsc::Receiver::try_iter API --- src/libstd/sync/mpsc/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 51a820b2e91c3..2d2bded9f6060 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -317,6 +317,7 @@ pub struct Iter<'a, T: 'a> { /// /// This Iterator will never block the caller in order to wait for data to /// become available. Instead, it will return `None`. +#[unstable(feature = "receiver_try_iter")] pub struct TryIter<'a, T: 'a> { rx: &'a Receiver } @@ -997,6 +998,7 @@ impl Receiver { /// 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 /// user by waiting for values. + #[unstable(feature = "receiver_try_iter")] pub fn try_iter(&self) -> TryIter { TryIter { rx: self } } @@ -1096,6 +1098,7 @@ impl<'a, T> Iterator for Iter<'a, T> { fn next(&mut self) -> Option { self.rx.recv().ok() } } +#[unstable(feature = "receiver_try_iter")] impl<'a, T> Iterator for TryIter<'a, T> { type Item = T; From b4ff6b028ed6ae2e67d97604ad6bfbd235bb4f74 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Fri, 8 Jul 2016 23:14:32 -0400 Subject: [PATCH 020/150] document DoubleEndedIterator::next_back fixes #34726 --- src/libcore/iter/traits.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 9b5c2128f1eaf..43360b91fdaaa 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -386,10 +386,11 @@ pub trait Extend { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait DoubleEndedIterator: Iterator { - /// An iterator able to yield elements from both ends. + /// Removes and returns an element from the end of the iterator. /// - /// As this is the only method for this trait, the [trait-level] docs - /// contain more details. + /// Returns `None` when there are no more elements. + /// + /// The [trait-level] docs contain more details. /// /// [trait-level]: trait.DoubleEndedIterator.html /// From 97003e56991d3e475f2d4bb18a88c768018041e9 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sun, 10 Jul 2016 06:13:34 +0200 Subject: [PATCH 021/150] Switch around Examples and Alternatives --- src/libcore/intrinsics.rs | 93 ++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 953173f8aace8..ab7545d37dc9e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -294,11 +294,56 @@ extern "rust-intrinsic" { /// The [nomicon](../../nomicon/transmutes.html) has additional /// documentation. /// + /// # Examples + /// + /// There are a few things that `transmute` is really useful for. + /// + /// Getting the bitpattern of a floating point type (or, more generally, + /// type punning, when T and U aren't pointers): + /// + /// ``` + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; + /// assert_eq!(bitpattern, 0x3F800000); + /// ``` + /// + /// Turning a pointer into a function pointer: + /// + /// ``` + /// fn foo() -> i32 { + /// 0 + /// } + /// let pointer = foo as *const (); + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; + /// assert_eq!(function(), 0); + /// ``` + /// + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: + /// + /// ``` + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// std::mem::transmute::, R<'static>>(r) + /// } + /// + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) + /// } + /// ``` + /// /// # Alternatives /// - /// There are very few good cases for `transmute`. Most can be achieved - /// through other means. Some more or less common uses, and a better way, - /// are as follows: + /// However, many uses of `transmute` can be achieved through other means. + /// This is unfortunate because either `transmute` isn't guaranteed to work + /// in that case, and only does because of rustc's current implemenation; + /// or, more commonly, `transmute` is just too powerful. It can transform + /// any type into any other, with just the caveat that they're the same + /// size. Some more or less common uses, and a better way, are as follows: /// /// Turning a pointer into a `usize`: /// @@ -428,48 +473,6 @@ extern "rust-intrinsic" { /// } /// } /// ``` - /// - /// # Examples - /// - /// There are valid uses of transmute, though they are few and far between. - /// - /// Getting the bitpattern of a floating point type: - /// - /// ``` - /// let bitpattern = unsafe { - /// std::mem::transmute::(1.0) - /// }; - /// assert_eq!(bitpattern, 0x3F800000); - /// ``` - /// - /// Turning a pointer into a function pointer (this is not guaranteed to - /// work in Rust, although, for example, Linux does make this guarantee): - /// - /// ``` - /// fn foo() -> i32 { - /// 0 - /// } - /// let pointer = foo as *const (); - /// let function = unsafe { - /// std::mem::transmute::<*const (), fn() -> i32>(pointer) - /// }; - /// assert_eq!(function(), 0); - /// ``` - /// - /// Extending a lifetime, or shortening an invariant lifetime; this is - /// advanced, very unsafe rust: - /// - /// ``` - /// struct R<'a>(&'a i32); - /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// std::mem::transmute::, R<'static>>(r) - /// } - /// - /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b mut R<'c> { - /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) - /// } - /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From c0bee60adbf979ae624cfcdc7610044c357794a0 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sun, 10 Jul 2016 23:17:02 +0200 Subject: [PATCH 022/150] Make it nicer from @alexandermerritt --- src/libcore/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ab7545d37dc9e..d6fb1816b5fa0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -339,11 +339,11 @@ extern "rust-intrinsic" { /// # Alternatives /// /// However, many uses of `transmute` can be achieved through other means. - /// This is unfortunate because either `transmute` isn't guaranteed to work - /// in that case, and only does because of rustc's current implemenation; - /// or, more commonly, `transmute` is just too powerful. It can transform + /// `transmute` can transform /// any type into any other, with just the caveat that they're the same - /// size. Some more or less common uses, and a better way, are as follows: + /// size, and it sometimes results in interesting results. Below are common + /// applications of `transmute` which can be replaced with safe applications + /// of `as`: /// /// Turning a pointer into a `usize`: /// @@ -374,7 +374,8 @@ extern "rust-intrinsic" { /// let val_transmuted = unsafe { /// std::mem::transmute::<&mut i32, &mut u32>(ptr) /// }; - /// // Now, put together `as` and reborrowing + /// // Now, put together `as` and reborrowing - note the chaining of `as` + /// // `as` is not transitive /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// From 0bcf64cfc792c39b09d0626649c3d0c18257499a Mon Sep 17 00:00:00 2001 From: Murarth Date: Mon, 11 Jul 2016 15:06:28 -0700 Subject: [PATCH 023/150] Add method `String::insert_str` --- src/libcollections/string.rs | 62 ++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index eedf4c2c11f34..ce3f96893242f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1126,18 +1126,62 @@ impl String { assert!(idx <= len); assert!(self.is_char_boundary(idx)); let bits = ch.encode_utf8(); - let bits = bits.as_slice(); - let amt = bits.len(); + + unsafe { + self.insert_bytes(idx, bits.as_slice()); + } + } + + unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { + let len = self.len(); + let amt = bytes.len(); self.vec.reserve(amt); + ptr::copy(self.vec.as_ptr().offset(idx as isize), + self.vec.as_mut_ptr().offset((idx + amt) as isize), + len - idx); + ptr::copy(bytes.as_ptr(), + self.vec.as_mut_ptr().offset(idx as isize), + amt); + self.vec.set_len(len + amt); + } + + /// Inserts a string into this `String` at a byte position. + /// + /// This is an `O(n)` operation as it requires copying every element in the + /// buffer. + /// + /// # Panics + /// + /// Panics if `idx` is larger than the `String`'s length, or if it does not + /// lie on a [`char`] boundary. + /// + /// [`char`]: ../../std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(insert_str)] + /// + /// let mut s = String::from("bar"); + /// + /// s.insert_str(0, "foo"); + /// + /// assert_eq!("foobar", s); + /// ``` + #[inline] + #[unstable(feature = "insert_str", + reason = "recent addition", + issue = "0")] + pub fn insert_str(&mut self, idx: usize, string: &str) { + let len = self.len(); + assert!(idx <= len); + assert!(self.is_char_boundary(idx)); + unsafe { - ptr::copy(self.vec.as_ptr().offset(idx as isize), - self.vec.as_mut_ptr().offset((idx + amt) as isize), - len - idx); - ptr::copy(bits.as_ptr(), - self.vec.as_mut_ptr().offset(idx as isize), - amt); - self.vec.set_len(len + amt); + self.insert_bytes(idx, string.as_bytes()); } } From 42326ec2a48a6a70d737b27cb7930810360a1df6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 16 Jul 2016 18:00:05 +0200 Subject: [PATCH 024/150] Add examples for VecDeque --- src/libcollections/vec_deque.rs | 72 ++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 84a0bbbd24983..9e4428ec57d50 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -365,12 +365,28 @@ impl VecDeque { impl VecDeque { /// Creates an empty `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque = VecDeque::new(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> VecDeque { VecDeque::with_capacity(INITIAL_CAPACITY) } /// Creates an empty `VecDeque` with space for at least `n` elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque = VecDeque::with_capacity(10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(n: usize) -> VecDeque { // +1 since the ringbuffer always leaves one space empty @@ -696,6 +712,25 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// vector.push_back(2); + /// + /// assert_eq!(vector.as_slices(), (&[0u32, 1, 2] as &[u32], &[] as &[u32])); + /// + /// vector.push_front(10); + /// vector.push_front(9); + /// + /// assert_eq!(vector.as_slices(), (&[9u32, 10] as &[u32], &[0u32, 1, 2] as &[u32])); + /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_slices(&self) -> (&[T], &[T]) { @@ -715,6 +750,24 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// + /// vector.push_front(10); + /// vector.push_front(9); + /// + /// vector.as_mut_slices().0[0] = 42; + /// vector.as_mut_slices().1[0] = 24; + /// assert_eq!(vector.as_slices(), (&[42u32, 10] as &[u32], &[24u32, 1] as &[u32])); + /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { @@ -789,7 +842,7 @@ impl VecDeque { /// /// ``` /// use std::collections::VecDeque; - + /// /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); /// assert_eq!(vec![3].into_iter().collect::>(), v.drain(2..).collect()); /// assert_eq!(vec![1, 2].into_iter().collect::>(), v); @@ -875,6 +928,22 @@ impl VecDeque { /// Returns `true` if the `VecDeque` contains an element equal to the /// given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_contains)] + /// + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// + /// assert_eq!(vector.contains(&1), true); + /// assert_eq!(vector.contains(&10), false); + /// ``` #[unstable(feature = "vec_deque_contains", reason = "recently added", issue = "32630")] pub fn contains(&self, x: &T) -> bool @@ -1404,6 +1473,7 @@ impl VecDeque { /// Returns `None` if `index` is out of bounds. /// /// # Examples + /// /// ``` /// use std::collections::VecDeque; /// From 0c9a6f65d0163c4b24b4e8ebb6474282f912f6f8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 16 Jul 2016 17:27:55 +0200 Subject: [PATCH 025/150] Add examples for LinkedList --- src/libcollections/linked_list.rs | 74 +++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index dbede94f0bf1b..3d5c3125fae24 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -172,6 +172,14 @@ impl Default for LinkedList { impl LinkedList { /// Creates an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new(); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Self { @@ -226,6 +234,24 @@ impl LinkedList { } /// Provides a forward iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&0)); + /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), None); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { @@ -238,6 +264,28 @@ impl LinkedList { } /// Provides a forward iterator with mutable references. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// for element in list.iter_mut() { + /// *element += 10; + /// } + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&10)); + /// assert_eq!(iter.next(), Some(&11)); + /// assert_eq!(iter.next(), Some(&12)); + /// assert_eq!(iter.next(), None); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut { @@ -289,7 +337,6 @@ impl LinkedList { /// /// dl.push_back(3); /// assert_eq!(dl.len(), 3); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -316,7 +363,6 @@ impl LinkedList { /// dl.clear(); /// assert_eq!(dl.len(), 0); /// assert_eq!(dl.front(), None); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -326,6 +372,23 @@ impl LinkedList { /// Returns `true` if the `LinkedList` contains an element equal to the /// given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_contains)] + /// + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// assert_eq!(list.contains(&0), true); + /// assert_eq!(list.contains(&10), false); + /// ``` #[unstable(feature = "linked_list_contains", reason = "recently added", issue = "32630")] pub fn contains(&self, x: &T) -> bool @@ -347,7 +410,6 @@ impl LinkedList { /// /// dl.push_front(1); /// assert_eq!(dl.front(), Some(&1)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -374,7 +436,6 @@ impl LinkedList { /// Some(x) => *x = 5, /// } /// assert_eq!(dl.front(), Some(&5)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -395,7 +456,6 @@ impl LinkedList { /// /// dl.push_back(1); /// assert_eq!(dl.back(), Some(&1)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -422,7 +482,6 @@ impl LinkedList { /// Some(x) => *x = 5, /// } /// assert_eq!(dl.back(), Some(&5)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -446,7 +505,6 @@ impl LinkedList { /// /// dl.push_front(1); /// assert_eq!(dl.front().unwrap(), &1); - /// /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_front(&mut self, elt: T) { @@ -471,9 +529,7 @@ impl LinkedList { /// assert_eq!(d.pop_front(), Some(3)); /// assert_eq!(d.pop_front(), Some(1)); /// assert_eq!(d.pop_front(), None); - /// /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] pub fn pop_front(&mut self) -> Option { self.pop_front_node().map(Node::into_element) From 3b5d71e0cfb2d81f588a0b8929e796f3b68488e0 Mon Sep 17 00:00:00 2001 From: "Novotnik, Petr" Date: Sun, 17 Jul 2016 12:06:10 +0200 Subject: [PATCH 026/150] Make .enumerate() example self-explanatory --- src/doc/book/loops.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md index e681d1bee0618..e4cb861d3b0f5 100644 --- a/src/doc/book/loops.md +++ b/src/doc/book/loops.md @@ -105,19 +105,19 @@ When you need to keep track of how many times you already looped, you can use th #### On ranges: ```rust -for (i, j) in (5..10).enumerate() { - println!("i = {} and j = {}", i, j); +for (index, value) in (5..10).enumerate() { + println!("index = {} and value = {}", index, value); } ``` Outputs: ```text -i = 0 and j = 5 -i = 1 and j = 6 -i = 2 and j = 7 -i = 3 and j = 8 -i = 4 and j = 9 +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. From 6a09df9079279297c5f68c0a1214a17e8193cd6a Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Sun, 17 Jul 2016 11:31:44 -0400 Subject: [PATCH 027/150] implement AddAssign for String --- src/libcollections/string.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index eedf4c2c11f34..688f057604251 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -59,7 +59,7 @@ use core::fmt; use core::hash; use core::iter::FromIterator; use core::mem; -use core::ops::{self, Add, Index, IndexMut}; +use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str::pattern::Pattern; use rustc_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; @@ -1559,6 +1559,14 @@ impl<'a> Add<&'a str> for String { } } +#[stable(feature = "rust1", since = "1.11.0")] +impl<'a> AddAssign<&'a str> for String { + #[inline] + fn add_assign(&mut self, other: &str) { + self.push_str(other); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; From ce442b4f5195ff6af27ae3335c7bb372015c1407 Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 20 Jul 2016 15:02:33 +0200 Subject: [PATCH 028/150] Add debug for hash_map::{Entry, VacantEntry, OccupiedEntry} --- src/libstd/collections/hash/map.rs | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 60d7e01d98814..a03249e006356 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1351,6 +1351,20 @@ pub enum Entry<'a, K: 'a, V: 'a> { ), } +#[stable(feature= "debug_hash_map", since = "1.12.0")] +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry") + .field(v) + .finish(), + Occupied(ref o) => f.debug_tuple("Entry") + .field(o) + .finish(), + } + } +} + /// A view into a single occupied location in a HashMap. #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { @@ -1358,6 +1372,16 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { elem: FullBucket>, } +#[stable(feature= "debug_hash_map", since = "1.12.0")] +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + /// A view into a single empty location in a HashMap. #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { @@ -1366,6 +1390,15 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { elem: VacantEntryState>, } +#[stable(feature= "debug_hash_map", since = "1.12.0")] +impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("VacantEntry") + .field(self.key()) + .finish() + } +} + /// Possible states of a VacantEntry. enum VacantEntryState { /// The index is occupied, but the key to insert has precedence, From d820fcba122771742f8bdeed4c8619292f3450f6 Mon Sep 17 00:00:00 2001 From: Mark Buer Date: Mon, 18 Jul 2016 17:54:15 +0930 Subject: [PATCH 029/150] Remove rustdoc reference to `walk_dir` --- 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 83439b3f13215..c28f70b8692ad 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -791,8 +791,8 @@ impl Iterator for ReadDir { impl DirEntry { /// Returns the full path to the file that this entry represents. /// - /// The full path is created by joining the original path to `read_dir` or - /// `walk_dir` with the filename of this entry. + /// The full path is created by joining the original path to `read_dir` + /// with the filename of this entry. /// /// # Examples /// From 0042c1a62094ea88787dc3a9ca19169ad0c425c9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 16 Jul 2016 16:12:56 +0000 Subject: [PATCH 030/150] Add `librustc_driver::driver::reset_thread_local_state` and remove the thread local state reset at the beginning of `phase_1_parse_input`. --- src/librustc_driver/driver.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ab3b20e08c809..9a94cc16bfe8c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -478,10 +478,6 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, cfg: ast::CrateConfig, input: &Input) -> PResult<'a, ast::Crate> { - // These may be left in an incoherent state after a previous compile. - syntax::ext::hygiene::reset_hygiene_data(); - // `clear_ident_interner` can be used to free memory, but it does not restore the initial state. - token::reset_ident_interner(); let continue_after_error = sess.opts.continue_parse_after_error; sess.diagnostic().set_continue_after_error(continue_after_error); @@ -1298,3 +1294,11 @@ pub fn build_output_filenames(input: &Input, } } } + +// For use by the `rusti` project (https://github.com/murarth/rusti). +pub fn reset_thread_local_state() { + // These may be left in an incoherent state after a previous compile. + syntax::ext::hygiene::reset_hygiene_data(); + // `clear_ident_interner` can be used to free memory, but it does not restore the initial state. + token::reset_ident_interner(); +} From cac58ab5b7501a7ea3146a4521d8f34389bc3f73 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Mon, 18 Jul 2016 14:00:35 -0400 Subject: [PATCH 031/150] update the since field to 1.12.0 for String AddAssign --- src/libcollections/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 688f057604251..3920b57962c87 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1559,7 +1559,7 @@ impl<'a> Add<&'a str> for String { } } -#[stable(feature = "rust1", since = "1.11.0")] +#[stable(feature = "rust1", since = "1.12.0")] impl<'a> AddAssign<&'a str> for String { #[inline] fn add_assign(&mut self, other: &str) { From 9b8130666de569d6d27332d42df43859a57b3e72 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Mon, 18 Jul 2016 14:27:17 -0400 Subject: [PATCH 032/150] use a new feature name for String AddAssign --- src/libcollections/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 3920b57962c87..71c6a6c892eab 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1559,7 +1559,7 @@ impl<'a> Add<&'a str> for String { } } -#[stable(feature = "rust1", since = "1.12.0")] +#[stable(feature = "stringaddassign", since = "1.12.0")] impl<'a> AddAssign<&'a str> for String { #[inline] fn add_assign(&mut self, other: &str) { From f77bcc86b1624644c4e897b9fb1f094d8ea81f15 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 18 Jul 2016 16:25:11 -0700 Subject: [PATCH 033/150] rustc: Remove soft-float from MIPS targets Right now two MIPS targets in the compiler, `mips-unknown-linux-{gnu,musl}` both generate object files using the soft-float ABI through LLVM by default. This is also expressed as the `-C soft-float` codegen option and otherwise isn't used for any other target in the compiler. This option was added quite some time ago (back in #9617), and nowadays it's more appropriate to be done through a codegen option. This is motivated by #34743 which necessitated an upgrade in the CMake installation on our bots which necessitated an upgrade in the Ubuntu version which invalidated the MIPS compilers we were using. The new MIPS compilers (coming from Debian I believe) all have hard float enabled by default and soft float support not built in. This meant that we couldn't upgrade the bots until #34841 landed because otherwise we would fail to compile C code as the `-msoft-float` option wouldn't work. Unfortunately, though, this means that once we upgrade the bots the C code we're compiling will be compiled for hard float and the Rust code will be compiled for soft float, a bad mismatch! This PR remedies the situation such that Rust will compile with hard float as well. If this lands it will likely produce broken nightlies for a day or two while we get around to upgrading the bots because the current C toolchain only produces soft-float binaries, and now rust will be hard-float. Hopefully, though, the upgrade can go smoothly! --- src/librustc_back/target/mips_unknown_linux_gnu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index 794e4d4996c94..ceb17e53a5552 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -22,7 +22,7 @@ pub fn target() -> Target { target_vendor: "unknown".to_string(), options: TargetOptions { cpu: "mips32r2".to_string(), - features: "+mips32r2,+soft-float".to_string(), + features: "+mips32r2".to_string(), max_atomic_width: 32, ..super::linux_base::opts() }, From b45c15eccaeca39099db3c8028e7a73e5caf6503 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 16 Jul 2016 15:07:35 -0700 Subject: [PATCH 034/150] mk: Remove -Wall -Werror everywhere We're not writing C code, so there's not really much of a reason for us to get warnings and errors from code we haven't written! --- mk/cfg/aarch64-apple-ios.mk | 2 +- mk/cfg/armv7-apple-ios.mk | 2 +- mk/cfg/armv7s-apple-ios.mk | 2 +- mk/cfg/asmjs-unknown-emscripten.mk | 2 +- mk/cfg/i386-apple-ios.mk | 2 +- mk/cfg/i586-unknown-linux-gnu.mk | 2 +- mk/cfg/i686-apple-darwin.mk | 2 +- mk/cfg/i686-pc-windows-gnu.mk | 2 +- mk/cfg/i686-unknown-freebsd.mk | 2 +- mk/cfg/i686-unknown-linux-gnu.mk | 2 +- mk/cfg/i686-unknown-linux-musl.mk | 2 +- mk/cfg/powerpc-unknown-linux-gnu.mk | 2 +- mk/cfg/powerpc64-unknown-linux-gnu.mk | 2 +- mk/cfg/powerpc64le-unknown-linux-gnu.mk | 2 +- mk/cfg/x86_64-apple-darwin.mk | 2 +- mk/cfg/x86_64-apple-ios.mk | 2 +- mk/cfg/x86_64-pc-windows-gnu.mk | 2 +- mk/cfg/x86_64-rumprun-netbsd.mk | 2 +- mk/cfg/x86_64-sun-solaris.mk | 2 +- mk/cfg/x86_64-unknown-bitrig.mk | 2 +- mk/cfg/x86_64-unknown-dragonfly.mk | 2 +- mk/cfg/x86_64-unknown-freebsd.mk | 2 +- mk/cfg/x86_64-unknown-linux-gnu.mk | 2 +- mk/cfg/x86_64-unknown-linux-musl.mk | 2 +- mk/cfg/x86_64-unknown-netbsd.mk | 2 +- mk/cfg/x86_64-unknown-openbsd.mk | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/mk/cfg/aarch64-apple-ios.mk b/mk/cfg/aarch64-apple-ios.mk index 8cd09fa9043c8..5d822f1b1aba6 100644 --- a/mk/cfg/aarch64-apple-ios.mk +++ b/mk/cfg/aarch64-apple-ios.mk @@ -17,7 +17,7 @@ CFG_STATIC_LIB_NAME_aarch64-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_aarch64-apple-ios = lib$(1)-*.a.dSYM CFG_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) CFG_JEMALLOC_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) -CFG_GCCISH_CFLAGS_aarch64-apple-ios := -Wall -Werror -fPIC $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) +CFG_GCCISH_CFLAGS_aarch64-apple-ios := -fPIC $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) CFG_GCCISH_CXXFLAGS_aarch64-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) -I$(CFG_IOS_SDK_aarch64-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_aarch64-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_aarch64-apple-ios) -Wl,-no_compact_unwind CFG_GCCISH_DEF_FLAG_aarch64-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/armv7-apple-ios.mk b/mk/cfg/armv7-apple-ios.mk index d4696976574e9..34ca4de6563e4 100644 --- a/mk/cfg/armv7-apple-ios.mk +++ b/mk/cfg/armv7-apple-ios.mk @@ -15,7 +15,7 @@ CFG_INSTALL_ONLY_RLIB_armv7-apple-ios = 1 CFG_STATIC_LIB_NAME_armv7-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_armv7-apple-ios = lib$(1)-*.a.dSYM CFG_JEMALLOC_CFLAGS_armv7-apple-ios := -arch armv7 -mfpu=vfp3 $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -CFG_GCCISH_CFLAGS_armv7-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -mfpu=vfp3 -arch armv7 +CFG_GCCISH_CFLAGS_armv7-apple-ios := -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -mfpu=vfp3 -arch armv7 CFG_GCCISH_CXXFLAGS_armv7-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -I$(CFG_IOS_SDK_armv7-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_armv7-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7-apple-ios) -Wl,-no_compact_unwind CFG_GCCISH_DEF_FLAG_armv7-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/armv7s-apple-ios.mk b/mk/cfg/armv7s-apple-ios.mk index efad43d25627d..6da7905a7003b 100644 --- a/mk/cfg/armv7s-apple-ios.mk +++ b/mk/cfg/armv7s-apple-ios.mk @@ -15,7 +15,7 @@ CFG_INSTALL_ONLY_RLIB_armv7s-apple-ios = 1 CFG_STATIC_LIB_NAME_armv7s-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_armv7s-apple-ios = lib$(1)-*.a.dSYM CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -CFG_GCCISH_CFLAGS_armv7s-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -arch armv7s +CFG_GCCISH_CFLAGS_armv7s-apple-ios := -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -arch armv7s CFG_GCCISH_CXXFLAGS_armv7s-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -I$(CFG_IOS_SDK_armv7s-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_armv7s-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7s-apple-ios) -Wl,-no_compact_unwind CFG_GCCISH_DEF_FLAG_armv7s-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/asmjs-unknown-emscripten.mk b/mk/cfg/asmjs-unknown-emscripten.mk index 9c98c0a6b4c9d..a98a51b06b5d3 100644 --- a/mk/cfg/asmjs-unknown-emscripten.mk +++ b/mk/cfg/asmjs-unknown-emscripten.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_asmjs-unknown-emscripten=lib$(1).a CFG_LIB_GLOB_asmjs-unknown-emscripten=lib$(1)-*.so CFG_LIB_DSYM_GLOB_asmjs-unknown-emscripten=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_asmjs-unknown-emscripten := -m32 $(CFLAGS) -CFG_GCCISH_CFLAGS_asmjs-unknown-emscripten := -Wall -Werror -g -fPIC -m32 $(CFLAGS) +CFG_GCCISH_CFLAGS_asmjs-unknown-emscripten := -g -fPIC -m32 $(CFLAGS) CFG_GCCISH_CXXFLAGS_asmjs-unknown-emscripten := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_asmjs-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_asmjs-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/i386-apple-ios.mk b/mk/cfg/i386-apple-ios.mk index 373e2e3b65d15..bfb7fa281f242 100644 --- a/mk/cfg/i386-apple-ios.mk +++ b/mk/cfg/i386-apple-ios.mk @@ -14,7 +14,7 @@ CFG_LIB_GLOB_i386-apple-ios = lib$(1)-*.dylib CFG_INSTALL_ONLY_RLIB_i386-apple-ios = 1 CFG_STATIC_LIB_NAME_i386-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_i386-apple-ios = lib$(1)-*.dylib.dSYM -CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios) +CFG_GCCISH_CFLAGS_i386-apple-ios := -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios) CFG_GCCISH_CXXFLAGS_i386-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_i386-apple-ios) -I$(CFG_IOSSIM_SDK_i386-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_i386-apple-ios := -lpthread -m32 -Wl,-no_compact_unwind -m32 -Wl,-syslibroot $(CFG_IOSSIM_SDK_i386-apple-ios) CFG_GCCISH_DEF_FLAG_i386-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/i586-unknown-linux-gnu.mk b/mk/cfg/i586-unknown-linux-gnu.mk index 2b28550320d85..14b9ebfdba668 100644 --- a/mk/cfg/i586-unknown-linux-gnu.mk +++ b/mk/cfg/i586-unknown-linux-gnu.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i586-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_i586-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_i586-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i586-unknown-linux-gnu := -m32 $(CFLAGS) -march=pentium -CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS) -march=pentium +CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) -march=pentium CFG_GCCISH_CXXFLAGS_i586-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) -march=pentium CFG_GCCISH_LINK_FLAGS_i586-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_i586-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/i686-apple-darwin.mk b/mk/cfg/i686-apple-darwin.mk index 7ebb492bb21fe..e4b3431e8b67f 100644 --- a/mk/cfg/i686-apple-darwin.mk +++ b/mk/cfg/i686-apple-darwin.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i686-apple-darwin=lib$(1).a CFG_LIB_GLOB_i686-apple-darwin=lib$(1)-*.dylib CFG_LIB_DSYM_GLOB_i686-apple-darwin=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-apple-darwin := -m32 -arch i386 $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386 $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-apple-darwin := -g -fPIC -m32 -arch i386 $(CFLAGS) CFG_GCCISH_CXXFLAGS_i686-apple-darwin := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_i686-apple-darwin := -dynamiclib -pthread -framework CoreServices -m32 CFG_GCCISH_DEF_FLAG_i686-apple-darwin := -Wl,-exported_symbols_list, diff --git a/mk/cfg/i686-pc-windows-gnu.mk b/mk/cfg/i686-pc-windows-gnu.mk index 3426b30aeeb85..50c2b8c98acd3 100644 --- a/mk/cfg/i686-pc-windows-gnu.mk +++ b/mk/cfg/i686-pc-windows-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_i686-pc-windows-gnu=$(1).lib CFG_LIB_GLOB_i686-pc-windows-gnu=$(1)-*.dll CFG_LIB_DSYM_GLOB_i686-pc-windows-gnu=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-pc-windows-gnu := -march=i686 -m32 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -Wall -Werror -g -m32 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -g -m32 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) CFG_GCCISH_CXXFLAGS_i686-pc-windows-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_i686-pc-windows-gnu := -shared -g -m32 CFG_GCCISH_DEF_FLAG_i686-pc-windows-gnu := diff --git a/mk/cfg/i686-unknown-freebsd.mk b/mk/cfg/i686-unknown-freebsd.mk index bbc0c2d6f396e..a9d4446d5d49b 100644 --- a/mk/cfg/i686-unknown-freebsd.mk +++ b/mk/cfg/i686-unknown-freebsd.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i686-unknown-freebsd=lib$(1).a CFG_LIB_GLOB_i686-unknown-freebsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_i686-unknown-freebsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-unknown-freebsd := -m32 -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -Wall -Werror -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_i686-unknown-freebsd := -m32 -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_i686-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_i686-unknown-freebsd := diff --git a/mk/cfg/i686-unknown-linux-gnu.mk b/mk/cfg/i686-unknown-linux-gnu.mk index 129af8ac69609..9e2312008a10a 100644 --- a/mk/cfg/i686-unknown-linux-gnu.mk +++ b/mk/cfg/i686-unknown-linux-gnu.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i686-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_i686-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_i686-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-unknown-linux-gnu := -m32 $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS) -march=i686 +CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) -march=i686 CFG_GCCISH_CXXFLAGS_i686-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_i686-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/i686-unknown-linux-musl.mk b/mk/cfg/i686-unknown-linux-musl.mk index c1cd20a843cec..80918728316a6 100644 --- a/mk/cfg/i686-unknown-linux-musl.mk +++ b/mk/cfg/i686-unknown-linux-musl.mk @@ -8,7 +8,7 @@ CFG_LIB_NAME_i686-unknown-linux-musl=lib$(1).so CFG_STATIC_LIB_NAME_i686-unknown-linux-musl=lib$(1).a CFG_LIB_GLOB_i686-unknown-linux-musl=lib$(1)-*.so CFG_JEMALLOC_CFLAGS_i686-unknown-linux-musl := -m32 -Wl,-melf_i386 -CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -Wall -Werror -g -fPIC -m32 -Wl,-melf_i386 +CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -g -fPIC -m32 -Wl,-melf_i386 CFG_GCCISH_CXXFLAGS_i686-unknown-linux-musl := CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-musl := CFG_GCCISH_DEF_FLAG_i686-unknown-linux-musl := diff --git a/mk/cfg/powerpc-unknown-linux-gnu.mk b/mk/cfg/powerpc-unknown-linux-gnu.mk index dda957673eba6..9c5720de4b310 100644 --- a/mk/cfg/powerpc-unknown-linux-gnu.mk +++ b/mk/cfg/powerpc-unknown-linux-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_powerpc-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_powerpc-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_powerpc-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_CFLAGS_powerpc-unknown-linux-gnu := -m32 $(CFLAGS) -CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS) +CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) CFG_GCCISH_CXXFLAGS_powerpc-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_powerpc-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_powerpc-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/powerpc64-unknown-linux-gnu.mk b/mk/cfg/powerpc64-unknown-linux-gnu.mk index f6e6436f61578..389bb6f0cab49 100644 --- a/mk/cfg/powerpc64-unknown-linux-gnu.mk +++ b/mk/cfg/powerpc64-unknown-linux-gnu.mk @@ -10,7 +10,7 @@ CFG_LIB_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_powerpc64-unknown-linux-gnu := -m64 CFG_CFLAGS_powerpc64-unknown-linux-gnu := -m64 $(CFLAGS) -CFG_GCCISH_CFLAGS_powerpc64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_powerpc64-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS) CFG_GCCISH_CXXFLAGS_powerpc64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_powerpc64-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 CFG_GCCISH_DEF_FLAG_powerpc64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/powerpc64le-unknown-linux-gnu.mk b/mk/cfg/powerpc64le-unknown-linux-gnu.mk index a2049331ab2e9..6884fa11e7412 100644 --- a/mk/cfg/powerpc64le-unknown-linux-gnu.mk +++ b/mk/cfg/powerpc64le-unknown-linux-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_powerpc64le-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_powerpc64le-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_powerpc64le-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_CFLAGS_powerpc64le-unknown-linux-gnu := -m64 $(CFLAGS) -CFG_GCCISH_CFLAGS_powerpc64le-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_powerpc64le-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS) CFG_GCCISH_CXXFLAGS_powerpc64le-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_powerpc64le-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 CFG_GCCISH_DEF_FLAG_powerpc64le-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/x86_64-apple-darwin.mk b/mk/cfg/x86_64-apple-darwin.mk index 4c68d3dcf37b4..8af47b671a850 100644 --- a/mk/cfg/x86_64-apple-darwin.mk +++ b/mk/cfg/x86_64-apple-darwin.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-apple-darwin=lib$(1).a CFG_LIB_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib CFG_LIB_DSYM_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-apple-darwin := -m64 -arch x86_64 $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -Wall -Werror -g -fPIC -m64 -arch x86_64 $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -g -fPIC -m64 -arch x86_64 $(CFLAGS) CFG_GCCISH_CXXFLAGS_x86_64-apple-darwin := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-apple-darwin := -dynamiclib -pthread -framework CoreServices -m64 CFG_GCCISH_DEF_FLAG_x86_64-apple-darwin := -Wl,-exported_symbols_list, diff --git a/mk/cfg/x86_64-apple-ios.mk b/mk/cfg/x86_64-apple-ios.mk index dd6080fdb0bab..764cdc15996d0 100644 --- a/mk/cfg/x86_64-apple-ios.mk +++ b/mk/cfg/x86_64-apple-ios.mk @@ -16,7 +16,7 @@ CFG_STATIC_LIB_NAME_x86_64-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_x86_64-apple-ios = lib$(1)-*.a.dSYM CFG_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) CFG_JEMALLOC_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) -CFG_GCCISH_CFLAGS_x86_64-apple-ios := -Wall -Werror -fPIC $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) +CFG_GCCISH_CFLAGS_x86_64-apple-ios := -fPIC $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) CFG_GCCISH_CXXFLAGS_x86_64-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) -I$(CFG_IOSSIM_SDK_x86_64-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_x86_64-apple-ios := -lpthread -Wl,-no_compact_unwind -m64 -Wl,-syslibroot $(CFG_IOSSIM_SDK_x86_64-apple-ios) CFG_GCCISH_DEF_FLAG_x86_64-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/x86_64-pc-windows-gnu.mk b/mk/cfg/x86_64-pc-windows-gnu.mk index f0732d08c71ea..82e7b23279fb5 100644 --- a/mk/cfg/x86_64-pc-windows-gnu.mk +++ b/mk/cfg/x86_64-pc-windows-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_x86_64-pc-windows-gnu=$(1).lib CFG_LIB_GLOB_x86_64-pc-windows-gnu=$(1)-*.dll CFG_LIB_DSYM_GLOB_x86_64-pc-windows-gnu=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-pc-windows-gnu := -m64 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -Wall -Werror -g -m64 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -g -m64 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-gnu := -shared -g -m64 CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-gnu := diff --git a/mk/cfg/x86_64-rumprun-netbsd.mk b/mk/cfg/x86_64-rumprun-netbsd.mk index 1b5aa12274d4e..53d58b9fceaa6 100644 --- a/mk/cfg/x86_64-rumprun-netbsd.mk +++ b/mk/cfg/x86_64-rumprun-netbsd.mk @@ -9,7 +9,7 @@ CFG_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).so CFG_STATIC_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).a CFG_LIB_GLOB_x86_64-rumprun-netbsd=lib$(1)-*.so CFG_JEMALLOC_CFLAGS_x86_64-rumprun-netbsd := -m64 -CFG_GCCISH_CFLAGS_x86_64-rumprun-netbsd := -Wall -Werror -g -fPIC -m64 +CFG_GCCISH_CFLAGS_x86_64-rumprun-netbsd := -g -fPIC -m64 CFG_GCCISH_CXXFLAGS_x86_64-rumprun-netbsd := CFG_GCCISH_LINK_FLAGS_x86_64-rumprun-netbsd := CFG_GCCISH_DEF_FLAG_x86_64-rumprun-netbsd := diff --git a/mk/cfg/x86_64-sun-solaris.mk b/mk/cfg/x86_64-sun-solaris.mk index 0a09a5cf72d9f..7fc323b234aee 100644 --- a/mk/cfg/x86_64-sun-solaris.mk +++ b/mk/cfg/x86_64-sun-solaris.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_x86_64-sun-solaris=lib$(1).a CFG_LIB_GLOB_x86_64-sun-solaris=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-sun-solaris=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-sun-solaris := -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-sun-solaris := -Wall -Werror -g -D_POSIX_PTHREAD_SEMANTICS -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-sun-solaris := -g -D_POSIX_PTHREAD_SEMANTICS -fPIC -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-sun-solaris := -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_x86_64-sun-solaris := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-sun-solaris := diff --git a/mk/cfg/x86_64-unknown-bitrig.mk b/mk/cfg/x86_64-unknown-bitrig.mk index 76b39b4502548..8ac31c176188b 100644 --- a/mk/cfg/x86_64-unknown-bitrig.mk +++ b/mk/cfg/x86_64-unknown-bitrig.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-bitrig=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-bitrig=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-bitrig=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIE -fPIC -m64 -I/usr/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -fPIE -fPIC -m64 -I/usr/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS) CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-bitrig := diff --git a/mk/cfg/x86_64-unknown-dragonfly.mk b/mk/cfg/x86_64-unknown-dragonfly.mk index 4015293826e1a..579a9a809e205 100644 --- a/mk/cfg/x86_64-unknown-dragonfly.mk +++ b/mk/cfg/x86_64-unknown-dragonfly.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-dragonfly=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-dragonfly=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-dragonfly=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-dragonfly := -m64 -I/usr/include -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -Wall -Werror -g -fPIC -m64 -I/usr/include -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -g -fPIC -m64 -I/usr/include -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-dragonfly := -shared -fPIC -g -pthread -lrt -m64 CFG_GCCISH_DEF_FLAG_x86_64-unknown-dragonfly := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-dragonfly := diff --git a/mk/cfg/x86_64-unknown-freebsd.mk b/mk/cfg/x86_64-unknown-freebsd.mk index 1bd43168b4f69..c700601eac7a1 100644 --- a/mk/cfg/x86_64-unknown-freebsd.mk +++ b/mk/cfg/x86_64-unknown-freebsd.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-freebsd=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-freebsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-freebsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-freebsd := -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -g -fPIC -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-freebsd := -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_x86_64-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-freebsd := diff --git a/mk/cfg/x86_64-unknown-linux-gnu.mk b/mk/cfg/x86_64-unknown-linux-gnu.mk index 044c687c9fc4c..817ce22e4f59d 100644 --- a/mk/cfg/x86_64-unknown-linux-gnu.mk +++ b/mk/cfg/x86_64-unknown-linux-gnu.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-gnu := -m64 -CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 +CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -g -fPIC -m64 CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-gnu := -fno-rtti CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/x86_64-unknown-linux-musl.mk b/mk/cfg/x86_64-unknown-linux-musl.mk index dfe9de18f5787..3a03b2accd541 100644 --- a/mk/cfg/x86_64-unknown-linux-musl.mk +++ b/mk/cfg/x86_64-unknown-linux-musl.mk @@ -8,7 +8,7 @@ CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64 -CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -Wall -Werror -g -fPIC -m64 +CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -g -fPIC -m64 CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-musl := CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-musl := CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-musl := diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk index a77c5fa542eb1..93bb2d672653e 100644 --- a/mk/cfg/x86_64-unknown-netbsd.mk +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-netbsd=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-netbsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-netbsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-netbsd := -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -g -fPIC -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-netbsd := -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_x86_64-unknown-netbsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-netbsd := diff --git a/mk/cfg/x86_64-unknown-openbsd.mk b/mk/cfg/x86_64-unknown-openbsd.mk index f1e45d7640992..7cca1f7b18b3d 100644 --- a/mk/cfg/x86_64-unknown-openbsd.mk +++ b/mk/cfg/x86_64-unknown-openbsd.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-openbsd=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-openbsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-openbsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-openbsd := -m64 -I/usr/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -Wall -Werror -g -fPIC -m64 -I/usr/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -g -fPIC -m64 -I/usr/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-openbsd := -shared -fPIC -g -pthread -m64 CFG_GCCISH_DEF_FLAG_x86_64-unknown-openbsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-openbsd := From 4c605e52e6c6ae5e61b31d5979e1f56fcabe29e5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 19 Jul 2016 05:47:28 -0400 Subject: [PATCH 035/150] Fix wrong condition in base::internalize_symbols(). --- src/librustc_trans/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c8b9fea15ba8b..f9e1a4f16087e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2286,7 +2286,7 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { let is_externally_visible = (linkage == llvm::ExternalLinkage as c_uint) || (linkage == llvm::LinkOnceODRLinkage as c_uint) || (linkage == llvm::WeakODRLinkage as c_uint); - let is_definition = llvm::LLVMIsDeclaration(val) != 0; + let is_definition = llvm::LLVMIsDeclaration(val) == 0; // If this is a definition (as opposed to just a declaration) // and externally visible, check if we can internalize it From f7820888daeb961339643dd142ba032847181555 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 19 Jul 2016 06:22:35 -0400 Subject: [PATCH 036/150] Add codegen test to make sure that closures are 'internalized' properly. --- src/test/codegen/internalize-closures.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/codegen/internalize-closures.rs diff --git a/src/test/codegen/internalize-closures.rs b/src/test/codegen/internalize-closures.rs new file mode 100644 index 0000000000000..90aafd6a3bb3b --- /dev/null +++ b/src/test/codegen/internalize-closures.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. + +// compile-flags: -C no-prepopulate-passes + +pub fn main() { + + // We want to make sure that closures get 'internal' linkage instead of + // 'weak_odr' when they are not shared between codegen units + // CHECK: define internal {{.*}}_ZN20internalize_closures4main{{.*}}$u7b$$u7b$closure$u7d$$u7d$ + let c = |x:i32| { x + 1 }; + let _ = c(1); +} From 4a2116b97af2e935b359558c046034f4c3cb80a8 Mon Sep 17 00:00:00 2001 From: ggomez Date: Tue, 19 Jul 2016 15:03:32 +0200 Subject: [PATCH 037/150] [CSS] Fix unwanted top margin for toggle wrapper --- src/librustdoc/html/static/rustdoc.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 303cc671f4a23..de0457592fc88 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -636,8 +636,11 @@ span.since { margin-right: 5px; } -.enum > .toggle-wrapper > .collapse-toggle, .struct > .toggle-wrapper > .collapse-toggle { +.toggle-wrapper > .collapse-toggle { left: 0; +} + +.variant + .toggle-wrapper > a { margin-top: 5px; } From a005b2cd2ac679da7393e537aa05e2b7d32d36d5 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 18 Jul 2016 22:29:05 -0400 Subject: [PATCH 038/150] Rewrite/expand doc examples for `Vec::set_len`. --- src/libcollections/vec.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index da56b21cf0c05..9badf8cf18305 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -532,9 +532,37 @@ impl Vec { /// # Examples /// /// ``` - /// let mut v = vec![1, 2, 3, 4]; + /// use std::ptr; + /// + /// let mut vec = vec!['r', 'u', 's', 't']; + /// + /// unsafe { + /// ptr::drop_in_place(&mut vec[3]); + /// vec.set_len(3); + /// } + /// assert_eq!(vec, ['r', 'u', 's']); + /// ``` + /// + /// In this example, there is a memory leak since the memory locations + /// owned by the vector were not freed prior to the `set_len` call: + /// + /// ``` + /// let mut vec = vec!['r', 'u', 's', 't']; + /// + /// unsafe { + /// vec.set_len(0); + /// } + /// ``` + /// + /// In this example, the vector gets expanded from zero to four items + /// without any memory allocations occurring, resulting in vector + /// values of unallocated memory: + /// + /// ``` + /// let mut vec: Vec = Vec::new(); + /// /// unsafe { - /// v.set_len(1); + /// vec.set_len(4); /// } /// ``` #[inline] From b40b7ef0c429b62d0907c0de930a93b262229b92 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 19 Jul 2016 20:01:54 +0000 Subject: [PATCH 039/150] Support nested `macro_rules!`. --- src/libsyntax/parse/parser.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4656ba03e21c3..32107026eedf4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -258,6 +258,7 @@ pub struct Parser<'a> { pub tokens_consumed: usize, pub restrictions: Restrictions, pub quote_depth: usize, // not (yet) related to the quasiquoter + parsing_token_tree: bool, pub reader: Box, /// The set of seen errors about obsolete syntax. Used to suppress /// extra detail when the same error is seen twice @@ -374,6 +375,7 @@ impl<'a> Parser<'a> { tokens_consumed: 0, restrictions: Restrictions::empty(), quote_depth: 0, + parsing_token_tree: false, obsolete_set: HashSet::new(), mod_path_stack: Vec::new(), filename: filename, @@ -2663,7 +2665,7 @@ impl<'a> Parser<'a> { } pub fn check_unknown_macro_variable(&mut self) { - if self.quote_depth == 0 { + if self.quote_depth == 0 && !self.parsing_token_tree { match self.token { token::SubstNt(name) => self.fatal(&format!("unknown macro variable `{}`", name)).emit(), @@ -2723,6 +2725,7 @@ impl<'a> Parser<'a> { Err(err) }, token::OpenDelim(delim) => { + let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true); // The span for beginning of the delimited section let pre_span = self.span; @@ -2787,6 +2790,7 @@ impl<'a> Parser<'a> { _ => {} } + self.parsing_token_tree = parsing_token_tree; Ok(TokenTree::Delimited(span, Rc::new(Delimited { delim: delim, open_span: open_span, From 485e2df1b1fbd4acde8dbc5bfbdf7fed3acc227c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 19 Jul 2016 20:16:23 +0000 Subject: [PATCH 040/150] Add regression test. --- src/test/run-pass/macro-of-higher-order.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/run-pass/macro-of-higher-order.rs b/src/test/run-pass/macro-of-higher-order.rs index 52e19b37d7935..c982e8ac6f83e 100644 --- a/src/test/run-pass/macro-of-higher-order.rs +++ b/src/test/run-pass/macro-of-higher-order.rs @@ -16,7 +16,16 @@ macro_rules! higher_order { }); } +macro_rules! outer { + ($x:expr; $fragment:ident) => { + macro_rules! inner { ($y:$fragment) => { $x + $y } } + } +} + fn main() { let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo))); assert_eq!(val, (3, "foo")); + + outer!(2; expr); + assert_eq!(inner!(3), 5); } From 536c3157955b76297ff667087807ffe463b48018 Mon Sep 17 00:00:00 2001 From: cgswords Date: Tue, 19 Jul 2016 13:00:45 -0700 Subject: [PATCH 041/150] Introduced `NoDelim` and modified the compiler to support it. --- src/librustdoc/html/highlight.rs | 1 + src/libsyntax/ext/quote.rs | 7 ++++--- src/libsyntax/parse/token.rs | 2 ++ src/libsyntax/print/pprust.rs | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 096e1ecc9ffb6..6cb79d6e8630f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -233,6 +233,7 @@ impl<'a> Classifier<'a> { token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi | token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) | token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) | + token::CloseDelim(token::NoDelim) | token::Question => Class::None, token::Dollar => { if self.lexer.peek().tok.is_ident() { diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index ffc950d76dd27..b70e270df54d2 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -581,9 +581,10 @@ fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P { fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P { let name = match delim { - token::Paren => "Paren", - token::Bracket => "Bracket", - token::Brace => "Brace", + token::Paren => "Paren", + token::Bracket => "Bracket", + token::Brace => "Brace", + token::NoDelim => "NoDelim", }; mk_token_path(cx, sp, name) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f0a6f8edeec73..6fdc9b714d347 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -48,6 +48,8 @@ pub enum DelimToken { Bracket, /// A curly brace: `{` or `}` Brace, + /// An empty delimiter + NoDelim, } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8866ffc2575cc..a619da84b2d51 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -242,6 +242,8 @@ pub fn token_to_string(tok: &Token) -> String { token::CloseDelim(token::Bracket) => "]".to_string(), token::OpenDelim(token::Brace) => "{".to_string(), token::CloseDelim(token::Brace) => "}".to_string(), + token::OpenDelim(token::NoDelim) => " ".to_string(), + token::CloseDelim(token::NoDelim) => " ".to_string(), token::Pound => "#".to_string(), token::Dollar => "$".to_string(), token::Question => "?".to_string(), @@ -1777,12 +1779,14 @@ impl<'a> State<'a> { try!(self.head("")); try!(self.bopen()); } + token::NoDelim => {} } try!(self.print_tts(&m.node.tts)); match delim { token::Paren => self.pclose(), token::Bracket => word(&mut self.s, "]"), token::Brace => self.bclose(m.span), + token::NoDelim => Ok(()), } } From 00e3149dede9fbc464e0f654e7093626d7a8ca27 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 19 Jul 2016 20:38:35 -0400 Subject: [PATCH 042/150] Add doc examples for `Vec::{as_slice,as_mut_slice}`. --- src/libcollections/vec.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 518b94b5031b4..4cc5b11dc3434 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -541,6 +541,14 @@ impl Vec { /// Extracts a slice containing the entire vector. /// /// Equivalent to `&s[..]`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// let buffer = vec![1, 2, 3, 5, 8]; + /// io::sink().write(buffer.as_slice()).unwrap(); + /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] pub fn as_slice(&self) -> &[T] { @@ -550,6 +558,14 @@ impl Vec { /// Extracts a mutable slice of the entire vector. /// /// Equivalent to `&mut s[..]`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Read}; + /// let mut buffer = vec![0; 3]; + /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap(); + /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] pub fn as_mut_slice(&mut self) -> &mut [T] { From aed2e5c1e5d1774fba671ba60ee6347a1d524f2e Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 20 Jul 2016 14:49:40 +1000 Subject: [PATCH 043/150] Add the missing tracking issue field for #34931 to the receiver_try_iter stability attributes --- src/libstd/sync/mpsc/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 2d2bded9f6060..b862a594ed210 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -317,7 +317,7 @@ pub struct Iter<'a, T: 'a> { /// /// This Iterator will never block the caller in order to wait for data to /// become available. Instead, it will return `None`. -#[unstable(feature = "receiver_try_iter")] +#[unstable(feature = "receiver_try_iter", issue = "34931")] pub struct TryIter<'a, T: 'a> { rx: &'a Receiver } @@ -998,7 +998,7 @@ impl Receiver { /// 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 /// user by waiting for values. - #[unstable(feature = "receiver_try_iter")] + #[unstable(feature = "receiver_try_iter", issue = "34931")] pub fn try_iter(&self) -> TryIter { TryIter { rx: self } } @@ -1098,7 +1098,7 @@ impl<'a, T> Iterator for Iter<'a, T> { fn next(&mut self) -> Option { self.rx.recv().ok() } } -#[unstable(feature = "receiver_try_iter")] +#[unstable(feature = "receiver_try_iter", issue = "34931")] impl<'a, T> Iterator for TryIter<'a, T> { type Item = T; From 9b5db220c899fdd3656c8e28fc747808b8cab7c7 Mon Sep 17 00:00:00 2001 From: ggomez Date: Tue, 19 Jul 2016 14:40:42 +0200 Subject: [PATCH 044/150] Add doc for btree_map types --- src/libcollections/btree/map.rs | 191 +++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 2 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index ef94aae78f416..c3a7d4023754a 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -313,6 +313,10 @@ pub struct RangeMut<'a, K: 'a, V: 'a> { } /// A view into a single entry in a map, which may either be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// [`BTreeMap`]: struct.BTreeMap.html +/// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { /// A vacant Entry @@ -340,7 +344,9 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A vacant Entry. +/// A vacant Entry. It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { key: K, @@ -360,7 +366,9 @@ impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { } } -/// An occupied Entry. +/// An occupied Entry. It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, @@ -1890,6 +1898,17 @@ impl BTreeMap { impl<'a, K: Ord, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn or_insert(self, default: V) -> &'a mut V { match self { @@ -1900,6 +1919,19 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let s = "hoho".to_owned(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_owned()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { @@ -1909,6 +1941,15 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { @@ -1921,12 +1962,36 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn into_key(self) -> K { self.key @@ -1934,6 +1999,21 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// // count the number of occurrences of letters in the vec + /// for x in vec!["a","b","a","c","a","b"] { + /// *count.entry(x).or_insert(0) += 1; + /// } + /// + /// assert_eq!(count["a"], 3); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { *self.length += 1; @@ -1979,30 +2059,106 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.handle.reborrow().into_kv().0 } /// Take ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_pair(); + /// } + /// + /// // If now try to get the value, it will panic: + /// // println!("{}", map["poneyland"]); + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn remove_pair(self) -> (K, V) { self.remove_kv() } /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> &V { self.handle.reborrow().into_kv().1 } /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { self.handle.kv_mut().1 } /// Converts the entry into a mutable reference to its value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { self.handle.into_kv_mut().1 @@ -2010,12 +2166,43 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Sets the value of the entry with the OccupiedEntry's key, /// and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// assert_eq!(map["poneyland"], 15); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: V) -> V { mem::replace(self.get_mut(), value) } /// Takes the value of the entry out of the map, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// // If we try to get "poneyland"'s value, it'll panic: + /// // println!("{}", map["poneyland"]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(self) -> V { self.remove_kv().1 From ecc12953dbe401b3e8cb663ce6529706c50cbf8d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 20 Jul 2016 07:55:45 -0400 Subject: [PATCH 045/150] trans: Make base::internalize_symbols() respect explicit linkage directives. --- src/librustc_trans/base.rs | 72 ++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f9e1a4f16087e..ea8c248d0239f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -89,13 +89,14 @@ use value::Value; use Disr; use util::common::indenter; use util::sha2::Sha256; -use util::nodemap::{NodeMap, NodeSet}; +use util::nodemap::{NodeMap, NodeSet, FnvHashSet}; use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; +use std::borrow::Cow; use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::ptr; use std::rc::Rc; use std::str; @@ -2256,12 +2257,20 @@ fn write_metadata(cx: &SharedCrateContext, /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. -fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { +fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>, + reachable: &FnvHashSet<&str>) { + let scx = ccxs.shared(); + let tcx = scx.tcx(); + + // 'unsafe' because we are holding on to CStr's from the LLVM module within + // this block. unsafe { - let mut declared = HashSet::new(); + let mut referenced_somewhere = FnvHashSet(); - // Collect all external declarations in all compilation units. - for ccx in cx.iter() { + // Collect all symbols that need to stay externally visible because they + // are referenced via a declaration in some other codegen unit. + for ccx in ccxs.iter() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { let linkage = llvm::LLVMGetLinkage(val); // We only care about external declarations (not definitions) @@ -2270,16 +2279,43 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { let is_decl = llvm::LLVMIsDeclaration(val) != 0; if is_decl || is_available_externally { - let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - declared.insert(name); + let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + referenced_somewhere.insert(symbol_name); } } } + // Also collect all symbols for which we cannot adjust linkage, because + // it is fixed by some directive in the source code (e.g. #[no_mangle]). + let linkage_fixed_explicitly: FnvHashSet<_> = scx + .translation_items() + .borrow() + .iter() + .cloned() + .filter(|trans_item|{ + let def_id = match *trans_item { + TransItem::DropGlue(..) => { + return false + }, + TransItem::Fn(ref instance) => { + instance.def + } + TransItem::Static(node_id) => { + tcx.map.local_def_id(node_id) + } + }; + + trans_item.explicit_linkage(tcx).is_some() || + attr::contains_extern_indicator(tcx.sess.diagnostic(), + &tcx.get_attrs(def_id)) + }) + .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) + .collect(); + // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, // then give it internal linkage. - for ccx in cx.iter() { + for ccx in ccxs.iter() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { let linkage = llvm::LLVMGetLinkage(val); @@ -2293,16 +2329,17 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { if is_definition && is_externally_visible { let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); let name_str = name_cstr.to_str().unwrap(); + let name_cow = Cow::Borrowed(name_str); - let is_referenced_somewhere = declared.contains(&name_cstr); - let is_reachable = reachable.contains(name_str); + let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); + let is_reachable = reachable.contains(&name_str); + let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); - if !is_referenced_somewhere && !is_reachable { + if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { llvm::SetLinkage(val, llvm::InternalLinkage); llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass); llvm::UnsetComdat(val); } - } } } @@ -2616,8 +2653,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })); } - internalize_symbols(&crate_context_list, - &reachable_symbols.iter().map(|x| &x[..]).collect()); + time(shared_ccx.sess().time_passes(), "internalize symbols", || { + internalize_symbols(&crate_context_list, + &symbol_map, + &reachable_symbols.iter() + .map(|s| &s[..]) + .collect()) + }); if sess.target.target.options.is_like_msvc && sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { From ee6011fc71e02485f2dffcc25be64631c2008775 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 16 Jul 2016 15:08:25 -0700 Subject: [PATCH 046/150] mk: Stop using cmake for compiler-rt The compiler-rt build system has been a never ending cause of pain for Rust unfortunately: * The build system is very difficult to invoke and configure to only build compiler-rt, especially across platforms. * The standard build system doesn't actually do what we want, not working for some of our platforms and requiring a significant number of patches on our end which are difficult to apply when updating compiler-rt. * Compiling compiler-rt requires LLVM to be compiled, which... is a big dependency! This also means that over time compiler-rt is not guaranteed to build against older versions of LLVM (or newer versions), and we often want to work with multiple versions of LLVM simultaneously. The makefiles and rustbuild already know how to compile C code, the code here is far from the *only* C code we're compiling. This patch jettisons all logic to work with compiler-rt's build system and just goes straight to the source. We just list all files manually (copied from compiler-rt's lib/builtins/CMakeLists.txt) and compile them into an archive. It's likely that this means we'll fail to pick up new files when we upgrade compiler-rt, but that seems like a much less significant cost to pay than what we're currently paying. cc #34400, first steps towards that --- mk/rt.mk | 428 +++++++++++++++++++++++++++--------- src/bootstrap/Cargo.lock | 11 +- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/native.rs | 457 ++++++++++++++++++++++++++++++++------- src/bootstrap/step.rs | 4 +- src/bootstrap/util.rs | 5 +- 6 files changed, 724 insertions(+), 183 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index 8113b68380744..067721fab4fa8 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -223,147 +223,373 @@ endif # compiler-rt ################################################################################ -ifdef CFG_ENABLE_FAST_MAKE -COMPRT_DEPS := $(S)/.gitmodules -else -COMPRT_DEPS := $(wildcard \ - $(S)src/compiler-rt/* \ - $(S)src/compiler-rt/*/* \ - $(S)src/compiler-rt/*/*/* \ - $(S)src/compiler-rt/*/*/*/*) -endif - -# compiler-rt's build system is a godawful mess. Here we figure out -# the ridiculous platform-specific values and paths necessary to get -# useful artifacts out of it. +# Everything below is a manual compilation of compiler-rt, disregarding its +# build system. See comments in `src/bootstrap/native.rs` for more information. COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1)) COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt -COMPRT_ARCH_$(1) := $$(word 1,$$(subst -, ,$(1))) +# GENERIC_SOURCES in CMakeLists.txt +COMPRT_OBJS_$(1) := \ + absvdi2.o \ + absvsi2.o \ + adddf3.o \ + addsf3.o \ + addvdi3.o \ + addvsi3.o \ + apple_versioning.o \ + ashldi3.o \ + ashrdi3.o \ + clear_cache.o \ + clzdi2.o \ + clzsi2.o \ + cmpdi2.o \ + comparedf2.o \ + comparesf2.o \ + ctzdi2.o \ + ctzsi2.o \ + divdc3.o \ + divdf3.o \ + divdi3.o \ + divmoddi4.o \ + divmodsi4.o \ + divsc3.o \ + divsf3.o \ + divsi3.o \ + divxc3.o \ + extendsfdf2.o \ + extendhfsf2.o \ + ffsdi2.o \ + fixdfdi.o \ + fixdfsi.o \ + fixsfdi.o \ + fixsfsi.o \ + fixunsdfdi.o \ + fixunsdfsi.o \ + fixunssfdi.o \ + fixunssfsi.o \ + fixunsxfdi.o \ + fixunsxfsi.o \ + fixxfdi.o \ + floatdidf.o \ + floatdisf.o \ + floatdixf.o \ + floatsidf.o \ + floatsisf.o \ + floatundidf.o \ + floatundisf.o \ + floatundixf.o \ + floatunsidf.o \ + floatunsisf.o \ + int_util.o \ + lshrdi3.o \ + moddi3.o \ + modsi3.o \ + muldc3.o \ + muldf3.o \ + muldi3.o \ + mulodi4.o \ + mulosi4.o \ + muloti4.o \ + mulsc3.o \ + mulsf3.o \ + mulvdi3.o \ + mulvsi3.o \ + mulxc3.o \ + negdf2.o \ + negdi2.o \ + negsf2.o \ + negvdi2.o \ + negvsi2.o \ + paritydi2.o \ + paritysi2.o \ + popcountdi2.o \ + popcountsi2.o \ + powidf2.o \ + powisf2.o \ + powixf2.o \ + subdf3.o \ + subsf3.o \ + subvdi3.o \ + subvsi3.o \ + truncdfhf2.o \ + truncdfsf2.o \ + truncsfhf2.o \ + ucmpdi2.o \ + udivdi3.o \ + udivmoddi4.o \ + udivmodsi4.o \ + udivsi3.o \ + umoddi3.o \ + umodsi3.o -# All this is to figure out the path to the compiler-rt bin -ifeq ($$(findstring windows-msvc,$(1)),windows-msvc) -COMPRT_DIR_$(1) := windows/Release -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(patsubst i%86,i386,$$(COMPRT_ARCH_$(1))) +ifeq ($$(findstring ios,$(1)),) +COMPRT_OBJS_$(1) += \ + absvti2.o \ + addtf3.o \ + addvti3.o \ + ashlti3.o \ + ashrti3.o \ + clzti2.o \ + cmpti2.o \ + ctzti2.o \ + divtf3.o \ + divti3.o \ + ffsti2.o \ + fixdfti.o \ + fixsfti.o \ + fixunsdfti.o \ + fixunssfti.o \ + fixunsxfti.o \ + fixxfti.o \ + floattidf.o \ + floattisf.o \ + floattixf.o \ + floatuntidf.o \ + floatuntisf.o \ + floatuntixf.o \ + lshrti3.o \ + modti3.o \ + multf3.o \ + multi3.o \ + mulvti3.o \ + negti2.o \ + negvti2.o \ + parityti2.o \ + popcountti2.o \ + powitf2.o \ + subtf3.o \ + subvti3.o \ + trampoline_setup.o \ + ucmpti2.o \ + udivmodti4.o \ + udivti3.o \ + umodti3.o endif -ifeq ($$(findstring windows-gnu,$(1)),windows-gnu) -COMPRT_DIR_$(1) := windows -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1)) +ifeq ($$(findstring apple,$(1)),apple) +COMPRT_OBJS_$(1) += \ + atomic_flag_clear.o \ + atomic_flag_clear_explicit.o \ + atomic_flag_test_and_set.o \ + atomic_flag_test_and_set_explicit.o \ + atomic_signal_fence.o \ + atomic_thread_fence.o endif -ifeq ($$(findstring darwin,$(1)),darwin) -COMPRT_DIR_$(1) := builtins -COMPRT_LIB_NAME_$(1) := clang_rt.builtins_$$(patsubst i686,i386,$$(COMPRT_ARCH_$(1)))_osx + +ifeq ($$(findstring windows,$(1)),) +COMPRT_OBJS_$(1) += emutls.o endif -ifeq ($$(findstring ios,$(1)),ios) -COMPRT_DIR_$(1) := builtins -COMPRT_ARCH_$(1) := $$(patsubst armv7s,armv7em,$$(COMPRT_ARCH_$(1))) -COMPRT_LIB_NAME_$(1) := clang_rt.hard_pic_$$(COMPRT_ARCH_$(1))_macho_embedded -ifeq ($$(COMPRT_ARCH_$(1)),aarch64) -COMPRT_LIB_NAME_$(1) := clang_rt.builtins_arm64_ios +ifeq ($$(findstring msvc,$(1)),) +COMPRT_OBJS_$(1) += gcc_personality_v0.o +COMPRT_OBJS_$(1) += emutls.o + +ifeq ($$(findstring x86_64,$(1)),x86_64) +COMPRT_OBJS_$(1) += \ + x86_64/chkstk.o \ + x86_64/chkstk2.o \ + x86_64/floatdidf.o \ + x86_64/floatdisf.o \ + x86_64/floatdixf.o \ + x86_64/floatundidf.o \ + x86_64/floatundisf.o \ + x86_64/floatundixf.o endif -COMPRT_DEFINES_$(1) := -DCOMPILER_RT_ENABLE_IOS=ON + +ifeq ($$(findstring i686,$$(patsubts i%86,i686,$(1))),i686) +COMPRT_OBJS_$(1) += \ + i386/ashldi3.o \ + i386/ashrdi3.o \ + i386/chkstk.o \ + i386/chkstk2.o \ + i386/divdi3.o \ + i386/floatdidf.o \ + i386/floatdisf.o \ + i386/floatdixf.o \ + i386/floatundidf.o \ + i386/floatundisf.o \ + i386/floatundixf.o \ + i386/lshrdi3.o \ + i386/moddi3.o \ + i386/muldi3.o \ + i386/udivdi3.o \ + i386/umoddi3.o endif -ifndef COMPRT_DIR_$(1) -# NB: FreeBSD and NetBSD output to "linux"... -COMPRT_DIR_$(1) := linux -COMPRT_ARCH_$(1) := $$(patsubst i586,i386,$$(COMPRT_ARCH_$(1))) +else -ifeq ($$(findstring android,$(1)),android) -ifeq ($$(findstring arm,$$(COMPRT_ARCH_$(1))),arm) -COMPRT_ARCH_$(1) := armhf -endif +ifeq ($$(findstring x86_64,$(1)),x86_64) +COMPRT_OBJS_$(1) += \ + x86_64/floatdidf.o \ + x86_64/floatdisf.o \ + x86_64/floatdixf.o endif -ifeq ($$(findstring eabihf,$(1)),eabihf) -ifeq ($$(findstring armv7,$(1)),) -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-armhf -endif endif -ifndef COMPRT_LIB_NAME_$(1) -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1)) +# Generic ARM sources, nothing compiles on iOS though +ifeq ($$(findstring arm,$(1)),arm) +ifeq ($$(findstring ios,$(1)),) +COMPRT_OBJS_$(1) += \ + arm/aeabi_cdcmp.o \ + arm/aeabi_cdcmpeq_check_nan.o \ + arm/aeabi_cfcmp.o \ + arm/aeabi_cfcmpeq_check_nan.o \ + arm/aeabi_dcmp.o \ + arm/aeabi_div0.o \ + arm/aeabi_drsub.o \ + arm/aeabi_fcmp.o \ + arm/aeabi_frsub.o \ + arm/aeabi_idivmod.o \ + arm/aeabi_ldivmod.o \ + arm/aeabi_memcmp.o \ + arm/aeabi_memcpy.o \ + arm/aeabi_memmove.o \ + arm/aeabi_memset.o \ + arm/aeabi_uidivmod.o \ + arm/aeabi_uldivmod.o \ + arm/bswapdi2.o \ + arm/bswapsi2.o \ + arm/clzdi2.o \ + arm/clzsi2.o \ + arm/comparesf2.o \ + arm/divmodsi4.o \ + arm/divsi3.o \ + arm/modsi3.o \ + arm/switch16.o \ + arm/switch32.o \ + arm/switch8.o \ + arm/switchu8.o \ + arm/sync_synchronize.o \ + arm/udivmodsi4.o \ + arm/udivsi3.o \ + arm/umodsi3.o endif endif - -ifeq ($$(findstring windows-gnu,$(1)),windows-gnu) -COMPRT_LIB_FILE_$(1) := lib$$(COMPRT_LIB_NAME_$(1)).a +# Thumb sources +ifeq ($$(findstring armv7,$(1)),armv7) +COMPRT_OBJS_$(1) += \ + arm/sync_fetch_and_add_4.o \ + arm/sync_fetch_and_add_8.o \ + arm/sync_fetch_and_and_4.o \ + arm/sync_fetch_and_and_8.o \ + arm/sync_fetch_and_max_4.o \ + arm/sync_fetch_and_max_8.o \ + arm/sync_fetch_and_min_4.o \ + arm/sync_fetch_and_min_8.o \ + arm/sync_fetch_and_nand_4.o \ + arm/sync_fetch_and_nand_8.o \ + arm/sync_fetch_and_or_4.o \ + arm/sync_fetch_and_or_8.o \ + arm/sync_fetch_and_sub_4.o \ + arm/sync_fetch_and_sub_8.o \ + arm/sync_fetch_and_umax_4.o \ + arm/sync_fetch_and_umax_8.o \ + arm/sync_fetch_and_umin_4.o \ + arm/sync_fetch_and_umin_8.o \ + arm/sync_fetch_and_xor_4.o \ + arm/sync_fetch_and_xor_8.o endif -ifeq ($$(findstring android,$(1)),android) -ifeq ($$(findstring arm,$(1)),arm) -COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1))-android) -endif +# VFP sources +ifeq ($$(findstring eabihf,$(1)),eabihf) +COMPRT_OBJS_$(1) += \ + arm/adddf3vfp.o \ + arm/addsf3vfp.o \ + arm/divdf3vfp.o \ + arm/divsf3vfp.o \ + arm/eqdf2vfp.o \ + arm/eqsf2vfp.o \ + arm/extendsfdf2vfp.o \ + arm/fixdfsivfp.o \ + arm/fixsfsivfp.o \ + arm/fixunsdfsivfp.o \ + arm/fixunssfsivfp.o \ + arm/floatsidfvfp.o \ + arm/floatsisfvfp.o \ + arm/floatunssidfvfp.o \ + arm/floatunssisfvfp.o \ + arm/gedf2vfp.o \ + arm/gesf2vfp.o \ + arm/gtdf2vfp.o \ + arm/gtsf2vfp.o \ + arm/ledf2vfp.o \ + arm/lesf2vfp.o \ + arm/ltdf2vfp.o \ + arm/ltsf2vfp.o \ + arm/muldf3vfp.o \ + arm/mulsf3vfp.o \ + arm/negdf2vfp.o \ + arm/negsf2vfp.o \ + arm/nedf2vfp.o \ + arm/nesf2vfp.o \ + arm/restore_vfp_d8_d15_regs.o \ + arm/save_vfp_d8_d15_regs.o \ + arm/subdf3vfp.o \ + arm/subsf3vfp.o \ + arm/truncdfsf2vfp.o \ + arm/unorddf2vfp.o \ + arm/unordsf2vfp.o endif -ifndef COMPRT_LIB_FILE_$(1) -COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1))) +ifeq ($$(findstring aarch64,$(1)),aarch64) +COMPRT_OBJS_$(1) += \ + comparetf2.o \ + extenddftf2.o \ + extendsftf2.o \ + fixtfdi.o \ + fixtfsi.o \ + fixtfti.o \ + fixunstfdi.o \ + fixunstfsi.o \ + fixunstfti.o \ + floatditf.o \ + floatsitf.o \ + floatunditf.o \ + floatunsitf.o \ + multc3.o \ + trunctfdf2.o \ + trunctfsf2.o endif -COMPRT_OUTPUT_$(1) := $$(COMPRT_BUILD_DIR_$(1))/lib/$$(COMPRT_DIR_$(1))/$$(COMPRT_LIB_FILE_$(1)) - -ifeq ($$(findstring windows-msvc,$(1)),windows-msvc) -COMPRT_BUILD_ARGS_$(1) := //v:m //nologo -COMPRT_BUILD_TARGET_$(1) := lib/builtins/builtins -COMPRT_BUILD_CC_$(1) := +ifeq ($$(findstring msvc,$(1)),msvc) +$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -Zl -D__func__=__FUNCTION__ else -COMPRT_BUILD_ARGS_$(1) := -ifndef COMPRT_BUILD_TARGET_$(1) -COMPRT_BUILD_TARGET_$(1) := $$(COMPRT_LIB_NAME_$(1)) +$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -fno-builtin -fvisibility=hidden \ + -fomit-frame-pointer -ffreestanding endif -COMPRT_BUILD_CC_$(1) := -DCMAKE_C_COMPILER=$$(call FIND_COMPILER,$$(CC_$(1))) \ - -DCMAKE_CXX_COMPILER=$$(call FIND_COMPILER,$$(CXX_$(1))) -ifeq ($$(findstring ios,$(1)),) -COMPRT_BUILD_CC_$(1) := $$(COMPRT_BUILD_CC_$(1)) \ - -DCMAKE_C_FLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error" -endif +COMPRT_OBJS_$(1) := $$(COMPRT_OBJS_$(1):%=$$(COMPRT_BUILD_DIR_$(1))/%) + +$$(COMPRT_BUILD_DIR_$(1))/%.o: $(S)src/compiler-rt/lib/builtins/%.c + @mkdir -p $$(@D) + @$$(call E, compile: $$@) + $$(Q)$$(call CFG_COMPILE_C_$(1),$$@,$$<) + +$$(COMPRT_BUILD_DIR_$(1))/%.o: $(S)src/compiler-rt/lib/builtins/%.S \ + $$(LLVM_CONFIG_$$(CFG_BUILD)) + @mkdir -p $$(@D) + @$$(call E, compile: $$@) + $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<) +ifeq ($$(findstring msvc,$(1)),msvc) +$$(COMPRT_BUILD_DIR_$(1))/%.o: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1))) endif ifeq ($$(findstring emscripten,$(1)),emscripten) - # FIXME: emscripten doesn't use compiler-rt and can't build it without # further hacks -$$(COMPRT_LIB_$(1)): - touch $$@ - -else - -$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD)) - @$$(call E, cmake: compiler-rt) - $$(Q)rm -rf $$(COMPRT_BUILD_DIR_$(1)) - $$(Q)mkdir $$(COMPRT_BUILD_DIR_$(1)) - $$(Q)cd "$$(COMPRT_BUILD_DIR_$(1))"; \ - $$(CFG_CMAKE) "$(S)src/compiler-rt" \ - -DCMAKE_BUILD_TYPE=$$(LLVM_BUILD_CONFIG_MODE) \ - -DLLVM_CONFIG_PATH=$$(LLVM_CONFIG_$$(CFG_BUILD)) \ - -DCOMPILER_RT_DEFAULT_TARGET_TRIPLE=$(1) \ - -DCOMPILER_RT_BUILD_SANITIZERS=OFF \ - -DCOMPILER_RT_BUILD_EMUTLS=OFF \ - $$(COMPRT_DEFINES_$(1)) \ - $$(COMPRT_BUILD_CC_$(1)) \ - -G"$$(CFG_CMAKE_GENERATOR)" -ifneq ($$(CFG_NINJA),) - $$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \ - --target $$(COMPRT_BUILD_TARGET_$(1)) \ - --config $$(LLVM_BUILD_CONFIG_MODE) \ - -- $$(COMPRT_BUILD_ARGS_$(1)) -else - $$(Q)$$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \ - --target $$(COMPRT_BUILD_TARGET_$(1)) \ - --config $$(LLVM_BUILD_CONFIG_MODE) \ - -- $$(COMPRT_BUILD_ARGS_$(1)) $$(MFLAGS) +COMPRT_OBJS_$(1) := endif - $$(Q)cp "$$(COMPRT_OUTPUT_$(1))" $$@ -endif +$$(COMPRT_LIB_$(1)): $$(COMPRT_OBJS_$(1)) + @$$(call E, link: $$@) + $$(Q)$$(call CFG_CREATE_ARCHIVE_$(1),$$@) $$^ ################################################################################ # libbacktrace diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 39c7a37501121..1290f2a404b22 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -5,7 +5,7 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.17 (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.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -25,7 +25,7 @@ name = "cmake" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -38,7 +38,12 @@ dependencies = [ [[package]] name = "gcc" -version = "0.3.26" +version = "0.3.31" +source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7" + +[[package]] +name = "gcc" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index cde4a825be1fb..02746034cca69 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -29,6 +29,6 @@ getopts = "0.2" rustc-serialize = "0.3" winapi = "0.2" kernel32-sys = "0.2" -gcc = "0.3.17" +gcc = { git = "https://github.com/alexcrichton/gcc-rs" } libc = "0.2" md5 = "0.1" diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 83e9393fbaef7..05ecbc0cadaa9 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -133,86 +133,395 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { /// Compiles the `compiler-rt` library, or at least the builtins part of it. /// -/// This uses the CMake build system and an existing LLVM build directory to -/// compile the project. +/// Note that while compiler-rt has a build system associated with it, we +/// specifically don't use it here. The compiler-rt build system, written in +/// CMake, is actually *very* difficult to work with in terms of getting it to +/// compile on all the relevant platforms we want it to compile on. In the end +/// it became so much pain to work with local patches, work around the oddities +/// of the build system, etc, that we're just building everything by hand now. +/// +/// In general compiler-rt is just a bunch of intrinsics that are in practice +/// *very* stable. We just need to make sure that all the relevant functions and +/// such are compiled somewhere and placed in an object file somewhere. +/// Eventually, these should all be written in Rust! +/// +/// So below you'll find a listing of every single file in the compiler-rt repo +/// that we're compiling. We just reach in and compile with the `gcc` crate +/// which should have all the relevant flags and such already configured. +/// +/// The risk here is that if we update compiler-rt we may need to compile some +/// new intrinsics, but to be honest we surely don't use all of the intrinsics +/// listed below today so the likelihood of us actually needing a new intrinsic +/// is quite low. The failure case is also just that someone reports a link +/// error (if any) and then we just add it to the list. Overall, that cost is +/// far far less than working with compiler-rt's build system over time. pub fn compiler_rt(build: &Build, target: &str) { - let dst = build.compiler_rt_out(target); - let arch = target.split('-').next().unwrap(); - let mode = if build.config.rust_optimize {"Release"} else {"Debug"}; + let build_dir = build.compiler_rt_out(target); + let output = build_dir.join(staticlib("compiler-rt", target)); + build.compiler_rt_built.borrow_mut().insert(target.to_string(), + output.clone()); + t!(fs::create_dir_all(&build_dir)); - let build_llvm_config = build.llvm_config(&build.config.build); - let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt")); - cfg.target(target) + let mut cfg = gcc::Config::new(); + cfg.cargo_metadata(false) + .out_dir(&build_dir) + .target(target) .host(&build.config.build) - .out_dir(&dst) - .profile(mode) - .define("LLVM_CONFIG_PATH", build_llvm_config) - .define("COMPILER_RT_DEFAULT_TARGET_TRIPLE", target) - .define("COMPILER_RT_BUILD_SANITIZERS", "OFF") - .define("COMPILER_RT_BUILD_EMUTLS", "OFF") - // inform about c/c++ compilers, the c++ compiler isn't actually used but - // it's needed to get the initial configure to work on all platforms. - .define("CMAKE_C_COMPILER", build.cc(target)) - .define("CMAKE_CXX_COMPILER", build.cc(target)); - - let (dir, build_target, libname) = if target.contains("linux") || - target.contains("freebsd") || - target.contains("netbsd") { - let os_extra = if target.contains("android") && target.contains("arm") { - "-android" - } else { - "" - }; - let builtins_arch = match arch { - "i586" => "i386", - "arm" | "armv7" if target.contains("android") => "armhf", - "arm" if target.contains("eabihf") => "armhf", - _ => arch, - }; - let target = format!("clang_rt.builtins-{}", builtins_arch); - ("linux".to_string(), - target.clone(), - format!("{}{}", target, os_extra)) - } else if target.contains("apple-darwin") { - let builtins_arch = match arch { - "i686" => "i386", - _ => arch, - }; - let target = format!("clang_rt.builtins_{}_osx", builtins_arch); - ("builtins".to_string(), target.clone(), target) - } else if target.contains("apple-ios") { - cfg.define("COMPILER_RT_ENABLE_IOS", "ON"); - let target = match arch { - "armv7s" => "hard_pic_armv7em_macho_embedded".to_string(), - "aarch64" => "builtins_arm64_ios".to_string(), - _ => format!("hard_pic_{}_macho_embedded", arch), - }; - ("builtins".to_string(), target.clone(), target) - } else if target.contains("windows-gnu") { - let target = format!("clang_rt.builtins-{}", arch); - ("windows".to_string(), target.clone(), target) - } else if target.contains("windows-msvc") { - let builtins_arch = match arch { - "i586" | "i686" => "i386", - _ => arch, - }; - (format!("windows/{}", mode), - "lib/builtins/builtins".to_string(), - format!("clang_rt.builtins-{}", builtins_arch)) + .opt_level(2) + .debug(false); + + if target.contains("msvc") { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); } else { - panic!("can't get os from target: {}", target) - }; - let output = dst.join("build/lib").join(dir) - .join(staticlib(&libname, target)); - build.compiler_rt_built.borrow_mut().insert(target.to_string(), - output.clone()); - if fs::metadata(&output).is_ok() { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + let mut sources = vec![ + "absvdi2.c", + "absvsi2.c", + "adddf3.c", + "addsf3.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "ashldi3.c", + "ashrdi3.c", + "clear_cache.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divdi3.c", + "divmoddi4.c", + "divmodsi4.c", + "divsc3.c", + "divsf3.c", + "divsi3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "lshrdi3.c", + "moddi3.c", + "modsi3.c", + "muldc3.c", + "muldf3.c", + "muldi3.c", + "mulodi4.c", + "mulosi4.c", + "muloti4.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powidf2.c", + "powisf2.c", + "powixf2.c", + "subdf3.c", + "subsf3.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + "udivdi3.c", + "udivmoddi4.c", + "udivmodsi4.c", + "udivsi3.c", + "umoddi3.c", + "umodsi3.c", + ]; + + if !target.contains("ios") { + sources.extend(vec![ + "absvti2.c", + "addtf3.c", + "addvti3.c", + "ashlti3.c", + "ashrti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "divtf3.c", + "divti3.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "lshrti3.c", + "modti3.c", + "multf3.c", + "multi3.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "powitf2.c", + "subtf3.c", + "subvti3.c", + "trampoline_setup.c", + "ucmpti2.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c", + ]); + } + + if target.contains("apple") { + sources.extend(vec![ + "atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c", + ]); + } + + if !target.contains("windows") { + sources.push("emutls.c"); + } + + if target.contains("msvc") { + if target.contains("x86_64") { + sources.extend(vec![ + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + ]); + } + } else { + sources.push("gcc_personality_v0.c"); + + if target.contains("x86_64") { + sources.extend(vec![ + "x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ]); + } + + if target.contains("i386") || + target.contains("i586") || + target.contains("i686") { + sources.extend(vec![ + "i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S", + ]); + } + } + + if target.contains("arm") && !target.contains("ios") { + sources.extend(vec![ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/aeabi_idivmod.S", + "arm/aeabi_ldivmod.S", + "arm/aeabi_memcmp.S", + "arm/aeabi_memcpy.S", + "arm/aeabi_memmove.S", + "arm/aeabi_memset.S", + "arm/aeabi_uidivmod.S", + "arm/aeabi_uldivmod.S", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S", + ]); + } + + if target.contains("armv7") { + sources.extend(vec![ + "arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S", + ]); + } + + if target.contains("eabihf") { + sources.extend(vec![ + "arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S", + "arm/truncdfsf2vfp.S", + "arm/unorddf2vfp.S", + "arm/unordsf2vfp.S", + ]); + } + + if target.contains("aarch64") { + sources.extend(vec![ + "comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c", + ]); + } + + let mut out_of_date = false; + for src in sources { + let src = build.src.join("src/compiler-rt/lib/builtins").join(src); + out_of_date = out_of_date || !up_to_date(&src, &output); + cfg.file(src); + } + if !out_of_date { return } - let _ = fs::remove_dir_all(&dst); - t!(fs::create_dir_all(&dst)); - cfg.build_target(&build_target); - cfg.build(); + cfg.compile("libcompiler-rt.a"); } /// Compiles the `rust_test_helpers.c` library which we used in various diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 82ae70d22ca06..1ce8c73123244 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -347,9 +347,7 @@ impl<'a> Step<'a> { vec![self.libstd(compiler), self.target(host).rustc(compiler.stage)] } - Source::CompilerRt { _dummy } => { - vec![self.llvm(()).target(&build.config.build)] - } + Source::CompilerRt { _dummy } => Vec::new(), Source::Llvm { _dummy } => Vec::new(), Source::TestHelpers { _dummy } => Vec::new(), Source::DebuggerScripts { stage: _ } => Vec::new(), diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 3ef7f8cab2d1b..b5230132bcb66 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -103,7 +103,10 @@ pub fn add_lib_path(path: Vec, cmd: &mut Command) { /// Uses last-modified time checks to verify this. pub fn up_to_date(src: &Path, dst: &Path) -> bool { let threshold = mtime(dst); - let meta = t!(fs::metadata(src)); + let meta = match fs::metadata(src) { + Ok(meta) => meta, + Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), + }; if meta.is_dir() { dir_up_to_date(src, &threshold) } else { From fbfee42a2f65b7a3d4acd0d9d029bb75208ac800 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 14 Jul 2016 12:17:39 -0700 Subject: [PATCH 047/150] core: impl From for Option --- src/libcore/option.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 045c1f9feafc6..fe508adb71380 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -142,6 +142,7 @@ use self::Option::*; use clone::Clone; +use convert::From; use default::Default; use iter::ExactSizeIterator; use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator}; @@ -754,6 +755,13 @@ impl<'a, T> IntoIterator for &'a mut Option { } } +#[stable(since = "1.12.0", feature = "option_from")] +impl From for Option { + fn from(val: T) -> Option { + Some(val) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// From 15cd5a18a656252e32e7320fde3072be7b59db18 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 20 Jul 2016 17:26:12 -0700 Subject: [PATCH 048/150] std: Fix usage of SOCK_CLOEXEC This code path was intended to only get executed on Linux, but unfortunately the `cfg!` was malformed so it actually never got executed. --- src/libstd/sys/unix/net.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index a784741c88cc7..6f1b70acb60bc 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -67,7 +67,7 @@ impl Socket { // this option, however, was added in 2.6.27, and we still support // 2.6.18 as a kernel, so if the returned error is EINVAL we // fallthrough to the fallback. - if cfg!(linux) { + if cfg!(target_os = "linux") { match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) { Ok(fd) => return Ok(Socket(FileDesc::new(fd))), Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} @@ -87,7 +87,7 @@ impl Socket { let mut fds = [0, 0]; // Like above, see if we can set cloexec atomically - if cfg!(linux) { + if cfg!(target_os = "linux") { match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { Ok(_) => { return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); From 8f9844dd5ccbb8185498601542512d96f1cc3f08 Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Thu, 7 Jul 2016 16:40:01 -0700 Subject: [PATCH 049/150] add mir optimization tests, dump-mir-dir option --- mk/tests.mk | 14 +++- src/bootstrap/lib.rs | 4 + src/bootstrap/step.rs | 3 + src/librustc/session/config.rs | 2 + src/librustc_mir/pretty.rs | 9 +- src/test/mir-opt/README.md | 44 ++++++++++ src/test/mir-opt/return_an_array.rs | 18 ++++ src/test/mir-opt/simplify_if.rs | 27 ++++++ src/tools/compiletest/src/common.rs | 3 + src/tools/compiletest/src/main.rs | 2 +- src/tools/compiletest/src/runtest.rs | 121 ++++++++++++++++++++++++++- 11 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 src/test/mir-opt/README.md create mode 100644 src/test/mir-opt/return_an_array.rs create mode 100644 src/test/mir-opt/simplify_if.rs diff --git a/mk/tests.mk b/mk/tests.mk index ed443147d466e..201e4cae51d6d 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -277,7 +277,8 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ check-stage$(1)-T-$(2)-H-$(3)-ui-exec \ check-stage$(1)-T-$(2)-H-$(3)-doc-exec \ check-stage$(1)-T-$(2)-H-$(3)-doc-error-index-exec \ - check-stage$(1)-T-$(2)-H-$(3)-pretty-exec + check-stage$(1)-T-$(2)-H-$(3)-pretty-exec \ + check-stage$(1)-T-$(2)-H-$(3)-mir-opt-exec ifndef CFG_DISABLE_CODEGEN_TESTS check-stage$(1)-T-$(2)-H-$(3)-exec: \ @@ -458,6 +459,7 @@ UI_RS := $(call rwildcard,$(S)src/test/ui/,*.rs) \ $(call rwildcard,$(S)src/test/ui/,*.stdout) \ $(call rwildcard,$(S)src/test/ui/,*.stderr) RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs) +MIR_OPT_RS := $(call rwildcard,$(S)src/test/mir-opt/,*.rs) RPASS_TESTS := $(RPASS_RS) RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS) @@ -475,6 +477,7 @@ CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS) INCREMENTAL_TESTS := $(INCREMENTAL_RS) RMAKE_TESTS := $(RMAKE_RS) UI_TESTS := $(UI_RS) +MIR_OPT_TESTS := $(MIR_OPT_RS) RUSTDOCCK_TESTS := $(RUSTDOCCK_RS) CTEST_SRC_BASE_rpass = run-pass @@ -552,6 +555,11 @@ CTEST_BUILD_BASE_ui = ui CTEST_MODE_ui = ui CTEST_RUNTOOL_ui = $(CTEST_RUNTOOL) +CTEST_SRC_BASE_mir-opt = mir-opt +CTEST_BUILD_BASE_mir-opt = mir-opt +CTEST_MODE_mir-opt = mir-opt +CTEST_RUNTOOL_mir-opt = $(CTEST_RUNTOOL) + CTEST_SRC_BASE_rustdocck = rustdoc CTEST_BUILD_BASE_rustdocck = rustdoc CTEST_MODE_rustdocck = rustdoc @@ -684,6 +692,7 @@ CTEST_DEPS_incremental_$(1)-T-$(2)-H-$(3) = $$(INCREMENTAL_TESTS) CTEST_DEPS_rmake_$(1)-T-$(2)-H-$(3) = $$(RMAKE_TESTS) \ $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3)) CTEST_DEPS_ui_$(1)-T-$(2)-H-$(3) = $$(UI_TESTS) +CTEST_DEPS_mir-opt_$(1)-T-$(2)-H-$(3) = $$(MIR_OPT_TESTS) CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ $(S)src/etc/htmldocck.py @@ -755,7 +764,7 @@ endef CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \ debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental \ - rmake ui + rmake ui mir-opt $(foreach host,$(CFG_HOST), \ $(eval $(foreach target,$(CFG_TARGET), \ @@ -964,6 +973,7 @@ TEST_GROUPS = \ pretty-rfail-full \ pretty-rfail \ pretty-pretty \ + mir-opt \ $(NULL) define DEF_CHECK_FOR_STAGE_AND_TARGET_AND_HOST diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 943271fc8a641..53a0625744650 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -375,6 +375,10 @@ impl Build { check::compiletest(self, &compiler, target.target, "pretty", "run-pass-valgrind"); } + CheckMirOpt { compiler } => { + check::compiletest(self, &compiler, target.target, + "mir-opt", "mir-opt"); + } CheckCodegen { compiler } => { check::compiletest(self, &compiler, target.target, "codegen", "codegen"); diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 4b3be04b57c57..bd262cc7721eb 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -124,6 +124,7 @@ macro_rules! targets { (check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }), (check_incremental, CheckIncremental { compiler: Compiler<'a> }), (check_ui, CheckUi { compiler: Compiler<'a> }), + (check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }), (check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }), (check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }), (check_docs, CheckDocs { compiler: Compiler<'a> }), @@ -444,6 +445,7 @@ impl<'a> Step<'a> { self.check_pretty_rfail_full(compiler), self.check_rpass_valgrind(compiler), self.check_rmake(compiler), + self.check_mir_opt(compiler), // crates self.check_crate_rustc(compiler), @@ -471,6 +473,7 @@ impl<'a> Step<'a> { Source::CheckTidy { stage } => { vec![self.tool_tidy(stage)] } + Source::CheckMirOpt { compiler} | Source::CheckPrettyRPass { compiler } | Source::CheckPrettyRFail { compiler } | Source::CheckRFail { compiler } | diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5ccc96210be78..2d0b243558ffd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -749,6 +749,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the MIR optimization level (0-3)"), dump_mir: Option = (None, parse_opt_string, "dump MIR state at various points in translation"), + dump_mir_dir: Option = (None, parse_opt_string, + "the directory the MIR is dumped into"), orbit: bool = (false, parse_bool, "get MIR where it belongs - everywhere; most importantly, in orbit"), } diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 515620d425389..577e0fd086015 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -19,6 +19,7 @@ use std::fmt::Display; use std::fs; use std::io::{self, Write}; use syntax::ast::NodeId; +use std::path::{PathBuf, Path}; const INDENT: &'static str = " "; /// Alignment for lining up comments following MIR statements @@ -66,9 +67,15 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => String::new() }; + let mut file_path = PathBuf::new(); + if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir { + let p = Path::new(file_dir); + file_path.push(p); + }; let file_name = format!("rustc.node{}{}.{}.{}.mir", node_id, promotion_id, pass_name, disambiguator); - let _ = fs::File::create(&file_name).and_then(|mut file| { + file_path.push(&file_name); + let _ = fs::File::create(&file_path).and_then(|mut file| { try!(writeln!(file, "// MIR for `{}`", node_path)); try!(writeln!(file, "// node_id = {}", node_id)); try!(writeln!(file, "// pass_name = {}", pass_name)); diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md new file mode 100644 index 0000000000000..9144e9757f6a7 --- /dev/null +++ b/src/test/mir-opt/README.md @@ -0,0 +1,44 @@ +This folder contains tests for MIR optimizations. + +The test format is: + +``` +(arbitrary rust code) +// END RUST SOURCE +// START $file_name_of_some_mir_dump_0 +// $expected_line_0 +// ... +// $expected_line_N +// END $file_name_of_some_mir_dump_0 +// ... +// START $file_name_of_some_mir_dump_N +// $expected_line_0 +// ... +// $expected_line_N +// END $file_name_of_some_mir_dump_N +``` + +All the test information is in comments so the test is runnable. + +For each $file_name, compiletest expects [$expected_line_0, ..., +$expected_line_N] to appear in the dumped MIR in order. Currently it allows +other non-matched lines before, after and in-between. + +Lines match ignoring whitespace, and the prefix "//" is removed. + +It also currently strips trailing comments -- partly because the full file path +in "scope comments" is unpredictable and partly because tidy complains about +the lines being too long. + +compiletest handles dumping the MIR before and after every pass for you. The +test writer only has to specify the file names of the dumped files (not the +full path to the file) and what lines to expect. I added an option to rustc +that tells it to dump the mir into some directly (rather then always dumping to +the current directory). + +Lines match ignoring whitespace, and the prefix "//" is removed of course. + +It also currently strips trailing comments -- partly because the full file path +in "scope comments" is unpredictable and partly because tidy complains about +the lines being too long. + diff --git a/src/test/mir-opt/return_an_array.rs b/src/test/mir-opt/return_an_array.rs new file mode 100644 index 0000000000000..4409f16b3f5ff --- /dev/null +++ b/src/test/mir-opt/return_an_array.rs @@ -0,0 +1,18 @@ +// Copyright 2012-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. + +// this tests move up progration, which is not yet implemented + +fn foo() -> [u8; 1024] { + let x = [0; 1024]; + return x; +} + +fn main() { } \ No newline at end of file diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs new file mode 100644 index 0000000000000..dd6a857960432 --- /dev/null +++ b/src/test/mir-opt/simplify_if.rs @@ -0,0 +1,27 @@ +// Copyright 2012-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 main() { + if false { + println!("hello world!"); + } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyBranches.initial-before.mir +// bb0: { +// if(const false) -> [true: bb1, false: bb2]; // scope 0 at simplify_if.rs:12:5: 14:6 +// } +// END rustc.node4.SimplifyBranches.initial-before.mir +// START rustc.node4.SimplifyBranches.initial-after.mir +// bb0: { +// goto -> bb2; // scope 0 at simplify_if.rs:12:5: 14:6 +// } +// END rustc.node4.SimplifyBranches.initial-after.mir \ No newline at end of file diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5ec62e06e37ae..2a35fab9676a7 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -29,6 +29,7 @@ pub enum Mode { Incremental, RunMake, Ui, + MirOpt, } impl FromStr for Mode { @@ -49,6 +50,7 @@ impl FromStr for Mode { "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), "ui" => Ok(Ui), + "mir-opt" => Ok(MirOpt), _ => Err(()), } } @@ -71,6 +73,7 @@ impl fmt::Display for Mode { Incremental => "incremental", RunMake => "run-make", Ui => "ui", + MirOpt => "mir-opt", }, f) } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 6830f32bb2ce1..cefcc11486fe2 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -86,7 +86,7 @@ pub fn parse_config(args: Vec ) -> Config { reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"), reqopt("", "mode", "which sort of compile tests to run", "(compile-fail|parse-fail|run-fail|run-pass|\ - run-pass-valgrind|pretty|debug-info|incremental)"), + run-pass-valgrind|pretty|debug-info|incremental|mir-opt)"), optflag("", "ignored", "run tests marked as ignored"), optopt("", "runtool", "supervisor program to run tests under \ (eg. emulator, valgrind)", "PROGRAM"), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 577da5c5af11d..f2acfa517ced5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -11,7 +11,7 @@ use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits}; -use common::{Incremental, RunMake, Ui}; +use common::{Incremental, RunMake, Ui, MirOpt}; use errors::{self, ErrorKind, Error}; use json; use header::TestProps; @@ -117,6 +117,7 @@ impl<'test> TestCx<'test> { Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), Ui => self.run_ui_test(), + MirOpt => self.run_mir_opt_test(), } } @@ -1336,7 +1337,22 @@ actual:\n\ .map(|s| s.to_string())); } } + MirOpt => { + args.extend(["-Z", + "dump-mir=all", + "-Z"] + .iter() + .map(|s| s.to_string())); + + let mir_dump_dir = self.get_mir_dump_dir(); + self.create_dir_racy(mir_dump_dir.as_path()); + let mut dir_opt = "dump-mir-dir=".to_string(); + dir_opt.push_str(mir_dump_dir.to_str().unwrap()); + debug!("dir_opt: {:?}", dir_opt); + + args.push(dir_opt); + } RunFail | RunPass | RunPassValgrind | @@ -2145,6 +2161,100 @@ actual:\n\ } } + fn run_mir_opt_test(&self) { + let proc_res = self.compile_test(); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + let proc_res = self.exec_compiled_test(); + + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + self.check_mir_dump(); + } + + fn check_mir_dump(&self) { + let mut test_file_contents = String::new(); + fs::File::open(self.testpaths.file.clone()).unwrap() + .read_to_string(&mut test_file_contents) + .unwrap(); + if let Some(idx) = test_file_contents.find("// END RUST SOURCE") { + let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len()); + let tests_text_str = String::from(tests_text); + let mut curr_test : Option<&str> = None; + let mut curr_test_contents = Vec::new(); + for l in tests_text_str.lines() { + debug!("line: {:?}", l); + if l.starts_with("// START ") { + let (_, t) = l.split_at("// START ".len()); + curr_test = Some(t); + } else if l.starts_with("// END") { + let (_, t) = l.split_at("// END ".len()); + if Some(t) != curr_test { + panic!("mismatched START END test name"); + } + self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents); + curr_test = None; + curr_test_contents.clear(); + } else if l.is_empty() { + // ignore + } else if l.starts_with("// ") { + let (_, test_content) = l.split_at("// ".len()); + curr_test_contents.push(test_content); + } + } + } + } + + fn compare_mir_test_output(&self, test_name: &str, expected_content: &Vec<&str>) { + let mut output_file = PathBuf::new(); + output_file.push(self.get_mir_dump_dir()); + output_file.push(test_name); + debug!("comparing the contests of: {:?}", output_file); + debug!("with: {:?}", expected_content); + + let mut dumped_file = fs::File::open(output_file.clone()).unwrap(); + let mut dumped_string = String::new(); + dumped_file.read_to_string(&mut dumped_string).unwrap(); + let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty()); + let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty()); + + // We expect each non-empty line from expected_content to appear + // in the dump in order, but there may be extra lines interleaved + while let Some(expected_line) = expected_lines.next() { + let e_norm = normalize_mir_line(expected_line); + if e_norm.is_empty() { + continue; + }; + let mut found = false; + while let Some(dumped_line) = dumped_lines.next() { + let d_norm = normalize_mir_line(dumped_line); + debug!("found: {:?}", d_norm); + debug!("expected: {:?}", e_norm); + if e_norm == d_norm { + found = true; + break; + }; + } + if !found { + panic!("ran out of mir dump output to match against"); + } + } + } + + fn get_mir_dump_dir(&self) -> PathBuf { + let mut mir_dump_dir = PathBuf::from(self.config.build_base + .as_path() + .to_str() + .unwrap()); + debug!("input_file: {:?}", self.testpaths.file); + mir_dump_dir.push(self.testpaths.file.file_stem().unwrap().to_str().unwrap()); + mir_dump_dir + } + fn normalize_output(&self, output: &str) -> String { let parent_dir = self.testpaths.file.parent().unwrap(); let parent_dir_str = parent_dir.display().to_string(); @@ -2274,3 +2384,12 @@ enum TargetLocation { ThisDirectory(PathBuf), } +fn normalize_mir_line(line: &str) -> String { + let no_comments = if let Some(idx) = line.find("//") { + let (l, _) = line.split_at(idx); + l + } else { + line + }; + no_comments.replace(char::is_whitespace, "") +} From 97d082c6cdc05c0ac7f37f7a0c0b3a2f9fe698e3 Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Thu, 21 Jul 2016 01:03:40 -0700 Subject: [PATCH 050/150] Make vec::Drain and binary_heap::Drain covariant --- src/libcollections/binary_heap.rs | 10 ++-- src/libcollections/vec.rs | 66 ++++++++++----------------- src/libcollectionstest/binary_heap.rs | 6 +++ src/libcollectionstest/vec.rs | 6 +++ 4 files changed, 40 insertions(+), 48 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index b9f5c6fcab909..f6ca90234c5b4 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -1016,12 +1016,12 @@ impl ExactSizeIterator for IntoIter {} /// An iterator that drains a `BinaryHeap`. #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, T: 'a> { - iter: vec::Drain<'a, T>, +pub struct Drain { + iter: vec::Drain, } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: 'a> Iterator for Drain<'a, T> { +impl Iterator for Drain { type Item = T; #[inline] @@ -1036,7 +1036,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { +impl DoubleEndedIterator for Drain { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -1044,7 +1044,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} +impl ExactSizeIterator for Drain {} #[stable(feature = "rust1", since = "1.0.0")] impl From> for BinaryHeap { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 518b94b5031b4..f4855cce3b4a2 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -74,6 +74,7 @@ use core::ops::{Index, IndexMut}; use core::ops; use core::ptr; use core::slice; +use super::vec_deque::VecDeque; use super::SpecExtend; use super::range::RangeArgument; @@ -843,20 +844,20 @@ impl Vec { let end = *range.end().unwrap_or(&len); assert!(start <= end); assert!(end <= len); + let mut drain_vec = VecDeque::new(); unsafe { - // set self.vec length's to start, to be safe in case Drain is leaked - self.set_len(start); - // Use the borrow in the IterMut to indicate borrowing behavior of the - // whole Drain iterator (like &mut T). - let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().offset(start as isize), - end - start); - Drain { - tail_start: end, - tail_len: len - end, - iter: range_slice.iter_mut(), - vec: self as *mut _, + for i in start..end { + let p = self.as_ptr().offset(i as isize); + drain_vec.push_back(ptr::read(p)); } + let src = self.as_ptr().offset(end as isize); + let dst = self.as_mut_ptr().offset(start as isize); + ptr::copy(src, dst, len - end); + self.set_len(len - (end - start)); + } + Drain { + deque: drain_vec } } @@ -1755,64 +1756,43 @@ impl Drop for IntoIter { /// [`drain`]: struct.Vec.html#method.drain /// [`Vec`]: struct.Vec.html #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, T: 'a> { - /// Index of tail to preserve - tail_start: usize, - /// Length of tail - tail_len: usize, +pub struct Drain { /// Current remaining range to remove - iter: slice::IterMut<'a, T>, - vec: *mut Vec, + deque: VecDeque } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +unsafe impl Sync for Drain {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Send> Send for Drain<'a, T> {} +unsafe impl Send for Drain {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Drain<'a, T> { +impl Iterator for Drain { type Item = T; #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) }) + self.deque.pop_front() } fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + (self.deque.len(), Some(self.deque.len())) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Drain<'a, T> { +impl DoubleEndedIterator for Drain { #[inline] fn next_back(&mut self) -> Option { - self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) + self.deque.pop_back() } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Drop for Drain<'a, T> { +impl Drop for Drain { fn drop(&mut self) { - // exhaust self first - while let Some(_) = self.next() {} - - if self.tail_len > 0 { - unsafe { - let source_vec = &mut *self.vec; - // memmove back untouched tail, update to new length - let start = source_vec.len(); - let tail = self.tail_start; - let src = source_vec.as_ptr().offset(tail as isize); - let dst = source_vec.as_mut_ptr().offset(start as isize); - ptr::copy(src, dst, self.tail_len); - source_vec.set_len(start + self.tail_len); - } - } } } - #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Drain<'a, T> {} +impl ExactSizeIterator for Drain {} diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs index be933abe41fe2..39efc9fc22c39 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollectionstest/binary_heap.rs @@ -9,6 +9,7 @@ // except according to those terms. use std::collections::BinaryHeap; +use std::collections::binary_heap::Drain; #[test] fn test_iterator() { @@ -292,3 +293,8 @@ fn test_extend_specialization() { assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); } + +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<&'static str>) -> Drain<&'new str> { d } +} diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index cb99659cc0ead..01656b44a8495 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::iter::{FromIterator, repeat}; use std::mem::size_of; +use std::vec::Drain; use test::Bencher; @@ -510,6 +511,11 @@ fn test_cow_from() { } } +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<&'static str>) -> Drain<&'new str> { d } +} + #[bench] fn bench_new(b: &mut Bencher) { b.iter(|| { From 05af033b7fec63638497a9780e6b323d327d1e17 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 21 Jul 2016 19:32:24 +1000 Subject: [PATCH 051/150] Fix issue in receiver_try_iter test where response sender would panic instead of break from the loop --- src/libstd/sync/mpsc/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index b862a594ed210..6fe1b2a3b47de 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1854,8 +1854,6 @@ mod tests { for x in response_rx.try_iter() { count += x; if count == 6 { - drop(response_rx); - drop(request_tx); return count; } } @@ -1864,7 +1862,9 @@ mod tests { }); for _ in request_rx.iter() { - response_tx.send(2).unwrap(); + if response_tx.send(2).is_err() { + break; + } } assert_eq!(t.join().unwrap(), 6); From d7a968eb1c8e1d4f84e52a1d1a302e40b1fc4aa9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Jul 2016 00:15:15 +0300 Subject: [PATCH 052/150] Fix ICE happening when unresolved imports are used in patterns --- src/librustc_resolve/lib.rs | 4 +-- .../unresolved-import-recovery.rs | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/unresolved-import-recovery.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index aa8c706ea1e27..88cd29a3ccfa7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2274,7 +2274,7 @@ impl<'a> Resolver<'a> { let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id, qself, path, namespace) { if resolution.depth == 0 { - if expected_fn(resolution.base_def) { + if expected_fn(resolution.base_def) || resolution.base_def == Def::Err { resolution } else { resolve_error( @@ -2345,7 +2345,7 @@ impl<'a> Resolver<'a> { ); None } - Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => { + Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => { // These entities are explicitly allowed // to be shadowed by fresh bindings. None diff --git a/src/test/compile-fail/unresolved-import-recovery.rs b/src/test/compile-fail/unresolved-import-recovery.rs new file mode 100644 index 0000000000000..8173f69191da8 --- /dev/null +++ b/src/test/compile-fail/unresolved-import-recovery.rs @@ -0,0 +1,27 @@ +// 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. + +// Check that unresolved imports do not create additional errors and ICEs + +mod m { + pub use unresolved; //~ ERROR unresolved import `unresolved` + + fn f() { + let unresolved = 0; // OK + } +} + +fn main() { + match 0u8 { + m::unresolved => {} // OK + m::unresolved(..) => {} // OK + m::unresolved{..} => {} // OK + } +} From b0de62064cc2ccba33a141bbde169e88b81d0b86 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 16 Jul 2016 11:18:53 +0200 Subject: [PATCH 053/150] doc: add missing pause --- src/doc/nomicon/phantom-data.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/nomicon/phantom-data.md b/src/doc/nomicon/phantom-data.md index d565532017a65..189695716deb1 100644 --- a/src/doc/nomicon/phantom-data.md +++ b/src/doc/nomicon/phantom-data.md @@ -50,7 +50,7 @@ struct Vec { } ``` -Unlike the previous example it *appears* that everything is exactly as we +Unlike the previous example, it *appears* that everything is exactly as we want. Every generic argument to Vec shows up in at least one field. Good to go! @@ -84,4 +84,3 @@ standard library made a utility for itself called `Unique` which: * includes a `PhantomData` * auto-derives Send/Sync as if T was contained * marks the pointer as NonZero for the null-pointer optimization - From f7019a4e2f80577d38ec35fcebd64d5970b15f78 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 21 Jul 2016 12:38:15 -0700 Subject: [PATCH 054/150] Remove unused methods from MultiSpan --- src/libsyntax_pos/lib.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 7dfe19452a2a9..c96be8fec2b02 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -193,20 +193,6 @@ impl MultiSpan { } } - pub fn from_span(primary_span: Span) -> MultiSpan { - MultiSpan { - primary_spans: vec![primary_span], - span_labels: vec![] - } - } - - pub fn from_spans(vec: Vec) -> MultiSpan { - MultiSpan { - primary_spans: vec, - span_labels: vec![] - } - } - pub fn push_span_label(&mut self, span: Span, label: String) { self.span_labels.push((span, label)); } @@ -254,7 +240,10 @@ impl MultiSpan { impl From for MultiSpan { fn from(span: Span) -> MultiSpan { - MultiSpan::from_span(span) + MultiSpan { + primary_spans: vec![span], + span_labels: vec![] + } } } From 24f8589bf3d4a198721a5ebe84679817cd1e205b Mon Sep 17 00:00:00 2001 From: ubsan Date: Thu, 21 Jul 2016 12:57:42 -0700 Subject: [PATCH 055/150] Fix nits --- src/libcore/intrinsics.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d6fb1816b5fa0..6a1d94a2e44d8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -284,8 +284,8 @@ extern "rust-intrinsic" { /// /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the destination type into the - /// source type, then forgets the original. If you know C or C++, it's like - /// `memcpy` under the hood. + /// source type, then forgets the original. It's equivalent to C's `memcpy` + /// under the hood, just like `transmute_copy`. /// /// `transmute` is incredibly unsafe. There are a vast number of ways to /// cause undefined behavior with this function. `transmute` should be @@ -299,7 +299,7 @@ extern "rust-intrinsic" { /// There are a few things that `transmute` is really useful for. /// /// Getting the bitpattern of a floating point type (or, more generally, - /// type punning, when T and U aren't pointers): + /// type punning, when `T` and `U` aren't pointers): /// /// ``` /// let bitpattern = unsafe { @@ -339,11 +339,10 @@ extern "rust-intrinsic" { /// # Alternatives /// /// However, many uses of `transmute` can be achieved through other means. - /// `transmute` can transform - /// any type into any other, with just the caveat that they're the same - /// size, and it sometimes results in interesting results. Below are common - /// applications of `transmute` which can be replaced with safe applications - /// of `as`: + /// `transmute` can transform any type into any other, with just the caveat + /// that they're the same size, and often interesting results occur. Below + /// are common applications of `transmute` which can be replaced with safe + /// applications of `as`: /// /// Turning a pointer into a `usize`: /// From a6f0d1e6b6cb6b13bf43a65d8a7dbc17fccaefc3 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 21 Jul 2016 22:58:54 +0200 Subject: [PATCH 056/150] switch mipsel-musl to soft float --- src/librustc_back/target/mipsel_unknown_linux_musl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index a9ea52c427862..6195ac5eadfce 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -22,7 +22,7 @@ pub fn target() -> Target { target_vendor: "unknown".to_string(), options: TargetOptions { cpu: "mips32".to_string(), - features: "+mips32".to_string(), + features: "+mips32,+soft-float".to_string(), max_atomic_width: 32, ..super::linux_base::opts() } From e21ffdf4d157cd40aebbe796632cc6ffe3bce549 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 21 Jul 2016 23:02:46 +0000 Subject: [PATCH 057/150] Avoid processing `feature`s on unconfigured crates. --- src/libsyntax/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ff75149f518ab..a825cf866a878 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -124,7 +124,7 @@ pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_ }; let err_count = sess.span_diagnostic.err_count(); - let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone()); + let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default(); features = get_features(&sess.span_diagnostic, &krate_attrs); if err_count < sess.span_diagnostic.err_count() { krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s From d1e2a935d2d35e768d0a56af7938c725f243fc28 Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Thu, 21 Jul 2016 20:55:19 -0700 Subject: [PATCH 058/150] Readding lifetime parameters and removing allocation --- src/libcollections/binary_heap.rs | 10 ++-- src/libcollections/vec.rs | 67 ++++++++++++++++++--------- src/libcollectionstest/binary_heap.rs | 2 +- src/libcollectionstest/vec.rs | 2 +- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index f6ca90234c5b4..b9f5c6fcab909 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -1016,12 +1016,12 @@ impl ExactSizeIterator for IntoIter {} /// An iterator that drains a `BinaryHeap`. #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain { - iter: vec::Drain, +pub struct Drain<'a, T: 'a> { + iter: vec::Drain<'a, T>, } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Drain { +impl<'a, T: 'a> Iterator for Drain<'a, T> { type Item = T; #[inline] @@ -1036,7 +1036,7 @@ impl Iterator for Drain { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Drain { +impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -1044,7 +1044,7 @@ impl DoubleEndedIterator for Drain { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Drain {} +impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] impl From> for BinaryHeap { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f4855cce3b4a2..f3d31ceea1347 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -73,8 +73,8 @@ use core::mem; use core::ops::{Index, IndexMut}; use core::ops; use core::ptr; +use core::ptr::Shared; use core::slice; -use super::vec_deque::VecDeque; use super::SpecExtend; use super::range::RangeArgument; @@ -844,20 +844,20 @@ impl Vec { let end = *range.end().unwrap_or(&len); assert!(start <= end); assert!(end <= len); - let mut drain_vec = VecDeque::new(); unsafe { - for i in start..end { - let p = self.as_ptr().offset(i as isize); - drain_vec.push_back(ptr::read(p)); + // set self.vec length's to start, to be safe in case Drain is leaked + self.set_len(start); + // Use the borrow in the IterMut to indicate borrowing behavior of the + // whole Drain iterator (like &mut T). + let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().offset(start as isize), + end - start); + Drain { + tail_start: end, + tail_len: len - end, + iter: range_slice.iter(), + vec: Shared::new(self as *mut _), } - let src = self.as_ptr().offset(end as isize); - let dst = self.as_mut_ptr().offset(start as isize); - ptr::copy(src, dst, len - end); - self.set_len(len - (end - start)); - } - Drain { - deque: drain_vec } } @@ -1756,43 +1756,64 @@ impl Drop for IntoIter { /// [`drain`]: struct.Vec.html#method.drain /// [`Vec`]: struct.Vec.html #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain { +pub struct Drain<'a, T: 'a> { + /// Index of tail to preserve + tail_start: usize, + /// Length of tail + tail_len: usize, /// Current remaining range to remove - deque: VecDeque + iter: slice::Iter<'a, T>, + vec: Shared>, } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain {} +unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain {} +unsafe impl<'a, T: Send> Send for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Drain { +impl<'a, T> Iterator for Drain<'a, T> { type Item = T; #[inline] fn next(&mut self) -> Option { - self.deque.pop_front() + self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) }) } fn size_hint(&self) -> (usize, Option) { - (self.deque.len(), Some(self.deque.len())) + self.iter.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Drain { +impl<'a, T> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { - self.deque.pop_back() + self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Drain { +impl<'a, T> Drop for Drain<'a, T> { fn drop(&mut self) { + // exhaust self first + while let Some(_) = self.next() {} + + if self.tail_len > 0 { + unsafe { + let source_vec = &mut **self.vec; + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.tail_start; + let src = source_vec.as_ptr().offset(tail as isize); + let dst = source_vec.as_mut_ptr().offset(start as isize); + ptr::copy(src, dst, self.tail_len); + source_vec.set_len(start + self.tail_len); + } + } } } + #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Drain {} +impl<'a, T> ExactSizeIterator for Drain<'a, T> {} diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs index 39efc9fc22c39..e2a57bd8d3862 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollectionstest/binary_heap.rs @@ -296,5 +296,5 @@ fn test_extend_specialization() { #[allow(dead_code)] fn assert_covariance() { - fn drain<'new>(d: Drain<&'static str>) -> Drain<&'new str> { d } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } } diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 01656b44a8495..7a6bd958a5f8c 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -513,7 +513,7 @@ fn test_cow_from() { #[allow(dead_code)] fn assert_covariance() { - fn drain<'new>(d: Drain<&'static str>) -> Drain<&'new str> { d } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } } #[bench] From e8ac07941c952d352683c7311b343ae72baf9fde Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 22 Jul 2016 09:34:44 +0200 Subject: [PATCH 059/150] improve const eval error reporting on "" and b"" casts --- src/librustc_const_eval/eval.rs | 18 ++++++++++++++++-- src/test/run-pass/const-byte-str-cast.rs | 5 ++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a3c707e82a0ff..4643686786be6 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -1105,11 +1105,25 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, Infer(c as u64), ty), Function(_) => Err(UnimplementedConstVal("casting fn pointers")), - ByteStr(_) => match ty.sty { + ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr")) }, - ty::TyRef(..) => Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")), + ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { + ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)), + ty::TySlice(_) => { + Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")) + }, + _ => Err(CannotCast), + }, + _ => Err(CannotCast), + }, + Str(s) => match ty.sty { + ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")), + ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { + ty::TyStr => Ok(Str(s)), + _ => Err(CannotCast), + }, _ => Err(CannotCast), }, _ => Err(CannotCast), diff --git a/src/test/run-pass/const-byte-str-cast.rs b/src/test/run-pass/const-byte-str-cast.rs index 2f265b9112b98..7297c71a6d668 100644 --- a/src/test/run-pass/const-byte-str-cast.rs +++ b/src/test/run-pass/const-byte-str-cast.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -12,4 +12,7 @@ pub fn main() { let _ = b"x" as &[u8]; + let _ = b"y" as &[u8; 1]; + let _ = b"z" as *const u8; + let _ = "ä" as *const str; } From b2422ab806b9a6c2c52e0bd690486df1950f7339 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 8 Jul 2016 22:51:29 +0300 Subject: [PATCH 060/150] remove never-called type-error reporting functions --- src/librustc/infer/mod.rs | 88 +++++++++------------------------------ 1 file changed, 19 insertions(+), 69 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2ea2978b2940d..fc5625036ae40 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1468,75 +1468,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // error type, meaning that an error occurred when typechecking this expression), // this is a derived error. The error cascaded from another error (that was already // reported), so it's not useful to display it to the user. - // The following four methods -- type_error_message_str, type_error_message_str_with_expected, - // type_error_message, and report_mismatched_types -- implement this logic. + // The following methods implement this logic. // They check if either the actual or expected type is TyError, and don't print the error // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these four methods, and should not call span_err directly for such + // types using one of these methods, and should not call span_err directly for such // errors. - pub fn type_error_message_str(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option, String) -> String, - { - self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_struct_str(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_message_str_with_expected(&self, - sp: Span, - mk_msg: M, - expected_ty: Option>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) - .emit(); - } - - pub fn type_error_struct_str_with_expected(&self, - sp: Span, - mk_msg: M, - expected_ty: Option>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option, String) -> String, - { - debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); - - let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); - - if !resolved_expected.references_error() { - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); - - let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}", - mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), - error_str)); - - if let Some(err) = err { - self.tcx.note_and_explain_type_err(&mut db, err, sp); - } - db - } else { - self.tcx.sess.diagnostic().struct_dummy() - } - } pub fn type_error_message(&self, sp: Span, @@ -1556,6 +1492,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, { + debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err); + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is TyError. @@ -1563,9 +1501,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return self.tcx.sess.diagnostic().struct_dummy(); } - self.type_error_struct_str(sp, - move |_e, a| { mk_msg(a) }, - self.ty_to_string(actual_ty), err) + let error_str = err.map_or("".to_string(), |t_err| { + format!(" ({})", t_err) + }); + + let msg = mk_msg(self.ty_to_string(actual_ty)); + + // FIXME: use an error code. + let mut db = self.tcx.sess.struct_span_err( + sp, &format!("{} {}", msg, error_str)); + + if let Some(err) = err { + self.tcx.note_and_explain_type_err(&mut db, err, sp); + } + + db } pub fn report_mismatched_types(&self, From 8eb12d91aaf95432ca73bda429af04e0710c984d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 16 Jul 2016 19:38:17 +0300 Subject: [PATCH 061/150] remove rustc_typeck::same_type_err --- src/librustc/infer/error_reporting.rs | 10 +++ src/librustc/infer/mod.rs | 64 ++++++++++++++++++- src/librustc/ty/structural_impls.rs | 13 ++++ src/librustc_typeck/check/_match.rs | 10 +-- src/librustc_typeck/check/demand.rs | 12 ---- src/librustc_typeck/check/intrinsic.rs | 6 +- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/diagnostics.rs | 2 + src/librustc_typeck/lib.rs | 36 ++++------- src/test/compile-fail/issue-26194.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 5 +- .../compile-fail/ufcs-explicit-self-bad.rs | 6 +- 12 files changed, 114 insertions(+), 55 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 96ecad629f543..a0fa188c4f809 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -554,6 +554,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { + let trace = self.resolve_type_vars_if_possible(&trace); let span = trace.origin.span(); let mut err = self.report_type_error(trace, terr); self.tcx.note_and_explain_type_err(&mut err, terr, span); @@ -1643,6 +1644,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TypeOrigin::EquatePredicate(_) => { "equality where clause is satisfied" } + TypeOrigin::MainFunctionType(_) => { + "the `main` function has the correct type" + } + TypeOrigin::StartFunctionType(_) => { + "the `start` function has the correct type" + } + TypeOrigin::IntrinsicType(_) => { + "the intrinsic has the correct type" + } }; match self.values_str(&trace.values) { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fc5625036ae40..dc262e61dd018 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,7 @@ use ty::adjustment; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use ty::fold::TypeFoldable; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::{self, PredicateObligations, ProjectionMode}; use rustc_data_structures::unify::{self, UnificationTable}; @@ -219,6 +219,15 @@ pub enum TypeOrigin { // `where a == b` EquatePredicate(Span), + + // `main` has wrong type + MainFunctionType(Span), + + // `start` has wrong type + StartFunctionType(Span), + + // intrinsic has wrong type + IntrinsicType(Span), } impl TypeOrigin { @@ -238,6 +247,9 @@ impl TypeOrigin { &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types", &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", + &TypeOrigin::MainFunctionType(_) => "main function has wrong type", + &TypeOrigin::StartFunctionType(_) => "start function has wrong type", + &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", } } } @@ -1791,6 +1803,9 @@ impl TypeOrigin { TypeOrigin::IfExpressionWithNoElse(span) => span, TypeOrigin::RangeExpression(span) => span, TypeOrigin::EquatePredicate(span) => span, + TypeOrigin::MainFunctionType(span) => span, + TypeOrigin::StartFunctionType(span) => span, + TypeOrigin::IntrinsicType(span) => span, } } } @@ -1841,3 +1856,50 @@ impl RegionVariableOrigin { } } } + +impl<'tcx> TypeFoldable<'tcx> for TypeOrigin { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + self.clone() + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ValuePairs::Types(ref ef) => { + ValuePairs::Types(ef.fold_with(folder)) + } + ValuePairs::TraitRefs(ref ef) => { + ValuePairs::TraitRefs(ef.fold_with(folder)) + } + ValuePairs::PolyTraitRefs(ref ef) => { + ValuePairs::PolyTraitRefs(ef.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ValuePairs::Types(ref ef) => ef.visit_with(visitor), + ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor), + ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + TypeTrace { + origin: self.origin.fold_with(folder), + values: self.values.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.origin.visit_with(visitor) || self.values.visit_with(visitor) + } +} diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 1e2920ca87ea6..16a54c20925de 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1018,3 +1018,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { self.generics.visit_with(visitor) || self.ty.visit_with(visitor) } } + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::error::ExpectedFound { + expected: self.expected.fold_with(folder), + found: self.found.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.expected.visit_with(visitor) || self.found.visit_with(visitor) + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e90b32cd5dfc0..aae6e3ad36dfe 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -103,15 +103,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } - // Check that the types of the end-points can be unified. - let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty, - "mismatched types in range"); - - // It's ok to return without a message as `require_same_types` prints an error. - if !types_unify { - return; - } - // Now that we know the types can be unified we find the unified type and use // it to type the entire expression. let common_type = self.resolve_type_vars_if_possible(&lhs_ty); @@ -120,6 +111,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping doesn't matter here, as the value is some kind of scalar self.demand_eqtype(pat.span, expected, lhs_ty); + self.demand_eqtype(pat.span, expected, rhs_ty); } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index eeebd6a7f626b..c1f415b3c028a 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -54,16 +54,4 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.report_mismatched_types(origin, expected, expr_ty, e); } } - - pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str) - -> bool { - if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - let found_ty = self.resolve_type_vars_if_possible(&t1); - let expected_ty = self.resolve_type_vars_if_possible(&t2); - ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg); - false - } else { - true - } - } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5a3268e9e447b..8a53c59b4c7fa 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -12,6 +12,7 @@ //! intrinsics that the compiler exposes. use intrinsics; +use rustc::infer::TypeOrigin; use rustc::ty::subst::{self, Substs}; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; @@ -56,10 +57,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, i_n_tps, n_tps); } else { require_same_types(ccx, - it.span, + TypeOrigin::IntrinsicType(it.span), i_ty.ty, - fty, - "intrinsic has wrong type"); + fty); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d101381e2565c..2d44a85f9af4b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -437,8 +437,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - fcx.require_same_types(span, sig.inputs[0], rcvr_ty, - "mismatched method receiver"); + fcx.demand_eqtype(span, rcvr_ty, sig.inputs[0]); } fn check_variances_for_type_defn(&self, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8769bc1a32b50..683328f4eb4a0 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2660,6 +2660,7 @@ For information on the design of the orphan rules, see [RFC 1023]. [RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 "##, +/* E0211: r##" You used a function or type which doesn't fit the requirements for where it was used. Erroneous code examples: @@ -2739,6 +2740,7 @@ impl Foo { } ``` "##, + */ E0214: r##" A generic type was described using parentheses rather than angle brackets. For diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 84452589dfda3..3b2d02dc861c4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -186,28 +186,14 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, } } -pub fn emit_type_err<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - found_ty: Ty<'tcx>, - expected_ty: Ty<'tcx>, - terr: &ty::error::TypeError<'tcx>, - msg: &str) { - let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg); - err.span_label(span, &terr); - err.note_expected_found(&"type", &expected_ty, &found_ty); - tcx.note_and_explain_type_err(&mut err, terr, span); - err.emit(); -} - fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, + origin: TypeOrigin, t1: Ty<'tcx>, - t2: Ty<'tcx>, - msg: &str) + t2: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| { - if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - emit_type_err(infcx.tcx, span, t1, t2, &err, msg); + if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) { + infcx.report_mismatched_types(origin, t1, t2, err); false } else { true @@ -249,8 +235,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, }) })); - require_same_types(ccx, main_span, main_t, se_ty, - "main function has wrong type"); + require_same_types( + ccx, + TypeOrigin::MainFunctionType(main_span), + main_t, + se_ty); } _ => { span_bug!(main_span, @@ -298,8 +287,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, }), })); - require_same_types(ccx, start_span, start_t, se_ty, - "start function has wrong type"); + require_same_types( + ccx, + TypeOrigin::StartFunctionType(start_span), + start_t, + se_ty); } _ => { span_bug!(start_span, diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index ef91188c5d166..1bc0a4f965219 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -12,7 +12,7 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } - //~^ ERROR mismatched method receiver + //~^ ERROR mismatched types } fn main() { S("".to_owned()).f(); } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 526aa83dec7fd..2c4c256302186 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -27,6 +27,7 @@ fn main() { 'c' ... 100 => { } _ => { } }; - //~^^^ ERROR mismatched types in range - //~| expected char, found integral variable + //~^^^ ERROR mismatched types + //~| expected type `_` + //~| found type `char` } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index f14a3505cdeb4..e997cf47c7333 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -15,7 +15,7 @@ struct Foo { } impl Foo { - fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched method receiver + fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched types self.f + x } } @@ -25,10 +25,10 @@ struct Bar { } impl Bar { - fn foo(self: Bar, x: isize) -> isize { //~ ERROR mismatched method receiver + fn foo(self: Bar, x: isize) -> isize { //~ ERROR mismatched types x } - fn bar(self: &Bar, x: isize) -> isize { //~ ERROR mismatched method receiver + fn bar(self: &Bar, x: isize) -> isize { //~ ERROR mismatched types x } } From cea88ebb39402ceee9ec5f7cd61c877ae4cd16dc Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 16 Jul 2016 23:18:20 +0300 Subject: [PATCH 062/150] refactor type error reporting --- src/librustc/infer/error_reporting.rs | 235 +++++++------------- src/librustc/infer/mod.rs | 48 ++-- src/librustc/macros.rs | 12 + src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/cast.rs | 15 +- src/librustc_typeck/check/method/suggest.rs | 3 +- src/librustc_typeck/check/mod.rs | 27 +-- src/librustc_typeck/check/op.rs | 2 +- 8 files changed, 141 insertions(+), 203 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index a0fa188c4f809..be73818c8a4eb 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -83,7 +83,7 @@ use hir::def_id::DefId; use infer::{self, TypeOrigin}; use middle::region; use ty::subst; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; @@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn report_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let (expected, found) = match self.values_str(&trace.values) { - Some(v) => v, - None => { - return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ - } - }; - - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; - - let mut err = struct_span_err!(self.tcx.sess, - trace.origin.span(), - E0308, - "{}", - trace.origin); - - if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); - } - - err.span_label(trace.origin.span(), &terr); - - self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); - - match trace.origin { - TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { - hir::MatchSource::IfLetDesugar{..} => { - err.span_note(arm_span, "`if let` arm with an incompatible type"); - } - _ => { - err.span_note(arm_span, "match arm with an incompatible type"); - } - }, - _ => () - } - - err - } - /// Adds a note if the types come from similarly named crates fn check_and_note_conflicting_crates(&self, err: &mut DiagnosticBuilder, @@ -550,43 +504,91 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_and_explain_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let trace = self.resolve_type_vars_if_possible(&trace); + fn note_error_origin(&self, + err: &mut DiagnosticBuilder<'tcx>, + origin: &TypeOrigin) + { + match origin { + &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { + hir::MatchSource::IfLetDesugar {..} => { + err.span_note(arm_span, "`if let` arm with an incompatible type"); + } + _ => { + err.span_note(arm_span, "match arm with an incompatible type"); + } + }, + _ => () + } + } + + pub fn report_and_explain_type_error_with_code(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>, + message: &str, + code: &str) + -> DiagnosticBuilder<'tcx> + { + let (expected, found) = match self.values_str(&trace.values) { + Some((expected, found)) => (expected, found), + None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + }; + let span = trace.origin.span(); - let mut err = self.report_type_error(trace, terr); + + let is_simple_error = if let &TypeError::Sorts(ref values) = terr { + values.expected.is_primitive() && values.found.is_primitive() + } else { + false + }; + + let mut err = self.tcx.sess.struct_span_err_with_code( + trace.origin.span(), + message, + code); + + if !is_simple_error || check_old_school() { + err.note_expected_found(&"type", &expected, &found); + } + + err.span_label(span, &terr); + + self.note_error_origin(&mut err, &trace.origin); + self.check_and_note_conflicting_crates(&mut err, terr, span); self.tcx.note_and_explain_type_err(&mut err, terr, span); + err } - /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived - /// error. + pub fn report_and_explain_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> + { + // FIXME: do we want to use a different error code for each origin? + let failure_str = trace.origin.as_failure_str(); + type_err!(self, trace, terr, E0308, "{}", failure_str) + } + + /// Returns a string of the form "expected `{}`, found `{}`". fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), - infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } - fn expected_found_str + TypeFoldable<'tcx>>( + fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) -> Option<(String, String)> { - let expected = exp_found.expected.resolve(self); - if expected.references_error() { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { return None; } - let found = exp_found.found.resolve(self); - if found.references_error() { - return None; - } - - Some((format!("{}", expected), format!("{}", found))) + Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) } fn report_generic_bound_failure(&self, @@ -1609,68 +1611,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => { - let desc = match trace.origin { - TypeOrigin::Misc(_) => { - "types are compatible" - } - TypeOrigin::MethodCompatCheck(_) => { - "method type is compatible with trait" - } - TypeOrigin::ExprAssignable(_) => { - "expression is assignable" - } - TypeOrigin::RelateTraitRefs(_) => { - "traits are compatible" - } - TypeOrigin::RelateSelfType(_) => { - "self type matches impl self type" - } - TypeOrigin::RelateOutputImplTypes(_) => { - "trait type parameters matches those \ - specified on the impl" - } - TypeOrigin::MatchExpressionArm(_, _, _) => { - "match arms have compatible types" - } - TypeOrigin::IfExpression(_) => { - "if and else have compatible types" - } - TypeOrigin::IfExpressionWithNoElse(_) => { - "if may be missing an else clause" - } - TypeOrigin::RangeExpression(_) => { - "start and end of range have compatible types" - } - TypeOrigin::EquatePredicate(_) => { - "equality where clause is satisfied" - } - TypeOrigin::MainFunctionType(_) => { - "the `main` function has the correct type" - } - TypeOrigin::StartFunctionType(_) => { - "the `start` function has the correct type" - } - TypeOrigin::IntrinsicType(_) => { - "the intrinsic has the correct type" - } - }; - - match self.values_str(&trace.values) { - Some((expected, found)) => { - err.span_note( - trace.origin.span(), - &format!("...so that {} (expected {}, found {})", - desc, expected, found)); - } - None => { - // Really should avoid printing this error at - // all, since it is derived, but that would - // require more refactoring than I feel like - // doing right now. - nmatsakis - err.span_note( - trace.origin.span(), - &format!("...so that {}", desc)); - } + if let Some((expected, found)) = self.values_str(&trace.values) { + // FIXME: do we want a "the" here? + err.span_note( + trace.origin.span(), + &format!("...so that {} (expected {}, found {})", + trace.origin.as_requirement_str(), expected, found)); + } else { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. + + err.span_note( + trace.origin.span(), + &format!("...so that {}", + trace.origin.as_requirement_str())); } } infer::Reborrow(span) => { @@ -1813,32 +1768,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -pub trait Resolvable<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self; -} - -impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> ty::TraitRef<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { - fn resolve<'a, 'gcx>(&self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> ty::PolyTraitRef<'tcx> - { - infcx.resolve_type_vars_if_possible(self) - } -} - fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, scope_id: ast::NodeId) -> Vec { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index dc262e61dd018..fd65e06ea972c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -231,7 +231,7 @@ pub enum TypeOrigin { } impl TypeOrigin { - fn as_str(&self) -> &'static str { + fn as_failure_str(&self) -> &'static str { match self { &TypeOrigin::Misc(_) | &TypeOrigin::RelateSelfType(_) | @@ -252,11 +252,26 @@ impl TypeOrigin { &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", } } -} -impl fmt::Display for TypeOrigin { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { - fmt::Display::fmt(self.as_str(), f) + fn as_requirement_str(&self) -> &'static str { + match self { + &TypeOrigin::Misc(_) => "types are compatible", + &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", + &TypeOrigin::ExprAssignable(_) => "expression is assignable", + &TypeOrigin::RelateTraitRefs(_) => "traits are compatible", + &TypeOrigin::RelateSelfType(_) => "self type matches impl self type", + &TypeOrigin::RelateOutputImplTypes(_) => { + "trait type parameters matches those specified on the impl" + } + &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types", + &TypeOrigin::IfExpression(_) => "if and else have compatible types", + &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()", + &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types", + &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied", + &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", + &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", + &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", + } } } @@ -1489,22 +1504,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn type_error_message(&self, sp: Span, mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) + actual_ty: Ty<'tcx>) where M: FnOnce(String) -> String, { - self.type_error_struct(sp, mk_msg, actual_ty, err).emit(); + self.type_error_struct(sp, mk_msg, actual_ty).emit(); } pub fn type_error_struct(&self, sp: Span, mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) + actual_ty: Ty<'tcx>) -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, { - debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err); + debug!("type_error_struct({:?}, {:?})", sp, actual_ty); let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); @@ -1513,21 +1526,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return self.tcx.sess.diagnostic().struct_dummy(); } - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); - let msg = mk_msg(self.ty_to_string(actual_ty)); // FIXME: use an error code. - let mut db = self.tcx.sess.struct_span_err( - sp, &format!("{} {}", msg, error_str)); - - if let Some(err) = err { - self.tcx.note_and_explain_type_err(&mut db, err, sp); - } - - db + self.tcx.sess.struct_span_err(sp, &msg) } pub fn report_mismatched_types(&self, diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b649..52420475db100 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -59,3 +59,15 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! type_err { + ($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + $infcx.report_and_explain_type_error_with_code( + $trace, + $terr, + &format!($($message)*), + stringify!($code)) + }) +} diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 2c7e7d284fa16..9c6727ebbfcf9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => { let mut err = self.type_error_struct(call_expr.span, |actual| { format!("expected function, found `{}`", actual) - }, callee_ty, None); + }, callee_ty); if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = self.tcx; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 22ac8bc56907b..7a4cc09a7d506 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) .help(&format!("cast through {} first", match e { CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaThinPtr => "a thin pointer", @@ -167,35 +167,35 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { CastError::CastToChar => { fcx.type_error_message(self.span, |actual| { format!("only `u8` can be cast as `char`, not `{}`", actual) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::NonScalar => { fcx.type_error_message(self.span, |actual| { format!("non-scalar cast: `{}` as `{}`", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::IllegalCast => { fcx.type_error_message(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::SizedUnsizedCast => { fcx.type_error_message(self.span, |actual| { format!("cannot cast thin pointer `{}` to fat pointer `{}`", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) } CastError::DifferingKinds => { fcx.type_error_struct(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) .note("vtable kinds may not match") .emit(); } @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let tstr = fcx.ty_to_string(self.cast_ty); let mut err = fcx.type_error_struct(self.span, |actual| { format!("cast to unsized type: `{}` as `{}`", actual, tstr) - }, self.expr_ty, None); + }, self.expr_ty); match self.expr_ty.sty { ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { let mtstr = match mt { @@ -484,4 +484,3 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span) } } - diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f20dcdc35aea5..346449d0a5133 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -160,8 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_name, actual) }, - rcvr_ty, - None); + rcvr_ty); // If the item has the name of a field, give a help note if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fc1d2236f3fea..7076b6a2a900b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2541,21 +2541,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(arg.span, |t| { format!("can't pass an `{}` to variadic \ function, cast to `c_double`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_int`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_uint`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyFnDef(_, _, f) => { let ptr_ty = self.tcx.mk_fn_ptr(f); @@ -2564,7 +2564,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |t| { format!("can't pass `{}` to variadic \ function, cast to `{}`", t, ptr_ty) - }, arg_ty, None); + }, arg_ty); } _ => {} } @@ -2908,9 +2908,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ `{}`", field.node, actual) - }, expr_t, None) - .help( - "maybe a `()` to call it is missing? \ + }, expr_t) + .help("maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); self.write_error(expr.id); @@ -2919,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("attempted access of field `{}` on type `{}`, \ but no field with that name was found", field.node, actual) - }, expr_t, None); + }, expr_t); if let ty::TyStruct(def, _) = expr_t.sty { Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } @@ -3019,7 +3018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { actual) } }, - expr_t, None); + expr_t); self.write_error(expr.id); } @@ -3038,8 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("structure `{}` has no field named `{}`", actual, field.name.node) }, - ty, - None); + ty); // prevent all specified fields from being suggested let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect()); @@ -3272,7 +3270,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ dereferenced", actual) - }, oprnd_t, None); + }, oprnd_t); oprnd_t = tcx.types.err; } } @@ -3647,8 +3645,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("cannot index a value of type `{}`", actual) }, - base_t, - None); + base_t); // Try to give some advice about indexing tuples. if let ty::TyTuple(_) = base_t.sty { let mut needs_note = true; @@ -4523,7 +4520,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !self.is_tainted_by_errors() { self.type_error_message(sp, |_actual| { "the type of this value must be known in this context".to_string() - }, ty, None); + }, ty); } self.demand_suptype(sp, self.tcx.types.err, ty); ty = self.tcx.types.err; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8604dadf46dff..d02f87d0b9cd6 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(ex.span, |actual| { format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) - }, operand_ty, None); + }, operand_ty); self.tcx.types.err } } From b7b2db4da7dc6762d53659b32e5fb4ba8e5c5988 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 18 Jul 2016 23:13:34 +0300 Subject: [PATCH 063/150] switch compare_method to new-style trait error reporting --- src/librustc_typeck/check/compare_method.rs | 21 ++++++++++--------- .../associated-const-impl-wrong-type.rs | 5 ++--- src/test/compile-fail/issue-13033.rs | 4 +++- src/test/compile-fail/issue-15094.rs | 4 ++-- src/test/compile-fail/issue-21332.rs | 3 +-- src/test/compile-fail/issue-24356.rs | 3 --- .../trait-impl-method-mismatch.rs | 4 ++-- src/test/compile-fail/unsafe-trait-impl.rs | 4 ++-- 8 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 35a5bc9c60967..847dcc90ad395 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -324,10 +324,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - span_err!(tcx.sess, impl_m_span, E0053, - "method `{}` has an incompatible type for trait: {}", - trait_m.name, - terr); + let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty); + type_err!(infcx, trace, &terr, E0053, + "method `{}` has an incompatible type for trait", + trait_m.name).emit(); return } @@ -437,10 +437,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Compute skolemized form of impl and trait const tys. let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs); + let origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { - let origin = TypeOrigin::Misc(impl_c_span); - // There is no "body" here, so just pass dummy id. let impl_ty = assoc::normalize_associated_types_in(&infcx, @@ -473,11 +472,13 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", impl_ty, trait_ty); - span_err!(tcx.sess, impl_c_span, E0326, + let values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_ty, + found: impl_ty + })); + type_err!(infcx, origin, values, terr, E0326, "implemented const `{}` has an incompatible type for \ - trait: {}", - trait_c.name, - terr); + trait", trait_c.name).emit(); } }); } diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index 4658d0f057d71..95508a31044b8 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -18,9 +18,8 @@ struct SignedBar; impl Foo for SignedBar { const BAR: i32 = -1; - //~^ ERROR implemented const `BAR` has an incompatible type for trait - //~| expected u32, - //~| found i32 [E0326] + //~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326] + //~| expected u32, found i32 } fn main() {} diff --git a/src/test/compile-fail/issue-13033.rs b/src/test/compile-fail/issue-13033.rs index 43cf70e5bc3cf..3d9d81471cb1e 100644 --- a/src/test/compile-fail/issue-13033.rs +++ b/src/test/compile-fail/issue-13033.rs @@ -16,7 +16,9 @@ struct Baz; impl Foo for Baz { fn bar(&mut self, other: &Foo) {} - //~^ ERROR method `bar` has an incompatible type for trait: values differ in mutability [E0053] + //~^ ERROR method `bar` has an incompatible type for trait + //~| expected type `fn(&mut Baz, &mut Foo)` + //~| found type `fn(&mut Baz, &Foo)` } fn main() {} diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index 42e3456b309be..da48bbb3ecd71 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -20,8 +20,8 @@ impl ops::FnOnce<(),> for Debuger { type Output = (); fn call_once(self, _args: ()) { //~^ ERROR `call_once` has an incompatible type for trait - //~| expected "rust-call" fn, - //~| found "Rust" fn + //~| expected type `extern "rust-call" fn + //~| found type `fn println!("{:?}", self.x); } } diff --git a/src/test/compile-fail/issue-21332.rs b/src/test/compile-fail/issue-21332.rs index b36918149fa99..db3334834d44e 100644 --- a/src/test/compile-fail/issue-21332.rs +++ b/src/test/compile-fail/issue-21332.rs @@ -14,8 +14,7 @@ impl Iterator for S { type Item = i32; fn next(&mut self) -> Result { Ok(7) } //~^ ERROR method `next` has an incompatible type for trait - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` [E0053] + //~| expected enum `std::option::Option`, found enum `std::result::Result` } fn main() {} diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/compile-fail/issue-24356.rs index 27d46be40fbeb..ede81bea32ae3 100644 --- a/src/test/compile-fail/issue-24356.rs +++ b/src/test/compile-fail/issue-24356.rs @@ -30,9 +30,6 @@ fn main() { impl Deref for Thing { //~^ ERROR not all trait items implemented, missing: `Target` [E0046] fn deref(&self) -> i8 { self.0 } - //~^ ERROR method `deref` has an incompatible type for trait - //~| expected &-ptr - //~| found i8 [E0053] } let thing = Thing(72); diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs index f86d9b7648bbe..a05e007d6b739 100644 --- a/src/test/compile-fail/trait-impl-method-mismatch.rs +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -17,8 +17,8 @@ impl Mumbo for usize { // Cannot have a larger effect than the trait: unsafe fn jumbo(&self, x: &usize) { *self + *x; } //~^ ERROR method `jumbo` has an incompatible type for trait - //~| expected normal fn, - //~| found unsafe fn + //~| expected type `fn + //~| found type `unsafe fn } fn main() {} diff --git a/src/test/compile-fail/unsafe-trait-impl.rs b/src/test/compile-fail/unsafe-trait-impl.rs index 51f876661f651..fb4652affd0d8 100644 --- a/src/test/compile-fail/unsafe-trait-impl.rs +++ b/src/test/compile-fail/unsafe-trait-impl.rs @@ -17,8 +17,8 @@ trait Foo { impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait - //~| expected unsafe fn, - //~| found normal fn + //~| expected type `unsafe fn(&u32) -> u32` + //~| found type `fn(&u32) -> u32` } fn main() { } From fa4eda8935cc902b0757815e774f11ee791af156 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 19 Jul 2016 01:02:47 +0300 Subject: [PATCH 064/150] switch projection errors to use the new type error messages Unfortunately, projection errors do not come with a nice set of mismatched types. This is because the type equality check occurs within a higher-ranked context. Therefore, only the type error is reported. This is ugly but was always the situation. I will introduce better errors for the lower-ranked case in another commit. Fixes the last known occurence of #31173 --- src/librustc/infer/error_reporting.rs | 47 +++++++++++-------- src/librustc/macros.rs | 7 +-- src/librustc/traits/error_reporting.rs | 14 ++++-- src/librustc_typeck/check/compare_method.rs | 8 +++- .../compile-fail/associated-types-eq-3.rs | 6 +-- src/test/compile-fail/issue-31173.rs | 26 ++++++++++ 6 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 src/test/compile-fail/issue-31173.rs diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index be73818c8a4eb..0726d8560bab9 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -522,37 +522,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn report_and_explain_type_error_with_code(&self, - trace: TypeTrace<'tcx>, + origin: TypeOrigin, + values: Option>, terr: &TypeError<'tcx>, message: &str, code: &str) -> DiagnosticBuilder<'tcx> { - let (expected, found) = match self.values_str(&trace.values) { - Some((expected, found)) => (expected, found), - None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + let expected_found = match values { + None => None, + Some(values) => match self.values_str(&values) { + Some((expected, found)) => Some((expected, found)), + None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + } }; - let span = trace.origin.span(); + let span = origin.span(); + let mut err = self.tcx.sess.struct_span_err_with_code( + span, message, code); - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; + let mut is_simple_error = false; - let mut err = self.tcx.sess.struct_span_err_with_code( - trace.origin.span(), - message, - code); + if let Some((expected, found)) = expected_found { + is_simple_error = if let &TypeError::Sorts(ref values) = terr { + values.expected.is_primitive() && values.found.is_primitive() + } else { + false + }; - if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); + if !is_simple_error || check_old_school() { + err.note_expected_found(&"type", &expected, &found); + } } - err.span_label(span, &terr); + if !is_simple_error && check_old_school() { + err.span_note(span, &format!("{}", terr)); + } else { + err.span_label(span, &terr); + } - self.note_error_origin(&mut err, &trace.origin); + self.note_error_origin(&mut err, &origin); self.check_and_note_conflicting_crates(&mut err, terr, span); self.tcx.note_and_explain_type_err(&mut err, terr, span); @@ -566,7 +575,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { // FIXME: do we want to use a different error code for each origin? let failure_str = trace.origin.as_failure_str(); - type_err!(self, trace, terr, E0308, "{}", failure_str) + type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str) } /// Returns a string of the form "expected `{}`, found `{}`". diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 52420475db100..190c9b665e0dd 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -62,11 +62,12 @@ macro_rules! span_bug { #[macro_export] macro_rules! type_err { - ($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ + ($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); $infcx.report_and_explain_type_error_with_code( - $trace, - $terr, + $origin, + $values, + &$terr, &format!($($message)*), stringify!($code)) }) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b9ecb8825854..afbe34f89bbf4 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,7 +26,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{InferCtxt}; +use infer::{InferCtxt, TypeOrigin}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; use ty::fold::TypeFolder; @@ -117,10 +117,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate, error.err)); } else { - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); + let mut err = type_err!( + self, + TypeOrigin::Misc(obligation.cause.span), + None, // FIXME: be smarter + error.err, + E0271, + "type mismatch resolving `{}`", + predicate); self.note_obligation_cause(&mut err, obligation); err.emit(); } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 847dcc90ad395..2c4c6279076dc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -12,6 +12,7 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, ProjectionMode}; +use rustc::ty::error::ExpectedFound; use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace}; use syntax::ast; @@ -324,8 +325,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty); - type_err!(infcx, trace, &terr, E0053, + let values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_fty, + found: impl_fty + })); + type_err!(infcx, origin, values, terr, E0053, "method `{}` has an incompatible type for trait", trait_m.name).emit(); return diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index 8c66160e8a36f..cb952f6534f0e 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -47,10 +47,8 @@ pub fn main() { let a = 42; foo1(a); //~^ ERROR type mismatch resolving - //~| expected usize - //~| found struct `Bar` + //~| expected usize, found struct `Bar` baz(&a); //~^ ERROR type mismatch resolving - //~| expected usize - //~| found struct `Bar` + //~| expected usize, found struct `Bar` } diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs new file mode 100644 index 0000000000000..62d23a99cbadc --- /dev/null +++ b/src/test/compile-fail/issue-31173.rs @@ -0,0 +1,26 @@ +// 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 std::vec::IntoIter; + +pub fn get_tok(it: &mut IntoIter) { + let mut found_e = false; + + let temp: Vec = it.take_while(|&x| { + found_e = true; + false + }) + .cloned() + //~^ ERROR type mismatch resolving + //~| expected u8, found &-ptr + .collect(); //~ ERROR no method named `collect` +} + +fn main() {} From 37c569627cd285788509f654a6a2658126ba72e4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 20 Jul 2016 00:02:56 +0300 Subject: [PATCH 065/150] refactor constant evaluation error reporting Refactor constant evaluation to use a single error reporting function that reports a type-error-like message. Also, unify all error codes with the "constant evaluation error" message to just E0080, and similarly for a few other duplicate codes. The old situation was a total mess, and now that we have *something* we can further iterate on the UX. --- src/librustc_const_eval/Cargo.toml | 1 + src/librustc_const_eval/check_match.rs | 55 ++-- src/librustc_const_eval/diagnostics.rs | 42 +-- src/librustc_const_eval/eval.rs | 258 +++++++++++++----- src/librustc_const_eval/lib.rs | 1 + src/librustc_passes/consts.rs | 28 +- src/librustc_passes/diagnostics.rs | 4 +- src/librustc_trans/_match.rs | 16 +- src/librustc_trans/consts.rs | 21 +- src/librustc_trans/intrinsic.rs | 6 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/trans_item.rs | 7 +- src/librustc_trans/tvec.rs | 6 +- src/librustc_typeck/astconv.rs | 37 +-- src/librustc_typeck/check/mod.rs | 5 +- src/librustc_typeck/collect.rs | 12 +- src/librustc_typeck/diagnostics.rs | 52 +--- src/rustc/Cargo.lock | 1 + src/test/compile-fail/array_const_index-0.rs | 3 +- src/test/compile-fail/array_const_index-1.rs | 3 +- .../associated-const-array-len.rs | 2 +- ...ssociated-const-type-parameter-arrays-2.rs | 3 +- src/test/compile-fail/const-array-oob.rs | 3 +- src/test/compile-fail/const-call.rs | 3 +- src/test/compile-fail/const-err.rs | 24 +- .../compile-fail/const-eval-overflow-2.rs | 11 +- .../compile-fail/const-eval-overflow-3.rs | 2 +- .../compile-fail/const-eval-overflow-4b.rs | 10 +- src/test/compile-fail/const-eval-overflow.rs | 84 ++++-- src/test/compile-fail/const-eval-span.rs | 3 +- src/test/compile-fail/const-fn-error.rs | 5 +- .../compile-fail/const-index-feature-gate.rs | 3 +- .../compile-fail/const-integer-bool-ops.rs | 24 +- .../const-len-underflow-separate-spans.rs | 3 +- .../const-len-underflow-subspans.rs | 3 +- .../const-pattern-not-const-evaluable.rs | 16 +- src/test/compile-fail/const-slice-oob.rs | 3 +- src/test/compile-fail/const-tup-index-span.rs | 3 +- src/test/compile-fail/discrim-ill-typed.rs | 24 +- .../compile-fail/enum-discrim-too-small.rs | 12 +- src/test/compile-fail/eval-enum.rs | 6 +- .../feature-gate-negate-unsigned0.rs | 9 +- .../compile-fail/invalid-path-in-const.rs | 3 +- src/test/compile-fail/issue-22933-2.rs | 6 +- src/test/compile-fail/issue-23217.rs | 3 +- src/test/compile-fail/issue-25145.rs | 3 +- src/test/compile-fail/issue-27008.rs | 2 +- src/test/compile-fail/issue-27895.rs | 3 +- src/test/compile-fail/issue-28586.rs | 2 +- src/test/compile-fail/issue-3521.rs | 3 +- src/test/compile-fail/issue-8761.rs | 12 +- .../non-constant-enum-for-vec-repeat.rs | 3 +- .../non-constant-expr-for-vec-repeat.rs | 4 +- .../non-constant-in-const-path.rs | 3 +- src/test/compile-fail/repeat_count.rs | 19 +- 55 files changed, 506 insertions(+), 376 deletions(-) diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 01872bbe3c049..8967672548b10 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -14,6 +14,7 @@ serialize = { path = "../libserialize" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } +rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 0de00d9d7f631..915a0cf0bdc73 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals}; use ::{const_expr_to_pat, lookup_const_by_id}; use ::EvalHint::ExprTypeChecked; +use eval::report_const_eval_err; use rustc::hir::def::*; use rustc::hir::def_id::{DefId}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; @@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::fold::{Folder, noop_fold_pat}; use rustc::hir::print::pat_to_string; use syntax::ptr::P; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::FnvHashMap; pub const DUMMY_WILD_PAT: &'static Pat = &Pat { @@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { Ok(_) => {} Err(err) => { - let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471, - "constant evaluation error: {}", - err.description()); - if !p.span.contains(err.span) { - diag.span_note(p.span, "in pattern here"); - } - diag.emit(); + report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit(); } } } @@ -838,22 +834,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us } } -fn range_covered_by_constructor(ctor: &Constructor, - from: &ConstVal, to: &ConstVal) -> Option { +fn range_covered_by_constructor(tcx: TyCtxt, span: Span, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal) + -> Result { let (c_from, c_to) = match *ctor { ConstantValue(ref value) => (value, value), ConstantRange(ref from, ref to) => (from, to), - Single => return Some(true), + Single => return Ok(true), _ => bug!() }; - let cmp_from = compare_const_vals(c_from, from); - let cmp_to = compare_const_vals(c_to, to); - match (cmp_from, cmp_to) { - (Some(cmp_from), Some(cmp_to)) => { - Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) - } - _ => None - } + let cmp_from = compare_const_vals(tcx, span, c_from, from)?; + let cmp_to = compare_const_vals(tcx, span, c_to, to)?; + Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) } fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>, @@ -965,13 +958,12 @@ pub fn specialize<'a, 'b, 'tcx>( Some(vec![(pat, Some(mt.ty))]) } else { let expr_value = eval_const_expr(cx.tcx, &expr); - match range_covered_by_constructor(constructor, &expr_value, &expr_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms"); - None - } + match range_covered_by_constructor( + cx.tcx, expr.span, constructor, &expr_value, &expr_value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, } } } @@ -979,13 +971,12 @@ pub fn specialize<'a, 'b, 'tcx>( PatKind::Range(ref from, ref to) => { let from_value = eval_const_expr(cx.tcx, &from); let to_value = eval_const_expr(cx.tcx, &to); - match range_covered_by_constructor(constructor, &from_value, &to_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms"); - None - } + match range_covered_by_constructor( + cx.tcx, pat_span, constructor, &from_value, &to_value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, } } diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index f2abdf831a3b8..45414c33c0754 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -551,44 +551,46 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0306: r##" -In an array literal `[x; N]`, `N` is the number of elements in the array. This -must be an unsigned integer. Erroneous code example: +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +constant expression that had to be evaluated. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: ```compile_fail -let x = [0i32; true]; // error: expected positive integer for repeat count, - // found boolean +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} ``` -Working example: +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: -``` -let x = [0i32; 2]; -``` +https://doc.rust-lang.org/reference.html#ffi-attributes "##, -E0307: r##" -The length of an array is part of its type. For this reason, this length must -be a compile-time constant. Erroneous code example: + +E0306: r##" +In an array literal `[x; N]`, `N` is the number of elements in the array. This +must be an unsigned integer. Erroneous code example: ```compile_fail - let len = 10; - let x = [0i32; len]; // error: expected constant integer for repeat count, - // found variable +let x = [0i32; true]; // error: expected positive integer for repeat count, + // found boolean ``` Working example: ``` -let x = [0i32; 10]; +let x = [0i32; 2]; ``` "##, - } register_diagnostics! { -E0298, // mismatched types between arms -E0299, // mismatched types between arms -E0471, // constant evaluation error: .. + E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0471, // constant evaluation error (in pattern) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a3c707e82a0ff..03d2f596e2165 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path; use rustc::ty::{self, Ty, TyCtxt, subst}; use rustc::ty::util::IntTypeExt; use rustc::traits::ProjectionMode; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::lint; @@ -43,6 +44,7 @@ use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; use rustc_const_math::*; +use rustc_errors::{DiagnosticBuilder, check_old_school}; macro_rules! math { ($e:expr, $op:expr) => { @@ -338,20 +340,80 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(P(hir::Pat { id: expr.id, node: pat, span: span })) } +pub fn report_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) + -> DiagnosticBuilder<'tcx> +{ + let mut err = err; + while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { + err = i_err; + } + + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); + diag +} + +pub fn fatal_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) + -> ! +{ + report_const_eval_err(tcx, err, primary_span, primary_kind).emit(); + tcx.sess.abort_if_errors(); + unreachable!() +} + +pub fn note_const_eval_err<'a, 'tcx>( + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str, + diag: &mut DiagnosticBuilder) +{ + match err.description() { + ConstEvalErrDescription::Simple(message) => { + if check_old_school() { + diag.note(&message); + } else { + diag.span_label(err.span, &message); + } + } + ConstEvalErrDescription::ExpectedFound { error, expected, found } => { + if check_old_school() { + diag.note(&error); + } else { + diag.span_label(err.span, &error); + } + diag.note(&format!("expected `{}`", expected)); + diag.note(&format!("found `{}`", found)); + } + } + + if !primary_span.contains(err.span) { + diag.span_note(primary_span, + &format!("for {} here", primary_kind)); + } +} + pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &Expr) -> ConstVal { match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { Ok(r) => r, // non-const path still needs to be a fatal error, because enums are funky Err(s) => { + report_const_eval_err(tcx, &s, e.span, "expression").emit(); match s.kind { NonConstPath | - UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()), - _ => { - tcx.sess.span_err(s.span, &s.description()); - Dummy - } + UnimplementedConstVal(_) => tcx.sess.abort_if_errors(), + _ => {} } + Dummy }, } } @@ -400,6 +462,7 @@ pub enum ErrKind { IntermediateUnsignedNegative, /// Expected, Got TypeMismatch(String, ConstInt), + BadType(ConstVal), ErroneousReferencedConstant(Box), CharCast(ConstInt), @@ -411,57 +474,96 @@ impl From for ErrKind { } } +#[derive(Clone, Debug)] +pub enum ConstEvalErrDescription<'a> { + Simple(Cow<'a, str>), + ExpectedFound { + error: Cow<'a, str>, + expected: Cow<'a, str>, + found: Cow<'a, str> + } +} + +impl<'a> ConstEvalErrDescription<'a> { + /// Return a one-line description of the error, for lints and such + pub fn into_oneline(self) -> Cow<'a, str> { + match self { + ConstEvalErrDescription::Simple(simple) => simple, + ConstEvalErrDescription::ExpectedFound { + error, + expected, + found + } => { + format!("{}: expected `{}`, found `{}`", error, expected, found) + .into_cow() + } + } + } +} + impl ConstEvalErr { - pub fn description(&self) -> Cow { + pub fn description(&self) -> ConstEvalErrDescription { use self::ErrKind::*; + use self::ConstEvalErrDescription::*; + + macro_rules! simple { + ($msg:expr) => ({ Simple($msg.into_cow()) }); + ($fmt:expr, $($arg:tt)+) => ({ + Simple(format!($fmt, $($arg)+).into_cow()) + }) + } match self.kind { - CannotCast => "can't cast this type".into_cow(), - CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(), - InvalidOpForInts(_) => "can't do this op on integrals".into_cow(), - InvalidOpForBools(_) => "can't do this op on bools".into_cow(), - InvalidOpForFloats(_) => "can't do this op on floats".into_cow(), - InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(), - InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(), - NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(), - NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), - CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(), - - MissingStructField => "nonexistent struct field".into_cow(), - NonConstPath => "non-constant path in constant expression".into_cow(), + CannotCast => simple!("can't cast this type"), + CannotCastTo(s) => simple!("can't cast this type to {}", s), + InvalidOpForInts(_) => simple!("can't do this op on integrals"), + InvalidOpForBools(_) => simple!("can't do this op on bools"), + InvalidOpForFloats(_) => simple!("can't do this op on floats"), + InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"), + InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"), + NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), + NotOn(ref const_val) => simple!("not on {}", const_val.description()), + CallOn(ref const_val) => simple!("call on {}", const_val.description()), + + MissingStructField => simple!("nonexistent struct field"), + NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => - format!("unimplemented constant expression: {}", what).into_cow(), - UnresolvedPath => "unresolved path in constant expression".into_cow(), - ExpectedConstTuple => "expected constant tuple".into_cow(), - ExpectedConstStruct => "expected constant struct".into_cow(), - TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(), - IndexedNonVec => "indexing is only supported for arrays".into_cow(), - IndexNegative => "indices must be non-negative integers".into_cow(), - IndexNotInt => "indices must be integers".into_cow(), + simple!("unimplemented constant expression: {}", what), + UnresolvedPath => simple!("unresolved path in constant expression"), + ExpectedConstTuple => simple!("expected constant tuple"), + ExpectedConstStruct => simple!("expected constant struct"), + TupleIndexOutOfBounds => simple!("tuple index out of bounds"), + IndexedNonVec => simple!("indexing is only supported for arrays"), + IndexNegative => simple!("indices must be non-negative integers"), + IndexNotInt => simple!("indices must be integers"), IndexOutOfBounds { len, index } => { - format!("index out of bounds: the len is {} but the index is {}", - len, index).into_cow() + simple!("index out of bounds: the len is {} but the index is {}", + len, index) } - RepeatCountNotNatural => "repeat count must be a natural number".into_cow(), - RepeatCountNotInt => "repeat count must be integers".into_cow(), + RepeatCountNotNatural => simple!("repeat count must be a natural number"), + RepeatCountNotInt => simple!("repeat count must be integers"), - MiscBinaryOp => "bad operands for binary".into_cow(), - MiscCatchAll => "unsupported constant expr".into_cow(), - IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(), - Math(ref err) => err.description().into_cow(), + MiscBinaryOp => simple!("bad operands for binary"), + MiscCatchAll => simple!("unsupported constant expr"), + IndexOpFeatureGated => simple!("the index operation on const values is unstable"), + Math(ref err) => Simple(err.description().into_cow()), - IntermediateUnsignedNegative => "during the computation of an unsigned a negative \ - number was encountered. This is most likely a bug in\ - the constant evaluator".into_cow(), + IntermediateUnsignedNegative => simple!( + "during the computation of an unsigned a negative \ + number was encountered. This is most likely a bug in\ + the constant evaluator"), TypeMismatch(ref expected, ref got) => { - format!("mismatched types: expected `{}`, found `{}`", - expected, got.description()).into_cow() + ExpectedFound { + error: "mismatched types".into_cow(), + expected: <&str>::into_cow(expected), + found: got.description().into_cow() + } }, - BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), - ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), + BadType(ref i) => simple!("value of wrong type: {:?}", i), + ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), CharCast(ref got) => { - format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow() + simple!("only `u8` can be cast as `char`, not `{}`", got.description()) }, } } @@ -1185,8 +1287,10 @@ fn parse_float(num: &str, fty_hint: Option, span: Span) -> ConstFl }) } -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { - match (a, b) { +pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) + -> Result +{ + let result = match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), (&Float(a), &Float(b)) => a.try_cmp(b).ok(), (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), @@ -1194,62 +1298,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)), (&Char(a), &Char(ref b)) => Some(a.cmp(b)), _ => None, + }; + + match result { + Some(result) => Ok(result), + None => { + // FIXME: can this ever be reached? + span_err!(tcx.sess, span, E0298, + "type mismatch comparing {} and {}", + a.description(), + b.description()); + Err(ErrorReported) + } } } pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + span: Span, a: &Expr, - b: &Expr) -> Option { + b: &Expr) -> Result { let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) { Ok(a) => a, Err(e) => { - tcx.sess.span_err(a.span, &e.description()); - return None; + report_const_eval_err(tcx, &e, a.span, "expression").emit(); + return Err(ErrorReported); } }; let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) { Ok(b) => b, Err(e) => { - tcx.sess.span_err(b.span, &e.description()); - return None; + report_const_eval_err(tcx, &e, b.span, "expression").emit(); + return Err(ErrorReported); } }; - compare_const_vals(&a, &b) + compare_const_vals(tcx, span, &a, &b) } -/// Returns the repeat count for a repeating vector expression. -pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - count_expr: &hir::Expr) -> usize { +/// Returns the value of the length-valued expression +pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + count_expr: &hir::Expr, + reason: &str) + -> Result +{ let hint = UncheckedExprHint(tcx.types.usize); match eval_const_expr_partial(tcx, count_expr, hint, None) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); - val as usize + Ok(val as usize) }, Ok(const_val) => { span_err!(tcx.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", + "expected usize for {}, found {}", + reason, const_val.description()); - 0 + Err(ErrorReported) } Err(err) => { - let err_msg = match count_expr.node { + let mut diag = report_const_eval_err( + tcx, &err, count_expr.span, reason); + + match count_expr.node { hir::ExprPath(None, hir::Path { global: false, ref segments, .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) + }) if segments.len() == 1 => { + if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) { + diag.note(&format!("`{}` is a variable", segments[0].name)); + } } - }; - span_err!(tcx.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - 0 + _ => {} + } + + diag.emit(); + Err(ErrorReported) } } } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 726ba4fc1924f..a6714c178e7cf 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -36,6 +36,7 @@ #[macro_use] extern crate rustc; extern crate rustc_back; extern crate rustc_const_math; +extern crate rustc_errors; extern crate graphviz; extern crate syntax_pos; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 27ce03b2d9390..b0ba38f1db673 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -40,6 +40,7 @@ use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::ProjectionMode; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::middle::const_qualif::ConstQualif; use rustc::lint::builtin::CONST_ERR; @@ -116,7 +117,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span, format!("constant evaluation error: {}. This will \ become a HARD ERROR in the future", - err.description())), + err.description().into_oneline())), } } self.with_mode(mode, |this| { @@ -211,15 +212,6 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } } } - - fn msg(&self) -> &'static str { - match self.mode { - Mode::Const => "constant", - Mode::ConstFn => "constant function", - Mode::StaticMut | Mode::Static => "static", - Mode::Var => bug!(), - } - } } impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { @@ -289,18 +281,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { self.global_expr(Mode::Const, &start); self.global_expr(Mode::Const, &end); - match compare_lit_exprs(self.tcx, start, end) { - Some(Ordering::Less) | - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => { + match compare_lit_exprs(self.tcx, p.span, start, end) { + Ok(Ordering::Less) | + Ok(Ordering::Equal) => {} + Ok(Ordering::Greater) => { span_err!(self.tcx.sess, start.span, E0030, "lower range bound must be less than or equal to upper"); } - None => { - span_err!(self.tcx.sess, p.span, E0014, - "paths in {}s may only refer to constants", - self.msg()); - } + Err(ErrorReported) => {} } } _ => intravisit::walk_pat(self, p) @@ -429,7 +417,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { Err(msg) => { self.tcx.sess.add_lint(CONST_ERR, ex.id, msg.span, - msg.description().into_owned()) + msg.description().into_oneline().into_owned()) } } } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 918e17d21ea99..a616b95ef7203 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -11,7 +11,7 @@ #![allow(non_snake_case)] register_long_diagnostics! { - +/* E0014: r##" Constants can only be initialized by a constant value or, in a future version of Rust, a call to a const function. This error indicates the use @@ -30,7 +30,7 @@ const FOO: i32 = { const X : i32 = 0; X }; const FOO2: i32 = { 0 }; // but brackets are useless here ``` "##, - +*/ E0030: r##" When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 08e894ffbcfd4..f7fd970f37f2f 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -190,7 +190,7 @@ use self::FailureHandler::*; use llvm::{ValueRef, BasicBlockRef}; use rustc_const_eval::check_match::{self, Constructor, StaticInliner}; -use rustc_const_eval::{compare_lit_exprs, eval_const_expr}; +use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err}; use rustc::hir::def::{Def, DefMap}; use rustc::hir::def_id::DefId; use middle::expr_use_visitor as euv; @@ -239,9 +239,9 @@ struct ConstantExpr<'a>(&'a hir::Expr); impl<'a> ConstantExpr<'a> { fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool { - match compare_lit_exprs(tcx, self.0, other.0) { - Some(result) => result == Ordering::Equal, - None => bug!("compare_list_exprs: type mismatch"), + match compare_lit_exprs(tcx, self.0.span, self.0, other.0) { + Ok(result) => result == Ordering::Equal, + Err(_) => bug!("compare_list_exprs: type mismatch"), } } } @@ -288,7 +288,9 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes); let llval = match expr { Ok((llval, _)) => llval, - Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()), + Err(err) => { + fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern"); + } }; let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); @@ -297,11 +299,11 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => { let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) { Ok((l1, _)) => l1, - Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()), + Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"), }; let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) { Ok((l2, _)) => l2, - Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()), + Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"), }; RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 00feb2cd1de09..f662ba75cc6fe 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -14,7 +14,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; use llvm::{InternalLinkage, ValueRef, Bool, True}; use middle::const_qualif::ConstQualif; use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; @@ -44,7 +44,6 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::hir; use std::ffi::{CStr, CString}; -use std::borrow::Cow; use libc::c_uint; use syntax::ast::{self, LitKind}; use syntax::attr::{self, AttrMetaMethods}; @@ -250,10 +249,11 @@ impl ConstEvalFailure { Compiletime(e) => e, } } - pub fn description(&self) -> Cow { + + pub fn as_inner(&self) -> &ConstEvalErr { match self { - &Runtime(ref e) => e.description(), - &Compiletime(ref e) => e.description(), + &Runtime(ref e) => e, + &Compiletime(ref e) => e, } } } @@ -274,7 +274,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let empty_substs = ccx.tcx().mk_substs(Substs::empty()); match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) { Err(Runtime(err)) => { - ccx.tcx().sess.span_err(expr.span, &err.description()); + report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit(); Err(Compiletime(err)) }, other => other, @@ -526,12 +526,15 @@ pub fn const_err(cx: &CrateContext, (Ok(x), _) => Ok(x), (Err(err), TrueConst::Yes) => { let err = ConstEvalErr{ span: span, kind: err }; - cx.tcx().sess.span_err(span, &err.description()); + report_const_eval_err(cx.tcx(), &err, span, "expression").emit(); Err(Compiletime(err)) }, (Err(err), TrueConst::No) => { let err = ConstEvalErr{ span: span, kind: err }; - cx.tcx().sess.span_warn(span, &err.description()); + let mut diag = cx.tcx().sess.struct_span_warn( + span, "this expression will panic at run-time"); + note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag); + diag.emit(); Err(Runtime(err)) }, } @@ -875,7 +878,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::ExprRepeat(ref elem, ref count) => { let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); - let n = eval_repeat_count(cx.tcx(), count); + let n = eval_length(cx.tcx(), count, "repeat count").unwrap(); let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0; let vs = vec![unit_val; n]; if val_ty(unit_val) != llunitty { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index a721361fce0e3..bc5f3a0f22e2a 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -44,6 +44,7 @@ use syntax::ptr::P; use syntax::parse::token; use rustc::session::Session; +use rustc_const_eval::fatal_const_eval_err; use syntax_pos::{Span, DUMMY_SP}; use std::cmp::Ordering; @@ -1408,7 +1409,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // this should probably help simd error reporting consts::TrueConst::Yes) { Ok((vector, _)) => vector, - Err(err) => bcx.sess().span_fatal(span, &err.description()), + Err(err) => { + fatal_const_eval_err(bcx.tcx(), err.as_inner(), span, + "shuffle indices"); + } } } None => llargs[2] diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index da72793abf6da..1f3b13203163f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -925,7 +925,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } Err(ConstEvalFailure::Runtime(err)) => { span_bug!(constant.span, - "MIR constant {:?} results in runtime panic: {}", + "MIR constant {:?} results in runtime panic: {:?}", constant, err.description()) } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8b8e658533ed0..fc95d208f32cc 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -29,6 +29,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst; use rustc::dep_graph::DepNode; +use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; use syntax::{attr,errors}; @@ -81,7 +82,11 @@ impl<'a, 'tcx> TransItem<'tcx> { if let hir::ItemStatic(_, m, ref expr) = item.node { match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), + Err(err) => { + // FIXME: shouldn't this be a `span_err`? + fatal_const_eval_err( + ccx.tcx(), &err, expr.span, "static"); + } }; } else { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index f5b9bef5313f2..92a2d3787bfd6 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -30,7 +30,7 @@ use value::Value; use rustc::ty::{self, Ty}; use rustc::hir; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::eval_length; use syntax::ast; use syntax::parse::token::InternedString; @@ -218,7 +218,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return expr::trans_into(bcx, &element, Ignore); } SaveIn(lldest) => { - match eval_repeat_count(bcx.tcx(), &count_expr) { + match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() { 0 => expr::trans_into(bcx, &element, Ignore), 1 => expr::trans_into(bcx, &element, SaveIn(lldest)), count => { @@ -268,7 +268,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { }, hir::ExprVec(ref es) => es.len(), hir::ExprRepeat(_, ref count_expr) => { - eval_repeat_count(bcx.tcx(), &count_expr) + eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() } _ => span_bug!(content_expr.span, "unexpected vec content") } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9ff30f9ede262..b642a7122194d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -48,10 +48,7 @@ //! case but `&a` in the second. Basically, defaults that appear inside //! an rptr (`&r.T`) use the region `r` that appears in the rptr. -use middle::const_val::ConstVal; -use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; -use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use rustc_const_eval::eval_length; use hir::{self, SelfKind}; use hir::def::{Def, PathResolution}; use hir::def_id::DefId; @@ -70,7 +67,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FnvHashSet}; -use rustc_const_math::ConstInt; use std::cell::RefCell; use syntax::{abi, ast}; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -1741,33 +1737,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty } hir::TyFixedLengthVec(ref ty, ref e) => { - let hint = UncheckedExprHint(tcx.types.usize); - match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) { - Ok(ConstVal::Integral(ConstInt::Usize(i))) => { - let i = i.as_u64(tcx.sess.target.uint_type); - assert_eq!(i as usize as u64, i); - tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize) - }, - Ok(val) => { - span_err!(tcx.sess, ast_ty.span, E0249, - "expected usize value for array length, got {}", - val.description()); - self.tcx().types.err - }, - // array length errors happen before the global constant check - // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) | - Err(r) => { - let mut err = struct_span_err!(tcx.sess, r.span, E0250, - "array length constant \ - evaluation error: {}", - r.description()); - if !ast_ty.span.contains(r.span) { - span_note!(&mut err, ast_ty.span, "for array length here") - } - err.emit(); - self.tcx().types.err - } + if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") { + tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length) + } else { + self.tcx().types.err } } hir::TyTypeof(ref _e) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7076b6a2a900b..c01edc568afd0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -126,7 +126,7 @@ use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; use rustc_back::slice; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::eval_length; mod assoc; mod autoderef; @@ -3539,7 +3539,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprRepeat(ref element, ref count_expr) => { self.check_expr_has_type(&count_expr, tcx.types.usize); - let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr); + let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count") + .unwrap_or(0); let uty = match expected { ExpectHasType(uty) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 41e7a467fa33a..57602b55cc96f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,8 +66,7 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; -use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; @@ -1091,14 +1090,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }, // enum variant evaluation happens before the global constant check // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) | Err(err) => { - let mut diag = struct_span_err!(ccx.tcx.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); - if !e.span.contains(err.span) { - diag.span_note(e.span, "for enum discriminant here"); - } + let mut diag = report_const_eval_err( + ccx.tcx, &err, e.span, "enum discriminant"); diag.emit(); None } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 683328f4eb4a0..38bf869119c6a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1079,25 +1079,6 @@ impl Foo { ``` "##, -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -integer expression provided as an enum discriminant. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -```compile_fail -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -2970,38 +2951,6 @@ not a distinct static type. Likewise, it's not legal to attempt to behavior for specific enum variants. "##, -E0249: r##" -This error indicates a constant expression for the array length was found, but -it was not an integer (signed or unsigned) expression. - -Some examples of code that produces this error are: - -```compile_fail -const A: [u32; "hello"] = []; // error -const B: [u32; true] = []; // error -const C: [u32; 0.0] = []; // error -"##, - -E0250: r##" -There was an error while evaluating the expression for the length of a fixed- -size array type. - -Some examples of this error are: - -```compile_fail -// divide by zero in the length expression -const A: [u32; 1/0] = []; - -// Rust currently will not evaluate the function `foo` at compile time -fn foo() -> usize { 12 } -const B: [u32; foo()] = []; - -// it is an error to try to add `u8` and `f64` -use std::{f64, u8}; -const C: [u32; u8::MAX + f64::EPSILON] = []; -``` -"##, - 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 @@ -4088,6 +4037,7 @@ register_diagnostics! { E0245, // not a trait // E0246, // invalid recursive type // E0247, +// E0249, // E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck E0328, // cannot implement Unsize explicitly diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 4def60e485f7e..0b2287cf233d1 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -105,6 +105,7 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", + "rustc_errors 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index e65230389f9c0..501c66e75cded 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -10,7 +10,8 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ ERROR index out of bounds: the len is 0 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 0 but the index is 1 fn main() { let _ = B; diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index 69d84e24c4982..d3b43e83bfe52 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -10,7 +10,8 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ ERROR index out of bounds: the len is 0 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 0 but the index is 1 fn main() { let _ = B; diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs index 5d8007defc906..0239986f5ad3a 100644 --- a/src/test/compile-fail/associated-const-array-len.rs +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -14,7 +14,7 @@ trait Foo { const ID: usize; } -const X: [i32; ::ID] = [0, 1, 2]; //~ ERROR E0250 +const X: [i32; ::ID] = [0, 1, 2]; //~ ERROR E0080 fn main() { assert_eq!(1, X); diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs index 2f687350f34e0..c3fa39659b968 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -25,7 +25,8 @@ impl Foo for Def { } pub fn test() { - let _array = [4; ::Y]; //~ error: expected constant integer + let _array = [4; ::Y]; //~ ERROR E0080 + //~| non-constant path in constant } fn main() { diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs index faabed4fd5e42..b980bc02c85a2 100644 --- a/src/test/compile-fail/const-array-oob.rs +++ b/src/test/compile-fail/const-array-oob.rs @@ -16,7 +16,8 @@ const FOO: [u32; 3] = [1, 2, 3]; const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval const BLUB: [u32; FOO[4]] = [5, 6]; -//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250] +//~^ ERROR constant evaluation error [E0080] +//~| index out of bounds: the len is 3 but the index is 4 fn main() { let _ = BAR; diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index 1143d3bd5cd96..7e2eabf412d6c 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -15,5 +15,6 @@ fn f(x: usize) -> usize { } fn main() { - let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307] + let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080] + //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index a1d3888e78ea0..f2079800cad31 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -22,21 +22,29 @@ fn black_box(_: T) { // Make sure that the two uses get two errors. const FOO: u8 = [5u8][1]; -//~^ ERROR index out of bounds: the len is 1 but the index is 1 -//~^^ ERROR index out of bounds: the len is 1 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 1 but the index is 1 +//~^^^ ERROR constant evaluation error +//~| index out of bounds: the len is 1 but the index is 1 fn main() { let a = -std::i8::MIN; - //~^ WARN attempted to negate with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to negate with overflow let b = 200u8 + 200u8 + 200u8; - //~^ WARN attempted to add with overflow - //~| WARN attempted to add with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to add with overflow + //~^^^ WARN this expression will panic at run-time + //~| attempted to add with overflow let c = 200u8 * 4; - //~^ WARN attempted to multiply with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to multiply with overflow let d = 42u8 - (42u8 + 1); - //~^ WARN attempted to subtract with overflow + //~^ WARN this expression will panic at run-time + //~| attempted to subtract with overflow let _e = [5u8][1]; - //~^ WARN index out of bounds: the len is 1 but the index is 1 + //~^ WARN this expression will panic at run-time + //~| index out of bounds: the len is 1 but the index is 1 black_box(a); black_box(b); black_box(c); diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 07e27a7dc9a9a..4749457da8814 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -19,13 +19,16 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error: attempted to negate with overflow -//~| ERROR attempted to negate with overflow -//~| ERROR attempted to negate with overflow +//~^ ERROR constant evaluation error +//~| attempted to negate with overflow +//~| ERROR constant evaluation error +//~| attempted to negate with overflow +//~| ERROR constant evaluation error +//~| attempted to negate with overflow fn main() { match -128i8 { - NEG_NEG_128 => println!("A"), //~ NOTE in pattern here + NEG_NEG_128 => println!("A"), //~ NOTE for pattern here _ => println!("B"), } } diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs index c90ae045f96b4..c78c74e9e231b 100644 --- a/src/test/compile-fail/const-eval-overflow-3.rs +++ b/src/test/compile-fail/const-eval-overflow-3.rs @@ -17,7 +17,7 @@ // self-hosted and a cross-compiled setup; therefore resorting to // error-pattern for now. -// error-pattern: expected constant integer for repeat count, but attempted to add with overflow +// error-pattern: attempted to add with overflow #![allow(unused_imports)] diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 31e1a72967f4d..e7639a4ff70ab 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -20,9 +20,10 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] - //~^ ERROR mismatched types: - //~| expected `i8`, - //~| found `u8` [E0250] + //~^ ERROR constant evaluation error [E0080] + //~| mismatched types + //~| expected `i8` + //~| found `u8` = [0; (i8::MAX as usize) + 1]; @@ -33,7 +34,8 @@ const A_CHAR_USIZE const A_BAD_CHAR_USIZE : [u32; 5i8 as char as usize] - //~^ ERROR only `u8` can be cast as `char`, not `i8` + //~^ ERROR constant evaluation error + //~| only `u8` can be cast as `char`, not `i8` = [0; 5]; fn main() {} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index 3dfcb5bb29a24..c1c693544fa96 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -21,86 +21,114 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8, i8, i8, i8) = (-i8::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i8::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i8::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i8::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_I16: (i16, i16, i16, i16) = (-i16::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i16::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i16::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i16::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_I32: (i32, i32, i32, i32) = (-i32::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i32::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i32::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i32::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_I64: (i64, i64, i64, i64) = (-i64::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempted to negate with overflow i64::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow i64::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow i64::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U8: (u8, u8, u8, u8) = (-(u8::MIN as i8) as u8, u8::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u8::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u8::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U16: (u16, u16, u16, u16) = (-(u16::MIN as i16) as u16, u16::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u16::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u16::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U32: (u32, u32, u32, u32) = (-(u32::MIN as i32) as u32, u32::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u32::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u32::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); const VALS_U64: (u64, u64, u64, u64) = (-(u64::MIN as i64) as u64, u64::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempted to subtract with overflow u64::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempted to add with overflow u64::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempted to multiply with overflow ); fn main() { diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs index 9fdd24c42fdbd..73351429b5060 100644 --- a/src/test/compile-fail/const-eval-span.rs +++ b/src/test/compile-fail/const-eval-span.rs @@ -14,7 +14,8 @@ struct S(i32); const CONSTANT: S = S(0); -//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080] +//~^ ERROR E0080 +//~| unimplemented constant expression: tuple struct constructors enum E { V = CONSTANT, diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 45a00de48e712..dd0f058f2c95c 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -17,10 +17,11 @@ const fn f(x: usize) -> usize { for i in 0..x { sum += i; } - sum //~ ERROR: E0250 + sum //~ ERROR E0080 + //~| non-constant path in constant } #[allow(unused_variables)] fn main() { - let a : [i32; f(X)]; + let a : [i32; f(X)]; //~ NOTE for array length here } diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/compile-fail/const-index-feature-gate.rs index 09822e46cc1ab..4f92770df289c 100644 --- a/src/test/compile-fail/const-index-feature-gate.rs +++ b/src/test/compile-fail/const-index-feature-gate.rs @@ -9,7 +9,8 @@ // except according to those terms. const ARR: [usize; 1] = [2]; -const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable +const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080 + //~| unstable fn main() { } diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs index 0d6cf3bab453f..5dadd892f8352 100644 --- a/src/test/compile-fail/const-integer-bool-ops.rs +++ b/src/test/compile-fail/const-integer-bool-ops.rs @@ -8,30 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals +const X: usize = 42 && 39; //~ ERROR E0080 + //~| can't do this op on integrals const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here -const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals +const X1: usize = 42 || 39; //~ ERROR E0080 + //~| can't do this op on integrals const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here -const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer +const X2: usize = -42 || -39; //~ ERROR E0080 + //~| unary negation of unsigned integer const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here -const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer +const X3: usize = -42 && -39; //~ ERROR E0080 + //~| unary negation of unsigned integer const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here const Y: usize = 42.0 == 42.0; -const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y1: usize = 42.0 >= 42.0; -const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y2: usize = 42.0 <= 42.0; -const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y3: usize = 42.0 > 42.0; -const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length const Y4: usize = 42.0 < 42.0; -const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length const Y5: usize = 42.0 != 42.0; -const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length fn main() { let _ = ARR; diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index 9c6b774b99039..43375ee3d1896 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -15,7 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250] +//~^ ERROR E0080 +//~| attempted to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs index d51f31087d0df..e338f206553b4 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -16,5 +16,6 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); - //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250] + //~^ ERROR constant evaluation error [E0080] + //~| attempted to subtract with overflow } diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index 4567cd4a74bb2..d68d63683a79c 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -17,22 +17,26 @@ enum Cake { use Cake::*; const BOO: (Cake, Cake) = (Marmor, BlackForest); -//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471] +//~^ ERROR: constant evaluation error [E0080] +//~| unimplemented constant expression: enum variants const FOO: Cake = BOO.1; const fn foo() -> Cake { - Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants - //~^ ERROR: unimplemented constant expression: enum variants + Marmor + //~^ ERROR: constant evaluation error [E0080] + //~| unimplemented constant expression: enum variants + //~^^^ ERROR: constant evaluation error [E0080] + //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; -const GOO: Cake = foo(); +const GOO: Cake = foo(); //~ NOTE for expression here fn main() { match BlackForest { - FOO => println!("hi"), //~ NOTE: in pattern here - GOO => println!("meh"), //~ NOTE: in pattern here + FOO => println!("hi"), //~ NOTE: for pattern here + GOO => println!("meh"), //~ NOTE: for pattern here WORKS => println!("möp"), _ => println!("bye"), } diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index d63b0097e5a0c..b1b4bfe2d1c39 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -10,7 +10,8 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ ERROR index out of bounds: the len is 3 but the index is 5 +//~^ ERROR constant evaluation error [E0080] +//~| index out of bounds: the len is 3 but the index is 5 fn main() { let _ = BAR; diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 9d3c432d14878..6f095b3041ffe 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -11,7 +11,8 @@ // Test spans of errors const TUP: (usize,) = 5 << 64; -//~^ ERROR: attempted to shift left with overflow [E0250] +//~^ ERROR E0080 +//~| attempted to shift left with overflow const ARR: [i32; TUP.0] = []; fn main() { diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index 23106c99594a6..5af889cb23999 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -25,7 +25,8 @@ fn f_i8() { Ok = i8::MAX - 1, Ok2, OhNo = 0_u8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -37,7 +38,8 @@ fn f_u8() { Ok = u8::MAX - 1, Ok2, OhNo = 0_i8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -49,7 +51,8 @@ fn f_i16() { Ok = i16::MAX - 1, Ok2, OhNo = 0_u16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -61,7 +64,8 @@ fn f_u16() { Ok = u16::MAX - 1, Ok2, OhNo = 0_i16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -73,7 +77,8 @@ fn f_i32() { Ok = i32::MAX - 1, Ok2, OhNo = 0_u32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -85,7 +90,8 @@ fn f_u32() { Ok = u32::MAX - 1, Ok2, OhNo = 0_i32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -97,7 +103,8 @@ fn f_i64() { Ok = i64::MAX - 1, Ok2, OhNo = 0_u64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; @@ -109,7 +116,8 @@ fn f_u64() { Ok = u64::MAX - 1, Ok2, OhNo = 0_i64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| mismatched types } let x = A::Ok; diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs index d6ba09bb4c5bf..bbdb3891d9980 100644 --- a/src/test/compile-fail/enum-discrim-too-small.rs +++ b/src/test/compile-fail/enum-discrim-too-small.rs @@ -13,28 +13,32 @@ enum Eu8 { Au8 = 23, Bu8 = 223, - Cu8 = -23, //~ ERROR unary negation of unsigned integer + Cu8 = -23, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u16)] enum Eu16 { Au16 = 23, Bu16 = 55555, - Cu16 = -22333, //~ ERROR unary negation of unsigned integer + Cu16 = -22333, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u32)] enum Eu32 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer + Cu32 = -2_000_000_000, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u64)] enum Eu64 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer + Cu32 = -2_000_000_000, //~ ERROR E0080 + //~| unary negation of unsigned integer } // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 7ca274b81e574..57db583aefe23 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -9,9 +9,11 @@ // except according to those terms. enum test { - div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero + div_zero = 1/0, //~ ERROR E0080 + //~| attempted to divide by zero rem_zero = 1%0, -//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero + //~^ ERROR E0080 + //~| attempted to calculate the remainder with a divisor of zero } fn main() {} diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs index 05b194345d405..89ae1a09bd3e4 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned0.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned0.rs @@ -18,14 +18,17 @@ impl std::ops::Neg for S { fn main() { let a = -1; - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer let _b : u8 = a; // for infering variable a to u8. let _d = -1u8; - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer for _ in -10..10u8 {} - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer -S; // should not trigger the gate; issue 26840 } diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs index 3c4ad5a56ec36..9a9358b787f53 100644 --- a/src/test/compile-fail/invalid-path-in-const.rs +++ b/src/test/compile-fail/invalid-path-in-const.rs @@ -10,5 +10,6 @@ fn main() { fn f(a: [u8; u32::DOESNOTEXIST]) {} - //~^ ERROR unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index 7d619c270d32b..54a2408935461 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -12,10 +12,12 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR constant evaluation error: unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } const FOO: [u32; u8::MIN as usize] = []; -//~^ ERROR array length constant evaluation error: unresolved path in constant expression +//~^ ERROR constant evaluation error +//~| unresolved path in constant expression fn main() {} diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs index 32cdd6b5ed9f2..c2bcbb9d54a9a 100644 --- a/src/test/compile-fail/issue-23217.rs +++ b/src/test/compile-fail/issue-23217.rs @@ -10,7 +10,8 @@ pub enum SomeEnum { B = SomeEnum::A, - //~^ ERROR constant evaluation error: unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } fn main() {} diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs index e8a9c8d2ea34b..93f75e9bfed0d 100644 --- a/src/test/compile-fail/issue-25145.rs +++ b/src/test/compile-fail/issue-25145.rs @@ -17,6 +17,7 @@ impl S { } static STUFF: [u8; S::N] = [0; S::N]; -//~^ ERROR array length constant evaluation error: unresolved path in constant expression +//~^ ERROR constant evaluation error +//~| unresolved path in constant expression fn main() {} diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs index bdcbaf09177fe..ee6ec52761266 100644 --- a/src/test/compile-fail/issue-27008.rs +++ b/src/test/compile-fail/issue-27008.rs @@ -16,5 +16,5 @@ fn main() { //~| expected type `usize` //~| found type `S` //~| expected usize, found struct `S` - //~| ERROR expected positive integer for repeat count, found struct + //~| ERROR expected usize for repeat count, found struct } diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index 3b3abc94a4900..ca8d5a1f70473 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -14,7 +14,8 @@ fn main() { match i { 0...index => println!("winner"), - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression _ => println!("hello"), } } diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs index c8a1e424da2e2..1dfd146985ff4 100644 --- a/src/test/compile-fail/issue-28586.rs +++ b/src/test/compile-fail/issue-28586.rs @@ -11,6 +11,6 @@ // Regression test for issue #28586 pub trait Foo {} -impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250 +impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080 fn main() { } diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index 52375ef281ace..1b6e4b1d289e4 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -15,7 +15,8 @@ fn main() { enum Stuff { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant - //~^^ ERROR constant evaluation error: non-constant path in constant expression + //~^^ ERROR constant evaluation error + //~| non-constant path in constant expression } println!("{}", Stuff::Bar); diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 1c98abce0304e..6352f4f6a0447 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -10,13 +10,13 @@ enum Foo { A = 1i64, - //~^ ERROR mismatched types: - //~| expected `isize`, - //~| found `i64` [E0080] + //~^ ERROR constant evaluation error + //~| expected `isize` + //~| found `i64` B = 2u8 - //~^ ERROR mismatched types: - //~| expected `isize`, - //~| found `u8` [E0080] + //~^ ERROR constant evaluation error + //~| expected `isize` + //~| found `u8` } fn main() {} diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs index 9564a080b8ee7..cadfec5a38d3d 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs @@ -15,5 +15,6 @@ enum State { ST_NULL, ST_WHITESPACE } fn main() { [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression + //~^ ERROR constant evaluation error + //~| unimplemented constant expression: enum variants } diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs index 3ce206ff7fb2c..a6f88a57b9125 100644 --- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs @@ -13,6 +13,8 @@ fn main() { fn bar(n: usize) { let _x = [0; n]; - //~^ ERROR expected constant integer for repeat count, found variable + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression + //~| NOTE `n` is a variable } } diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index ee88168515d39..737f80372debf 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -12,6 +12,7 @@ fn main() { let x = 0; match 1 { 0 ... x => {} - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression }; } diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index ab5af64d95c13..d68df97364169 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -13,37 +13,38 @@ fn main() { let n = 1; let a = [0; n]; - //~^ ERROR expected constant integer for repeat count, found variable [E0307] + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression let b = [0; ()]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `()` //~| expected usize, found () - //~| ERROR expected positive integer for repeat count, found tuple [E0306] + //~| ERROR expected usize for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types //~| expected usize, found bool - //~| ERROR expected positive integer for repeat count, found boolean [E0306] + //~| ERROR expected usize for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `_` //~| expected usize, found floating-point variable - //~| ERROR expected positive integer for repeat count, found float [E0306] + //~| ERROR expected usize for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `&'static str` //~| expected usize, found &-ptr - //~| ERROR expected positive integer for repeat count, found string literal [E0306] + //~| ERROR expected usize for repeat count, found string literal [E0306] let f = [0; -4_isize]; - //~^ ERROR mismatched types + //~^ ERROR constant evaluation error //~| expected `usize` //~| found `isize` - //~| ERROR mismatched types: + //~| ERROR mismatched types //~| expected usize, found isize let f = [0_usize; -1_isize]; - //~^ ERROR mismatched types + //~^ ERROR constant evaluation error //~| expected `usize` //~| found `isize` //~| ERROR mismatched types @@ -56,5 +57,5 @@ fn main() { //~| expected type `usize` //~| found type `main::G` //~| expected usize, found struct `main::G` - //~| ERROR expected positive integer for repeat count, found struct [E0306] + //~| ERROR expected usize for repeat count, found struct [E0306] } From 712c5cadbbb460a0b313a2fbcdaa9d6e10a25b6b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 19 Jul 2016 01:10:19 +0300 Subject: [PATCH 066/150] remove the now-unused multiline error code --- src/librustc/session/mod.rs | 81 ++----------------------------------- 1 file changed, 4 insertions(+), 77 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index fa9bc7c83680c..5901c42b52582 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -126,20 +126,14 @@ impl Session { sp: S, msg: &str) -> DiagnosticBuilder<'a> { - match split_msg_into_multilines(msg) { - Some(ref msg) => self.diagnostic().struct_span_err(sp, msg), - None => self.diagnostic().struct_span_err(sp, msg), - } + self.diagnostic().struct_span_err(sp, msg) } pub fn struct_span_err_with_code<'a, S: Into>(&'a self, sp: S, msg: &str, code: &str) -> DiagnosticBuilder<'a> { - match split_msg_into_multilines(msg) { - Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code), - None => self.diagnostic().struct_span_err_with_code(sp, msg, code), - } + self.diagnostic().struct_span_err_with_code(sp, msg, code) } pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_err(msg) @@ -178,16 +172,10 @@ impl Session { } } pub fn span_err>(&self, sp: S, msg: &str) { - match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err(sp, &msg), - None => self.diagnostic().span_err(sp, msg) - } + self.diagnostic().span_err(sp, msg) } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { - match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code), - None => self.diagnostic().span_err_with_code(sp, msg, code) - } + self.diagnostic().span_err_with_code(sp, &msg, code) } pub fn err(&self, msg: &str) { self.diagnostic().err(msg) @@ -343,67 +331,6 @@ impl Session { } } -fn split_msg_into_multilines(msg: &str) -> Option { - // Conditions for enabling multi-line errors: - if !msg.contains("mismatched types") && - !msg.contains("type mismatch resolving") && - !msg.contains("if and else have incompatible types") && - !msg.contains("if may be missing an else clause") && - !msg.contains("match arms have incompatible types") && - !msg.contains("structure constructor specifies a structure of type") && - !msg.contains("has an incompatible type for trait") { - return None - } - let first = msg.match_indices("expected").filter(|s| { - let last = msg[..s.0].chars().rev().next(); - last == Some(' ') || last == Some('(') - }).map(|(a, b)| (a - 1, a + b.len())); - let second = msg.match_indices("found").filter(|s| { - msg[..s.0].chars().rev().next() == Some(' ') - }).map(|(a, b)| (a - 1, a + b.len())); - - let mut new_msg = String::new(); - let mut head = 0; - - // Insert `\n` before expected and found. - for (pos1, pos2) in first.zip(second) { - new_msg = new_msg + - // A `(` may be preceded by a space and it should be trimmed - msg[head..pos1.0].trim_right() + // prefix - "\n" + // insert before first - &msg[pos1.0..pos1.1] + // insert what first matched - &msg[pos1.1..pos2.0] + // between matches - "\n " + // insert before second - // 123 - // `expected` is 3 char longer than `found`. To align the types, - // `found` gets 3 spaces prepended. - &msg[pos2.0..pos2.1]; // insert what second matched - - head = pos2.1; - } - - let mut tail = &msg[head..]; - let third = tail.find("(values differ") - .or(tail.find("(lifetime")) - .or(tail.find("(cyclic type of infinite size")); - // Insert `\n` before any remaining messages which match. - if let Some(pos) = third { - // The end of the message may just be wrapped in `()` without - // `expected`/`found`. Push this also to a new line and add the - // final tail after. - new_msg = new_msg + - // `(` is usually preceded by a space and should be trimmed. - tail[..pos].trim_right() + // prefix - "\n" + // insert before paren - &tail[pos..]; // append the tail - - tail = ""; - } - - new_msg.push_str(tail); - return Some(new_msg); -} - pub fn build_session(sopts: config::Options, dep_graph: &DepGraph, local_crate_source_file: Option, From f3ee99bd4d9d282c33127449073c521f29b07c21 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 21 Jul 2016 02:13:14 +0300 Subject: [PATCH 067/150] try to recover the non-matching types in projection errors The type equation in projection takes place under a binder and a snapshot, which we can't easily take types out of. Instead, when encountering a projection error, try to re-do the projection and find the type error then. This fails to produce a sane type error when the failure was a "leak_check" failure. I can't think of a sane way to show *these*, so I just left them use the old crappy representation, and added a test to make sure we don't break them. --- src/librustc/traits/error_reporting.rs | 81 ++++++++++++++----- .../higher-ranked-projection.rs | 38 +++++++++ src/test/compile-fail/issue-31173.rs | 3 +- 3 files changed, 100 insertions(+), 22 deletions(-) create mode 100644 src/test/compile-fail/associated-types/higher-ranked-projection.rs diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index afbe34f89bbf4..33ca1d05cad7e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,8 +26,9 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{InferCtxt, TypeOrigin}; +use infer::{self, InferCtxt, TypeOrigin}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::{self, Subst, TypeSpace}; @@ -107,28 +108,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); - if !predicate.references_error() { - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, + if predicate.references_error() { + return + } + if let Some(warning_node_id) = warning_node_id { + self.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("type mismatch resolving `{}`: {}", + predicate, + error.err)); + return + } + self.probe(|_| { + let origin = TypeOrigin::Misc(obligation.cause.span); + let err_buf; + let mut err = &error.err; + let mut values = None; + + // try to find the mismatched types to report the error with. + // + // this can fail if the problem was higher-ranked, in which + // cause I have no idea for a good error message. + if let ty::Predicate::Projection(ref data) = predicate { + let mut selcx = SelectionContext::new(self); + let (data, _) = self.replace_late_bound_regions_with_fresh_var( obligation.cause.span, - format!("type mismatch resolving `{}`: {}", - predicate, - error.err)); - } else { - let mut err = type_err!( - self, - TypeOrigin::Misc(obligation.cause.span), - None, // FIXME: be smarter - error.err, - E0271, - "type mismatch resolving `{}`", - predicate); - self.note_obligation_cause(&mut err, obligation); - err.emit(); + infer::LateBoundRegionConversionTime::HigherRankedType, + data); + let normalized = super::normalize_projection_type( + &mut selcx, + data.projection_ty, + obligation.cause.clone(), + 0 + ); + let origin = TypeOrigin::Misc(obligation.cause.span); + if let Err(error) = self.eq_types( + false, origin, + data.ty, normalized.value + ) { + values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: normalized.value, + found: data.ty, + })); + err_buf = error; + err = &err_buf; + } } - } + + let mut diag = type_err!( + self, + origin, + values, + err, + E0271, + "type mismatch resolving `{}`", + predicate); + self.note_obligation_cause(&mut diag, obligation); + diag.emit(); + }); } fn impl_substs(&self, diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs new file mode 100644 index 0000000000000..12341fa8db38f --- /dev/null +++ b/src/test/compile-fail/associated-types/higher-ranked-projection.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. + +#![feature(rustc_attrs)] + +// revisions: good bad + +trait Mirror { + type Image; +} + +impl Mirror for T { + type Image = T; +} + +#[cfg(bad)] +fn foo(_t: T) + where for<'a> &'a T: Mirror +{} + +#[cfg(good)] +fn foo(_t: T) + where for<'a> &'a T: Mirror +{} + +#[rustc_error] +fn main() { //[good]~ ERROR compilation successful + foo(()); + //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` + //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime +} diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs index 62d23a99cbadc..fb1e3cc87e88c 100644 --- a/src/test/compile-fail/issue-31173.rs +++ b/src/test/compile-fail/issue-31173.rs @@ -19,7 +19,8 @@ pub fn get_tok(it: &mut IntoIter) { }) .cloned() //~^ ERROR type mismatch resolving - //~| expected u8, found &-ptr + //~| expected type `u8` + //~| found type `&_` .collect(); //~ ERROR no method named `collect` } From 0d192c34991aef87a06e1a3e2396228b03508796 Mon Sep 17 00:00:00 2001 From: abhi Date: Fri, 22 Jul 2016 17:50:54 +0530 Subject: [PATCH 068/150] Update VecDeque documentation to specify direction of index 0 (#34920) --- src/libcollections/vec_deque.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 9e4428ec57d50..9c3792afa2f1c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -402,6 +402,8 @@ impl VecDeque { /// Retrieves an element in the `VecDeque` by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -425,6 +427,8 @@ impl VecDeque { /// Retrieves an element in the `VecDeque` mutably by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -456,6 +460,8 @@ impl VecDeque { /// /// Fails if there is no element with either index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1180,6 +1186,8 @@ impl VecDeque { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1214,6 +1222,8 @@ impl VecDeque { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1245,6 +1255,8 @@ impl VecDeque { /// end is closer to the insertion point will be moved to make room, /// and all the affected elements will be moved to new positions. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `index` is greater than `VecDeque`'s length @@ -1472,6 +1484,8 @@ impl VecDeque { /// room, and all the affected elements will be moved to new positions. /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1651,6 +1665,8 @@ impl VecDeque { /// /// Note that the capacity of `self` does not change. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `at > len` From ec33dab062aba12ff248a4fd3cb04c7c8d0dfd27 Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 20 Jul 2016 14:44:15 +0200 Subject: [PATCH 069/150] Add HashMap Entry enums examples --- src/libstd/collections/hash/map.rs | 203 ++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 5 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 60d7e01d98814..a4aa434d6c47f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1336,6 +1336,10 @@ impl<'a, K, V> InternalEntry> { } /// A view into a single location in a map, which may be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied Entry. @@ -1352,6 +1356,9 @@ pub enum Entry<'a, K: 'a, V: 'a> { } /// A view into a single occupied location in a HashMap. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { key: Option, @@ -1359,6 +1366,9 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { } /// A view into a single empty location in a HashMap. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { hash: SafeHash, @@ -1518,6 +1528,20 @@ impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// *map.entry("poneyland").or_insert(12) += 10; + /// assert_eq!(map["poneyland"], 22); + /// ``` pub fn or_insert(self, default: V) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -1528,6 +1552,19 @@ impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_owned(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_owned()); + /// ``` pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -1536,6 +1573,15 @@ impl<'a, K, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { @@ -1547,37 +1593,130 @@ impl<'a, K, V> Entry<'a, K, V> { impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.elem.read().0 } /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_pair(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn remove_pair(self) -> (K, V) { pop_internal(self.elem) } /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> &V { self.elem.read().1 } /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { self.elem.read_mut().1 } /// Converts the OccupiedEntry into a mutable reference to the value in the entry - /// with a lifetime bound to the map itself + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { self.elem.into_mut_refs().1 } - /// Sets the value of the entry, and returns the entry's old value + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, mut value: V) -> V { let old_value = self.get_mut(); @@ -1585,7 +1724,23 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { value } - /// Takes the value out of the entry, and returns it + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(self) -> V { pop_internal(self.elem).1 @@ -1601,20 +1756,58 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value - /// through the VacantEntry. + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn into_key(self) -> K { self.key } /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { match self.elem { From 3c8fae369f54649fe90dc85f284e897974aeb1ca Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 22 Jul 2016 14:57:52 +0200 Subject: [PATCH 070/150] Add Random state doc --- src/libstd/collections/hash/map.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 60d7e01d98814..d4b09807e749b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1666,6 +1666,17 @@ impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap /// A particular instance `RandomState` will create the same instances of /// `Hasher`, but the hashers created by two different `RandomState` /// instances are unlikely to produce the same result for the same values. +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashMap; +/// use std::collections::hash_map::RandomState; +/// +/// let s = RandomState::new(); +/// let mut map = HashMap::with_hasher(s); +/// map.insert(1, 2); +/// ``` #[derive(Clone)] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub struct RandomState { @@ -1675,6 +1686,14 @@ pub struct RandomState { impl RandomState { /// Constructs a new `RandomState` that is initialized with random keys. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// ``` #[inline] #[allow(deprecated)] // rand #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] From 890706070dee22035032f936a51a122670d1cd40 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 22 Jul 2016 16:38:16 +0200 Subject: [PATCH 071/150] Add BuildHasher example --- src/libcore/hash/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 9e3f7a4a84a81..27fdbd383017f 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -234,6 +234,16 @@ pub trait BuildHasher { type Hasher: Hasher; /// Creates a new hasher. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::RandomState; + /// use std::hash::BuildHasher; + /// + /// let s = RandomState::new(); + /// let new_s = s.build_hasher(); + /// ``` #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } From f2f8bbc49f240c9494f876c57389ad58fe7d6bb0 Mon Sep 17 00:00:00 2001 From: Camille Roussel Date: Fri, 22 Jul 2016 10:48:19 -0400 Subject: [PATCH 072/150] Fixed to spelling errors in char.rs Fixed two small spelling mistakes (interator -> iterator) in the documentation for encode_utf8 and encode_utf16 --- src/librustc_unicode/char.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 7445ff94eb502..1ea0f8d70a8eb 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -392,7 +392,7 @@ impl char { C::len_utf16(self) } - /// Returns an interator over the bytes of this character as UTF-8. + /// Returns an iterator over the bytes of this character as UTF-8. /// /// The returned iterator also has an `as_slice()` method to view the /// encoded bytes as a byte slice. @@ -415,7 +415,7 @@ impl char { C::encode_utf8(self) } - /// Returns an interator over the `u16` entries of this character as UTF-16. + /// Returns an iterator over the `u16` entries of this character as UTF-16. /// /// The returned iterator also has an `as_slice()` method to view the /// encoded form as a slice. From 1e4f6d56836e9f9867bb8b05efc2fffceab6b423 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 21 Jul 2016 20:12:04 +0300 Subject: [PATCH 073/150] rustc_errors: fix a few bugs --- src/librustc_errors/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 6a48f65714cc5..610e5647d6d12 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -531,10 +531,12 @@ impl Handler { DiagnosticBuilder::new(self, Level::Fatal, msg) } - pub fn cancel(&mut self, err: &mut DiagnosticBuilder) { + pub fn cancel(&self, err: &mut DiagnosticBuilder) { if err.level == Level::Error || err.level == Level::Fatal { - assert!(self.has_errors()); - self.err_count.set(self.err_count.get() + 1); + self.err_count.set( + self.err_count.get().checked_sub(1) + .expect("cancelled an error but err_count is 0") + ); } err.cancel(); } From 93a96835b09fda7aefb886c9c1c9daa5831bdac6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 21 Jul 2016 20:12:30 +0300 Subject: [PATCH 074/150] use diagnostic-mutating style for `note_type_err` too that is much cleaner than the `type_err!` style I used earlier. --- src/librustc/infer/error_reporting.rs | 42 +++++++++++---------- src/librustc/macros.rs | 13 ------- src/librustc/traits/error_reporting.rs | 13 +++---- src/librustc_typeck/check/compare_method.rs | 40 +++++++++++++------- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 0726d8560bab9..511cc32d2e1e6 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -521,25 +521,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_and_explain_type_error_with_code(&self, - origin: TypeOrigin, - values: Option>, - terr: &TypeError<'tcx>, - message: &str, - code: &str) - -> DiagnosticBuilder<'tcx> + pub fn note_type_err(&self, + diag: &mut DiagnosticBuilder<'tcx>, + origin: TypeOrigin, + values: Option>, + terr: &TypeError<'tcx>) { let expected_found = match values { None => None, Some(values) => match self.values_str(&values) { Some((expected, found)) => Some((expected, found)), - None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ + None => { + // Derived error. Cancel the emitter. + self.tcx.sess.diagnostic().cancel(diag); + return + } } }; let span = origin.span(); - let mut err = self.tcx.sess.struct_span_err_with_code( - span, message, code); let mut is_simple_error = false; @@ -551,21 +551,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); + diag.note_expected_found(&"type", &expected, &found); } } if !is_simple_error && check_old_school() { - err.span_note(span, &format!("{}", terr)); + diag.span_note(span, &format!("{}", terr)); } else { - err.span_label(span, &terr); + diag.span_label(span, &terr); } - self.note_error_origin(&mut err, &origin); - self.check_and_note_conflicting_crates(&mut err, terr, span); - self.tcx.note_and_explain_type_err(&mut err, terr, span); - - err + self.note_error_origin(diag, &origin); + self.check_and_note_conflicting_crates(diag, terr, span); + self.tcx.note_and_explain_type_err(diag, terr, span); } pub fn report_and_explain_type_error(&self, @@ -574,8 +572,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> { // FIXME: do we want to use a different error code for each origin? - let failure_str = trace.origin.as_failure_str(); - type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str) + let mut diag = struct_span_err!( + self.tcx.sess, trace.origin.span(), E0308, + "{}", trace.origin.as_failure_str() + ); + self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr); + diag } /// Returns a string of the form "expected `{}`, found `{}`". diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 190c9b665e0dd..76dca1bb5b649 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -59,16 +59,3 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } - -#[macro_export] -macro_rules! type_err { - ($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({ - __diagnostic_used!($code); - $infcx.report_and_explain_type_error_with_code( - $origin, - $values, - &$terr, - &format!($($message)*), - stringify!($code)) - }) -} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 33ca1d05cad7e..67ad887530eb3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -157,14 +157,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - let mut diag = type_err!( - self, - origin, - values, - err, - E0271, - "type mismatch resolving `{}`", - predicate); + let mut diag = struct_span_err!( + self.tcx.sess, origin.span(), E0271, + "type mismatch resolving `{}`", predicate + ); + self.note_type_err(&mut diag, origin, values, err); self.note_obligation_cause(&mut diag, obligation); diag.emit(); }); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2c4c6279076dc..9844377d0bd32 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -325,13 +325,19 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - let values = Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_fty, - found: impl_fty - })); - type_err!(infcx, origin, values, terr, E0053, - "method `{}` has an incompatible type for trait", - trait_m.name).emit(); + + let mut diag = struct_span_err!( + tcx.sess, origin.span(), E0053, + "method `{}` has an incompatible type for trait", trait_m.name + ); + infcx.note_type_err( + &mut diag, origin, + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_fty, + found: impl_fty + })), &terr + ); + diag.emit(); return } @@ -476,13 +482,19 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", impl_ty, trait_ty); - let values = Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_ty, - found: impl_ty - })); - type_err!(infcx, origin, values, terr, E0326, - "implemented const `{}` has an incompatible type for \ - trait", trait_c.name).emit(); + let mut diag = struct_span_err!( + tcx.sess, origin.span(), E0326, + "implemented const `{}` has an incompatible type for trait", + trait_c.name + ); + infcx.note_type_err( + &mut diag, origin, + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_ty, + found: impl_ty + })), &terr + ); + diag.emit(); } }); } From e76a46a10d9bc0e5a2765addf24c3069555bdc83 Mon Sep 17 00:00:00 2001 From: ggomez Date: Thu, 21 Jul 2016 16:07:08 +0200 Subject: [PATCH 075/150] Add new error codes in librustc_typeck --- src/librustc/infer/mod.rs | 19 ++++++++++++++----- src/librustc_typeck/check/mod.rs | 12 +++++++----- src/librustc_typeck/diagnostics.rs | 2 ++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fd65e06ea972c..1df06e8a00736 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1510,6 +1510,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.type_error_struct(sp, mk_msg, actual_ty).emit(); } + // FIXME: this results in errors without an error code. Deprecate? pub fn type_error_struct(&self, sp: Span, mk_msg: M, @@ -1517,19 +1518,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, { - debug!("type_error_struct({:?}, {:?})", sp, actual_ty); + self.type_error_struct_with_diag(sp, |actual_ty| { + self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty)) + }, actual_ty) + } + pub fn type_error_struct_with_diag(&self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>) + -> DiagnosticBuilder<'tcx> + where M: FnOnce(String) -> DiagnosticBuilder<'tcx>, + { let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); + debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); // Don't report an error if actual type is TyError. if actual_ty.references_error() { return self.tcx.sess.diagnostic().struct_dummy(); } - let msg = mk_msg(self.ty_to_string(actual_ty)); - - // FIXME: use an error code. - self.tcx.sess.struct_span_err(sp, &msg) + mk_diag(self.ty_to_string(actual_ty)) } pub fn report_mismatched_types(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c01edc568afd0..6062bd048b3d2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3028,14 +3028,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { variant: ty::VariantDef<'tcx>, field: &hir::Field, skip_fields: &[hir::Field]) { - let mut err = self.type_error_struct( + let mut err = self.type_error_struct_with_diag( field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { - format!("struct variant `{}::{}` has no field named `{}`", - actual, variant.name.as_str(), field.name.node) + struct_span_err!(self.tcx.sess, field.name.span, E0559, + "struct variant `{}::{}` has no field named `{}`", + actual, variant.name.as_str(), field.name.node) } else { - format!("structure `{}` has no field named `{}`", - actual, field.name.node) + struct_span_err!(self.tcx.sess, field.name.span, E0560, + "structure `{}` has no field named `{}`", + actual, field.name.node) }, ty); // prevent all specified fields from being suggested diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 38bf869119c6a..6000ea71bff8e 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4053,4 +4053,6 @@ register_diagnostics! { E0528, // expected at least {} elements, found {} E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant + E0559, + E0560, } From 0304850942d40c798750c4a1ba194c3992dbde1a Mon Sep 17 00:00:00 2001 From: ggomez Date: Thu, 21 Jul 2016 16:18:12 +0200 Subject: [PATCH 076/150] Add E0560 error explanation --- src/librustc_typeck/diagnostics.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6000ea71bff8e..e7efed905ad7b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3980,6 +3980,32 @@ impl SpaceLlama for i32 { ``` "##, +E0560: r##" +An unknown field was specified into a structure. + +Erroneous code example: + +```compile_fail,E0560 +struct Simba { + mother: u32, +} + +let s = Simba { mother: 1, father: 0 }; +// error: structure `Simba` has no field named `father` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +struct Simba { + mother: u32, + father: u32, +} + +let s = Simba { mother: 1, father: 0 }; // ok! +``` +"##, + } register_diagnostics! { @@ -4054,5 +4080,4 @@ register_diagnostics! { E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant E0559, - E0560, } From 23bb1df1e52dd17062cd135b5be70ba55d5af147 Mon Sep 17 00:00:00 2001 From: ggomez Date: Thu, 21 Jul 2016 16:47:05 +0200 Subject: [PATCH 077/150] Add E0559 error explanation --- src/librustc_typeck/diagnostics.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e7efed905ad7b..500f624ea3f72 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3980,6 +3980,31 @@ impl SpaceLlama for i32 { ``` "##, +E0559: r##" +An unknown field was specified into an enum's structure variant. + +Erroneous code example: + +```compile_fail,E0559 +enum Field { + Fool { x: u32 }, +} + +let s = Field::Fool { joke: 0 }; +// error: struct variant `Field::Fool` has no field named `joke` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +enum Field { + Fool { joke: u32 }, +} + +let s = Field::Fool { joke: 0 }; // ok! +``` +"##, + E0560: r##" An unknown field was specified into a structure. @@ -4079,5 +4104,4 @@ register_diagnostics! { E0528, // expected at least {} elements, found {} E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant - E0559, } From 64d36ccf96c8562a88f5fba75618a9c74fa06daf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 21 Jul 2016 23:03:13 +0000 Subject: [PATCH 078/150] Add regression test. --- src/test/run-pass/issue-34932.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/issue-34932.rs diff --git a/src/test/run-pass/issue-34932.rs b/src/test/run-pass/issue-34932.rs new file mode 100644 index 0000000000000..e83939e7aec6b --- /dev/null +++ b/src/test/run-pass/issue-34932.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. + +// compile-flags:--test +// rustc-env:RUSTC_BOOTSTRAP_KEY= +// ignore-pretty : (#23623) problems when ending with // comments + +#![cfg(any())] // This test should be configured away +#![feature(rustc_attrs)] // Test that this is allowed on stable/beta +#![feature(iter_arith_traits)] // Test that this is not unused +#![deny(unused_features)] + +#[test] +fn dummy() { + let () = "this should not reach type-checking"; +} From 717e39294f635d90f8ba9e0968494f741878f37b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Jul 2016 23:52:53 +0300 Subject: [PATCH 079/150] address review comments I split the RFC1592 commit out --- src/librustc/infer/mod.rs | 18 +++----- src/librustc_const_eval/eval.rs | 28 +----------- src/librustc_typeck/check/demand.rs | 9 +++- src/librustc_typeck/check/wfcheck.rs | 44 +++++++++++++------ .../compile-fail/const-eval-overflow-4b.rs | 4 +- src/test/compile-fail/discrim-ill-typed.rs | 16 +++---- .../explicit-self-lifetime-mismatch.rs | 8 ++-- src/test/compile-fail/issue-17740.rs | 4 +- src/test/compile-fail/issue-26194.rs | 2 +- src/test/compile-fail/issue-8761.rs | 6 +-- src/test/compile-fail/repeat_count.rs | 6 +-- .../compile-fail/ufcs-explicit-self-bad.rs | 14 +++--- 12 files changed, 74 insertions(+), 85 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1df06e8a00736..87882c5528ec1 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -196,12 +196,6 @@ pub enum TypeOrigin { // FIXME(eddyb) #11161 is the original Expr required? ExprAssignable(Span), - // Relating trait refs when resolving vtables - RelateTraitRefs(Span), - - // Relating self types when resolving vtables - RelateSelfType(Span), - // Relating trait type parameters to those found in impl etc RelateOutputImplTypes(Span), @@ -228,16 +222,17 @@ pub enum TypeOrigin { // intrinsic has wrong type IntrinsicType(Span), + + // method receiver + MethodReceiver(Span), } impl TypeOrigin { fn as_failure_str(&self) -> &'static str { match self { &TypeOrigin::Misc(_) | - &TypeOrigin::RelateSelfType(_) | &TypeOrigin::RelateOutputImplTypes(_) | &TypeOrigin::ExprAssignable(_) => "mismatched types", - &TypeOrigin::RelateTraitRefs(_) => "mismatched traits", &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", &TypeOrigin::MatchExpressionArm(_, _, source) => match source { hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", @@ -250,6 +245,7 @@ impl TypeOrigin { &TypeOrigin::MainFunctionType(_) => "main function has wrong type", &TypeOrigin::StartFunctionType(_) => "start function has wrong type", &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", + &TypeOrigin::MethodReceiver(_) => "mismatched method receiver", } } @@ -258,8 +254,6 @@ impl TypeOrigin { &TypeOrigin::Misc(_) => "types are compatible", &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", &TypeOrigin::ExprAssignable(_) => "expression is assignable", - &TypeOrigin::RelateTraitRefs(_) => "traits are compatible", - &TypeOrigin::RelateSelfType(_) => "self type matches impl self type", &TypeOrigin::RelateOutputImplTypes(_) => { "trait type parameters matches those specified on the impl" } @@ -271,6 +265,7 @@ impl TypeOrigin { &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", + &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type", } } } @@ -1806,8 +1801,6 @@ impl TypeOrigin { TypeOrigin::MethodCompatCheck(span) => span, TypeOrigin::ExprAssignable(span) => span, TypeOrigin::Misc(span) => span, - TypeOrigin::RelateTraitRefs(span) => span, - TypeOrigin::RelateSelfType(span) => span, TypeOrigin::RelateOutputImplTypes(span) => span, TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span, TypeOrigin::IfExpression(span) => span, @@ -1817,6 +1810,7 @@ impl TypeOrigin { TypeOrigin::MainFunctionType(span) => span, TypeOrigin::StartFunctionType(span) => span, TypeOrigin::IntrinsicType(span) => span, + TypeOrigin::MethodReceiver(span) => span, } } } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 03d2f596e2165..2eb08cab1aa9f 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -384,15 +384,6 @@ pub fn note_const_eval_err<'a, 'tcx>( diag.span_label(err.span, &message); } } - ConstEvalErrDescription::ExpectedFound { error, expected, found } => { - if check_old_school() { - diag.note(&error); - } else { - diag.span_label(err.span, &error); - } - diag.note(&format!("expected `{}`", expected)); - diag.note(&format!("found `{}`", found)); - } } if !primary_span.contains(err.span) { @@ -477,11 +468,6 @@ impl From for ErrKind { #[derive(Clone, Debug)] pub enum ConstEvalErrDescription<'a> { Simple(Cow<'a, str>), - ExpectedFound { - error: Cow<'a, str>, - expected: Cow<'a, str>, - found: Cow<'a, str> - } } impl<'a> ConstEvalErrDescription<'a> { @@ -489,14 +475,6 @@ impl<'a> ConstEvalErrDescription<'a> { pub fn into_oneline(self) -> Cow<'a, str> { match self { ConstEvalErrDescription::Simple(simple) => simple, - ConstEvalErrDescription::ExpectedFound { - error, - expected, - found - } => { - format!("{}: expected `{}`, found `{}`", error, expected, found) - .into_cow() - } } } } @@ -554,11 +532,7 @@ impl ConstEvalErr { the constant evaluator"), TypeMismatch(ref expected, ref got) => { - ExpectedFound { - error: "mismatched types".into_cow(), - expected: <&str>::into_cow(expected), - found: got.description().into_cow() - } + simple!("expected {}, found {}", expected, got.description()) }, BadType(ref i) => simple!("value of wrong type: {:?}", i), ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c1f415b3c028a..1f3a83ebc1d56 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -33,7 +33,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); + self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual); + } + + pub fn demand_eqtype_with_origin(&self, + origin: TypeOrigin, + expected: Ty<'tcx>, + actual: Ty<'tcx>) + { match self.eq_types(false, origin, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 2d44a85f9af4b..907cb734c2ff9 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; +use rustc::infer::TypeOrigin; use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -157,7 +158,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) { + fn check_trait_or_impl_item(&mut self, + item_id: ast::NodeId, + span: Span, + sig_if_method: Option<&hir::MethodSig>) { let code = self.code.clone(); self.for_id(item_id, span).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; @@ -182,7 +186,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); this.check_fn_or_method(fcx, span, &method_ty, &predicates, free_id_outlive, &mut implied_bounds); - this.check_method_receiver(fcx, span, &method, + let sig_if_method = sig_if_method.expect("bad signature for method"); + this.check_method_receiver(fcx, sig_if_method, &method, free_id_outlive, self_ty); } ty::TypeTraitItem(assoc_type) => { @@ -405,20 +410,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, + method_sig: &hir::MethodSig, method: &ty::Method<'tcx>, free_id_outlive: CodeExtent, self_ty: ty::Ty<'tcx>) { // check that the type of the method's receiver matches the // method's first parameter. - - let free_substs = &fcx.parameter_environment.free_substs; - let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); - - debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})", - method.name, method.explicit_self, self_ty, sig); + debug!("check_method_receiver({:?},cat={:?},self_ty={:?})", + method.name, method.explicit_self, self_ty); let rcvr_ty = match method.explicit_self { ty::ExplicitSelfCategory::Static => return, @@ -431,13 +431,23 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty) }; + + let span = method_sig.decl.inputs[0].pat.span; + + let free_substs = &fcx.parameter_environment.free_substs; + let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); + let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); + + debug!("check_method_receiver: sig={:?}", sig); + let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(rcvr_ty)); debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - fcx.demand_eqtype(span, rcvr_ty, sig.inputs[0]); + let origin = TypeOrigin::MethodReceiver(span); + fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]); } fn check_variances_for_type_defn(&self, @@ -552,13 +562,21 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) { debug!("visit_trait_item: {:?}", trait_item); - self.check_trait_or_impl_item(trait_item.id, trait_item.span); + let method_sig = match trait_item.node { + hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig), + _ => None + }; + self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig); intravisit::walk_trait_item(self, trait_item) } fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) { debug!("visit_impl_item: {:?}", impl_item); - self.check_trait_or_impl_item(impl_item.id, impl_item.span); + let method_sig = match impl_item.node { + hir::ImplItemKind::Method(ref sig, _) => Some(sig), + _ => None + }; + self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig); intravisit::walk_impl_item(self, impl_item) } } diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index e7639a4ff70ab..9e7a5ecae105a 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -21,9 +21,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] //~^ ERROR constant evaluation error [E0080] - //~| mismatched types - //~| expected `i8` - //~| found `u8` + //~| expected i8, found u8 = [0; (i8::MAX as usize) + 1]; diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index 5af889cb23999..c73b7e831b321 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -26,7 +26,7 @@ fn f_i8() { Ok2, OhNo = 0_u8, //~^ ERROR E0080 - //~| mismatched types + //~| expected i8, found u8 } let x = A::Ok; @@ -39,7 +39,7 @@ fn f_u8() { Ok2, OhNo = 0_i8, //~^ ERROR E0080 - //~| mismatched types + //~| expected u8, found i8 } let x = A::Ok; @@ -52,7 +52,7 @@ fn f_i16() { Ok2, OhNo = 0_u16, //~^ ERROR E0080 - //~| mismatched types + //~| expected i16, found u16 } let x = A::Ok; @@ -65,7 +65,7 @@ fn f_u16() { Ok2, OhNo = 0_i16, //~^ ERROR E0080 - //~| mismatched types + //~| expected u16, found i16 } let x = A::Ok; @@ -78,7 +78,7 @@ fn f_i32() { Ok2, OhNo = 0_u32, //~^ ERROR E0080 - //~| mismatched types + //~| expected i32, found u32 } let x = A::Ok; @@ -91,7 +91,7 @@ fn f_u32() { Ok2, OhNo = 0_i32, //~^ ERROR E0080 - //~| mismatched types + //~| expected u32, found i32 } let x = A::Ok; @@ -104,7 +104,7 @@ fn f_i64() { Ok2, OhNo = 0_u64, //~^ ERROR E0080 - //~| mismatched types + //~| expected i64, found u64 } let x = A::Ok; @@ -117,7 +117,7 @@ fn f_u64() { Ok2, OhNo = 0_i64, //~^ ERROR E0080 - //~| mismatched types + //~| expected u64, found i64 } let x = A::Ok; diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index b5432fafb1b85..f8aa1ea95f0f6 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -14,15 +14,17 @@ struct Foo<'a,'b> { } impl<'a,'b> Foo<'a,'b> { - fn bar(self: Foo<'b,'a>) {} - //~^ ERROR mismatched types + fn bar( + self + //~^ ERROR mismatched method receiver //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch - //~| ERROR mismatched types + //~| ERROR mismatched method receiver //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch + : Foo<'b,'a>) {} } fn main() {} diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 6b9294b2038f1..664d62e87ae61 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -14,11 +14,11 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { - //~^ mismatched types + //~^ mismatched method receiver //~| expected type `&mut Foo<'a>` //~| found type `&mut Foo<'_>` //~| lifetime mismatch - //~| mismatched types + //~| mismatched method receiver //~| expected type `&mut Foo<'a>` //~| found type `&mut Foo<'_>` //~| lifetime mismatch diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index 1bc0a4f965219..ef91188c5d166 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -12,7 +12,7 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } - //~^ ERROR mismatched types + //~^ ERROR mismatched method receiver } fn main() { S("".to_owned()).f(); } diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 6352f4f6a0447..91a07dd9ba6dd 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -11,12 +11,10 @@ enum Foo { A = 1i64, //~^ ERROR constant evaluation error - //~| expected `isize` - //~| found `i64` + //~| expected isize, found i64 B = 2u8 //~^ ERROR constant evaluation error - //~| expected `isize` - //~| found `u8` + //~| expected isize, found u8 } fn main() {} diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index d68df97364169..3a7e9cc4191ec 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -39,14 +39,12 @@ fn main() { //~| ERROR expected usize for repeat count, found string literal [E0306] let f = [0; -4_isize]; //~^ ERROR constant evaluation error - //~| expected `usize` - //~| found `isize` + //~| expected usize, found isize //~| ERROR mismatched types //~| expected usize, found isize let f = [0_usize; -1_isize]; //~^ ERROR constant evaluation error - //~| expected `usize` - //~| found `isize` + //~| expected usize, found isize //~| ERROR mismatched types //~| expected usize, found isize struct G { diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index e997cf47c7333..a98b7cd43090f 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -15,7 +15,7 @@ struct Foo { } impl Foo { - fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched types + fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched method receiver self.f + x } } @@ -25,10 +25,10 @@ struct Bar { } impl Bar { - fn foo(self: Bar, x: isize) -> isize { //~ ERROR mismatched types + fn foo(self: Bar, x: isize) -> isize { //~ ERROR mismatched method receiver x } - fn bar(self: &Bar, x: isize) -> isize { //~ ERROR mismatched types + fn bar(self: &Bar, x: isize) -> isize { //~ ERROR mismatched method receiver x } } @@ -41,14 +41,14 @@ trait SomeTrait { impl<'a, T> SomeTrait for &'a Bar { fn dummy1(self: &&'a Bar) { } - fn dummy2(self: &Bar) {} //~ ERROR mismatched types - //~^ ERROR mismatched types + fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver + //~^ ERROR mismatched method receiver fn dummy3(self: &&Bar) {} - //~^ ERROR mismatched types + //~^ ERROR mismatched method receiver //~| expected type `&&'a Bar` //~| found type `&&Bar` //~| lifetime mismatch - //~| ERROR mismatched types + //~| ERROR mismatched method receiver //~| expected type `&&'a Bar` //~| found type `&&Bar` //~| lifetime mismatch From 051c2d14fb1e73866376668088971605d38f0c65 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 22 Jul 2016 14:57:54 -0700 Subject: [PATCH 080/150] Implement rust_eh_personality in Rust, remove rust_eh_personality_catch. Well, not quite: ARM EHABI platforms still use the old scheme -- for now. --- src/libpanic_unwind/dwarf/eh.rs | 107 +++++++++++++------- src/libpanic_unwind/gcc.rs | 165 ++++++++++++++----------------- src/libpanic_unwind/lib.rs | 1 + src/libpanic_unwind/seh64_gnu.rs | 19 ++-- src/librustc_trans/intrinsic.rs | 14 ++- src/libunwind/libunwind.rs | 8 ++ 6 files changed, 176 insertions(+), 138 deletions(-) diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 0ad6a74d1013c..32fdf5c204801 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -45,16 +45,25 @@ pub const DW_EH_PE_aligned: u8 = 0x50; pub const DW_EH_PE_indirect: u8 = 0x80; #[derive(Copy, Clone)] -pub struct EHContext { +pub struct EHContext<'a> { pub ip: usize, // Current instruction pointer pub func_start: usize, // Address of the current function - pub text_start: usize, // Address of the code section - pub data_start: usize, // Address of the data section + pub get_text_start: &'a Fn() -> usize, // Get address of the code section + pub get_data_start: &'a Fn() -> usize, // Get address of the data section } -pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option { +pub enum EHAction { + None, + Cleanup(usize), + Catch(usize), + Terminate, +} + +pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); + +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { if lsda.is_null() { - return None; + return EHAction::None; } let func_start = context.func_start; @@ -77,32 +86,62 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option(); let call_site_table_length = reader.read_uleb128(); let action_table = reader.ptr.offset(call_site_table_length as isize); - // Return addresses point 1 byte past the call instruction, which could - // be in the next IP range. - let ip = context.ip - 1; - - while reader.ptr < action_table { - let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_action = reader.read_uleb128(); - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - if ip < func_start + cs_start { - break; + let ip = context.ip; + + if !USING_SJLJ_EXCEPTIONS { + while reader.ptr < action_table { + let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_action = reader.read_uleb128(); + // Callsite table is sorted by cs_start, so if we've passed the ip, we + // may stop searching. + if ip < func_start + cs_start { + break; + } + if ip < func_start + cs_start + cs_len { + if cs_lpad == 0 { + return EHAction::None; + } else { + let lpad = lpad_base + cs_lpad; + return interpret_cs_action(cs_action, lpad); + } + } } - if ip < func_start + cs_start + cs_len { - if cs_lpad != 0 { - return Some(lpad_base + cs_lpad); - } else { - return None; + // If ip is not present in the table, call terminate. This is for + // a destructor inside a cleanup, or a library routine the compiler + // was not expecting to throw + EHAction::Terminate + } else { + // SjLj version: + // The "IP" is an index into the call-site table, with two exceptions: + // -1 means 'no-action', and 0 means 'terminate'. + match ip as isize { + -1 => return EHAction::None, + 0 => return EHAction::Terminate, + _ => (), + } + let mut idx = ip; + loop { + let cs_lpad = reader.read_uleb128(); + let cs_action = reader.read_uleb128(); + idx -= 1; + if idx == 0 { + // Can never have null landing pad for sjlj -- that would have + // been indicated by a -1 call site index. + let lpad = (cs_lpad + 1) as usize; + return interpret_cs_action(cs_action, lpad); } } } - // IP range not found: gcc's C++ personality calls terminate() here, - // however the rest of the languages treat this the same as cs_lpad == 0. - // We follow this suit. - None +} + +fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { + if cs_action == 0 { + EHAction::Cleanup(lpad) + } else { + EHAction::Catch(lpad) + } } #[inline] @@ -140,18 +179,16 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader, DW_EH_PE_absptr => 0, // relative to address of the encoded value, despite the name DW_EH_PE_pcrel => reader.ptr as usize, - DW_EH_PE_textrel => { - assert!(context.text_start != 0); - context.text_start - } - DW_EH_PE_datarel => { - assert!(context.data_start != 0); - context.data_start - } DW_EH_PE_funcrel => { assert!(context.func_start != 0); context.func_start } + DW_EH_PE_textrel => { + (*context.get_text_start)() + } + DW_EH_PE_datarel => { + (*context.get_data_start)() + } _ => panic!(), }; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 3c46072e17e1a..cdf772ad3b825 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -106,117 +106,96 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { 0x4d4f5a_00_52555354 } -// We could implement our personality routine in Rust, however exception -// info decoding is tedious. More importantly, personality routines have to -// handle various platform quirks, which are not fun to maintain. For this -// reason, we attempt to reuse personality routine of the C language: -// __gcc_personality_v0. -// -// Since C does not support exception catching, __gcc_personality_v0 simply -// always returns _URC_CONTINUE_UNWIND in search phase, and always returns -// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase. -// -// This is pretty close to Rust's exception handling approach, except that Rust -// does have a single "catch-all" handler at the bottom of each thread's stack. -// So we have two versions of the personality routine: -// - rust_eh_personality, used by all cleanup landing pads, which never catches, -// so the behavior of __gcc_personality_v0 is perfectly adequate there, and -// - rust_eh_personality_catch, used only by rust_try(), which always catches. -// -// See also: rustc_trans::trans::intrinsic::trans_gnu_try - -#[cfg(all(not(target_arch = "arm"), - not(all(windows, target_arch = "x86_64"))))] +// All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses +// SjLj unwinding). Also, 64-bit Windows implementation lives in seh64_gnu.rs +#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] pub mod eabi { use unwind as uw; - use libc::c_int; + use libc::{c_int, uintptr_t}; + use dwarf::eh::{EHContext, EHAction, find_eh_action}; - extern "C" { - fn __gcc_personality_v0(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; - } + // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() + // and TargetLowering::getExceptionSelectorRegister() for each architecture, + // then mapped to DWARF register numbers via register definition tables + // (typically RegisterInfo.td, search for "DwarfRegNum"). + // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. - #[lang = "eh_personality"] - #[no_mangle] - extern "C" fn rust_eh_personality(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) } - } + #[cfg(target_arch = "x86")] + const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX - #[lang = "eh_personality_catch"] - #[no_mangle] - pub extern "C" fn rust_eh_personality_catch(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { + #[cfg(target_arch = "x86_64")] + const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX - if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { - // search phase - uw::_URC_HANDLER_FOUND // catch! - } else { - // cleanup phase - unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) } - } - } -} - -// iOS on armv7 is using SjLj exceptions and therefore requires to use -// a specialized personality routine: __gcc_personality_sj0 + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 -#[cfg(all(target_os = "ios", target_arch = "arm"))] -pub mod eabi { - use unwind as uw; - use libc::c_int; + #[cfg(any(target_arch = "mips", target_arch = "mipsel"))] + const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 - extern "C" { - fn __gcc_personality_sj0(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; - } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 + // Based on GCC's C and C++ personality routines. For reference, see: + // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc + // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c #[lang = "eh_personality"] #[no_mangle] - pub extern "C" fn rust_eh_personality(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) } + #[allow(unused)] + unsafe extern "C" fn rust_eh_personality(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + if version != 1 { + return uw::_URC_FATAL_PHASE1_ERROR; + } + let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; + let mut ip_before_instr: c_int = 0; + let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); + let eh_context = EHContext { + // The return address points 1 byte past the call instruction, + // which could be in the next IP range in LSDA range table. + ip: if ip_before_instr != 0 { ip } else { ip - 1 }, + func_start: uw::_Unwind_GetRegionStart(context), + get_text_start: &|| uw::_Unwind_GetTextRelBase(context), + get_data_start: &|| uw::_Unwind_GetDataRelBase(context), + }; + let eh_action = find_eh_action(lsda, &eh_context); + + if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { + match eh_action { + EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, + EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, + EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, + } + } else { + match eh_action { + EHAction::None => return uw::_URC_CONTINUE_UNWIND, + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); + uw::_Unwind_SetIP(context, lpad); + return uw::_URC_INSTALL_CONTEXT; + } + EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR, + } + } } + #[cfg(stage0)] #[lang = "eh_personality_catch"] #[no_mangle] - pub extern "C" fn rust_eh_personality_catch(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { - // search phase - uw::_URC_HANDLER_FOUND // catch! - } else { - // cleanup phase - unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) } - } + pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + rust_eh_personality(version, actions, exception_class, ue_header, context) } } - // ARM EHABI uses a slightly different personality routine signature, // but otherwise works the same. #[cfg(all(target_arch = "arm", not(target_os = "ios")))] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index b765ee6f81cf9..11dd9befe0a82 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -101,6 +101,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] +#[unwind] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 56801e8cb6bcf..7dc428871b387 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -19,7 +19,7 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; use core::ptr; -use dwarf::eh; +use dwarf::eh::{EHContext, EHAction, find_eh_action}; use windows as c; // Define our exception codes: @@ -81,6 +81,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { // This is considered acceptable, because the behavior of throwing exceptions // through a C ABI boundary is undefined. +#[cfg(stage0)] #[lang = "eh_personality_catch"] #[cfg(not(test))] unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD, @@ -132,11 +133,17 @@ unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { } unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option { - let eh_ctx = eh::EHContext { - ip: dc.ControlPc as usize, + let eh_ctx = EHContext { + // The return address points 1 byte past the call instruction, + // which could be in the next IP range in LSDA range table. + ip: dc.ControlPc as usize - 1, func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize, - text_start: dc.ImageBase as usize, - data_start: 0, + get_text_start: &|| dc.ImageBase as usize, + get_data_start: &|| unimplemented!(), }; - eh::find_landing_pad(dc.HandlerData, &eh_ctx) + match find_eh_action(dc.HandlerData, &eh_ctx) { + EHAction::None => None, + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad), + EHAction::Terminate => intrinsics::abort(), + } } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index a721361fce0e3..f033b278fe7f0 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1193,11 +1193,17 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // managed by the standard library. attributes::emit_uwtable(bcx.fcx.llfn, true); - let catch_pers = match tcx.lang_items.eh_personality_catch() { - Some(did) => { - Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val + let target = &bcx.sess().target.target; + let catch_pers = if target.arch == "arm" && target.target_os != "ios" { + // Only ARM still uses a separate catch personality (for now) + match tcx.lang_items.eh_personality_catch() { + Some(did) => { + Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val + } + None => bug!("eh_personality_catch not defined"), } - None => bug!("eh_personality_catch not defined"), + } else { + bcx.fcx.eh_personality() }; let then = bcx.fcx.new_temp_block("then"); diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index aadfe202afe79..d9b6c9ed74dd2 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -58,6 +58,7 @@ pub enum _Unwind_Reason_Code { pub type _Unwind_Exception_Class = u64; pub type _Unwind_Word = libc::uintptr_t; +pub type _Unwind_Ptr = libc::uintptr_t; pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void) -> _Unwind_Reason_Code; @@ -156,6 +157,13 @@ extern "C" { ip_before_insn: *mut libc::c_int) -> libc::uintptr_t; + pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; + pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; + pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; + pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; + pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr); + pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr); + #[cfg(all(not(target_os = "android"), not(all(target_os = "linux", target_arch = "arm"))))] pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void; From e7d16580f5856ecb0c515c7cdcabd2c10ba91547 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sun, 26 Jun 2016 15:11:48 +0200 Subject: [PATCH 081/150] Escape fewer Unicode codepoints in `Debug` impl of `str` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the same procedure as Python to determine whether a character is printable, described in [PEP 3138]. In particular, this means that the following character classes are escaped: - Cc (Other, Control) - Cf (Other, Format) - Cs (Other, Surrogate), even though they can't appear in Rust strings - Co (Other, Private Use) - Cn (Other, Not Assigned) - Zl (Separator, Line) - Zp (Separator, Paragraph) - Zs (Separator, Space), except for the ASCII space `' '` (`0x20`) This allows for user-friendly inspection of strings that are not English (e.g. compare `"\u{e9}\u{e8}\u{ea}"` to `"éèê"`). Fixes #34318. [PEP 3138]: https://www.python.org/dev/peps/pep-3138/ --- src/etc/char_private.py | 154 ++++++++ src/libcollectionstest/str.rs | 10 +- src/libcore/char.rs | 5 +- src/libcore/char_private.rs | 695 ++++++++++++++++++++++++++++++++++ src/libcore/lib.rs | 1 + src/libcoretest/char.rs | 16 +- 6 files changed, 872 insertions(+), 9 deletions(-) create mode 100644 src/etc/char_private.py create mode 100644 src/libcore/char_private.rs diff --git a/src/etc/char_private.py b/src/etc/char_private.py new file mode 100644 index 0000000000000..3566d143529be --- /dev/null +++ b/src/etc/char_private.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python +# +# Copyright 2011-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. + +# This script uses the following Unicode tables: +# - Categories.txt + +import os +import subprocess + +def to_ranges(iter): + current = None + for i in iter: + if current is None or i != current[1] or i in (0x10000, 0x20000): + if current is not None: + yield tuple(current) + current = [i, i + 1] + else: + current[1] += 1 + if current is not None: + yield tuple(current) + +def get_escaped(dictionary): + for i in range(0x110000): + if dictionary.get(i, "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and i != ord(' '): + yield i + +def get_file(f): + try: + return open(os.path.basename(f)) + except FileNotFoundError: + subprocess.run(["curl", "-O", f], check=True) + return open(os.path.basename(f)) + +def main(): + file = get_file("http://www.unicode.org/notes/tn36/Categories.txt") + + dictionary = {int(line.split()[0], 16): line.split()[1] for line in file} + + CUTOFF=0x10000 + singletons0 = [] + singletons1 = [] + normal0 = [] + normal1 = [] + extra = [] + + for a, b in to_ranges(get_escaped(dictionary)): + if a > 2 * CUTOFF: + extra.append((a, b - a)) + elif a == b - 1: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + else: + singletons0.append(a) + elif a == b - 2: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + singletons1.append((a + 1) & ~CUTOFF) + else: + singletons0.append(a) + singletons0.append(a + 1) + else: + if a >= 2 * CUTOFF: + extra.append((a, b - a)) + elif a & CUTOFF: + normal1.append((a & ~CUTOFF, b - a)) + else: + normal0.append((a, b - a)) + + print("""\ +// Copyright 2012-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. + +// 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 { + break; + } + } + 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; + } + } else { + break; + } + } + true +} + +pub fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1, NORMAL1) + } else {\ +""") + for a, b in extra: + print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b)) + print(" return false;") + print(" }") + print("""\ + true + } +}\ +""") + 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("];") + +if __name__ == '__main__': + main() diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 07428f3f8b2d8..4d85c9d545e5a 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -707,12 +707,14 @@ fn test_escape_unicode() { fn test_escape_default() { assert_eq!("abc".escape_default(), "abc"); assert_eq!("a c".escape_default(), "a c"); + assert_eq!("éèê".escape_default(), "éèê"); assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); - assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{fb00}".escape_default(), "ab\\u{fb00}"); - assert_eq!("\u{1d4ea}\r".escape_default(), "\\u{1d4ea}\\r"); + assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_default(), "\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); } #[test] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 0e7f04c775825..0d39217bd726c 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -17,6 +17,7 @@ use prelude::v1::*; +use char_private::is_printable; use mem::transmute; // UTF-8 ranges and tags for encoding characters @@ -320,8 +321,8 @@ impl CharExt for char { '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), - _ => EscapeDefaultState::Unicode(self.escape_unicode()) + c if is_printable(c) => EscapeDefaultState::Char(c), + c => EscapeDefaultState::Unicode(c.escape_unicode()), }; EscapeDefault { state: init_state } } diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs new file mode 100644 index 0000000000000..1d8f95cd4b81c --- /dev/null +++ b/src/libcore/char_private.rs @@ -0,0 +1,695 @@ +// Copyright 2012-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. + +// 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 { + break; + } + } + 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; + } + } else { + break; + } + } + true +} + +pub fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1, NORMAL1) + } else { + if 0x20000 <= x && x < 0x2f800 { + return false; + } + if 0x2fa1e <= x && x < 0xe0100 { + return false; + } + if 0xe01f0 <= x && x < 0x110000 { + return false; + } + true + } +} + +const SINGLETONS0: &'static [u16] = &[ + 0xad, + 0x378, + 0x379, + 0x38b, + 0x38d, + 0x3a2, + 0x557, + 0x558, + 0x560, + 0x588, + 0x590, + 0x61c, + 0x61d, + 0x6dd, + 0x70e, + 0x70f, + 0x74b, + 0x74c, + 0x82e, + 0x82f, + 0x83f, + 0x85c, + 0x85d, + 0x8a1, + 0x8ff, + 0x978, + 0x980, + 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, + 0xc34, + 0xc45, + 0xc49, + 0xc57, + 0xc64, + 0xc65, + 0xc80, + 0xc81, + 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, + 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, + 0x1680, + 0x170d, + 0x176d, + 0x1771, + 0x17de, + 0x17df, + 0x180e, + 0x180f, + 0x196e, + 0x196f, + 0x1a1c, + 0x1a1d, + 0x1a5f, + 0x1a7d, + 0x1a7e, + 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, + 0x2700, + 0x2c2f, + 0x2c5f, + 0x2d26, + 0x2d2e, + 0x2d2f, + 0x2da7, + 0x2daf, + 0x2db7, + 0x2dbf, + 0x2dc7, + 0x2dcf, + 0x2dd7, + 0x2ddf, + 0x2e9a, + 0x3040, + 0x3097, + 0x3098, + 0x318f, + 0x321f, + 0x32ff, + 0xa78f, + 0xa9ce, + 0xaa4e, + 0xaa4f, + 0xaa5a, + 0xaa5b, + 0xab07, + 0xab08, + 0xab0f, + 0xab10, + 0xab27, + 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 SINGLETONS1: &'static [u16] = &[ + 0xc, + 0x27, + 0x3b, + 0x3e, + 0x4e, + 0x4f, + 0x31f, + 0x39e, + 0x49e, + 0x49f, + 0x806, + 0x807, + 0x809, + 0x836, + 0x83d, + 0x83e, + 0x856, + 0xa04, + 0xa14, + 0xa18, + 0xb56, + 0xb57, + 0x10bd, + 0x1135, + 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, + 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, + 0xf0bf, + 0xf0c0, + 0xf0d0, + 0xf12f, + 0xf336, + 0xf3c5, + 0xf43f, + 0xf441, + 0xf4f8, + 0xf53e, + 0xf53f, +]; +const NORMAL0: &'static [u16] = &[ + 0x0, 0x20, + 0x7f, 0x22, + 0x37f, 0x5, + 0x528, 0x9, + 0x58b, 0x4, + 0x5c8, 0x8, + 0x5eb, 0x5, + 0x5f5, 0x11, + 0x7b2, 0xe, + 0x7fb, 0x5, + 0x85f, 0x41, + 0x8ad, 0x37, + 0x9b3, 0x3, + 0x9cf, 0x8, + 0x9d8, 0x4, + 0x9fc, 0x5, + 0xa0b, 0x4, + 0xa43, 0x4, + 0xa4e, 0x3, + 0xa52, 0x7, + 0xa5f, 0x7, + 0xa76, 0xb, + 0xad1, 0xf, + 0xaf2, 0xf, + 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, 0x6, + 0xc3a, 0x3, + 0xc4e, 0x7, + 0xc5a, 0x6, + 0xc70, 0x8, + 0xcce, 0x7, + 0xcd7, 0x7, + 0xcf3, 0xf, + 0xd4f, 0x8, + 0xd58, 0x8, + 0xd76, 0x3, + 0xd97, 0x3, + 0xdc7, 0x3, + 0xdcb, 0x4, + 0xde0, 0x12, + 0xdf5, 0xc, + 0xe3b, 0x4, + 0xe5c, 0x25, + 0xe8e, 0x6, + 0xee0, 0x20, + 0xf6d, 0x4, + 0xfdb, 0x25, + 0x10c8, 0x5, + 0x137d, 0x3, + 0x139a, 0x6, + 0x13f5, 0xb, + 0x169d, 0x3, + 0x16f1, 0xf, + 0x1715, 0xb, + 0x1737, 0x9, + 0x1754, 0xc, + 0x1774, 0xc, + 0x17ea, 0x6, + 0x17fa, 0x6, + 0x181a, 0x6, + 0x1878, 0x8, + 0x18ab, 0x5, + 0x18f6, 0xa, + 0x191d, 0x3, + 0x192c, 0x4, + 0x193c, 0x4, + 0x1941, 0x3, + 0x1975, 0xb, + 0x19ac, 0x4, + 0x19ca, 0x6, + 0x19db, 0x3, + 0x1a8a, 0x6, + 0x1a9a, 0x6, + 0x1aae, 0x52, + 0x1b4c, 0x4, + 0x1b7d, 0x3, + 0x1bf4, 0x8, + 0x1c38, 0x3, + 0x1c4a, 0x3, + 0x1c80, 0x40, + 0x1cc8, 0x8, + 0x1cf7, 0x9, + 0x1de7, 0x15, + 0x1fff, 0x11, + 0x2028, 0x8, + 0x205f, 0x11, + 0x209d, 0x3, + 0x20ba, 0x16, + 0x20f1, 0xf, + 0x218a, 0x6, + 0x23f4, 0xc, + 0x2427, 0x19, + 0x244b, 0x15, + 0x2b4d, 0x3, + 0x2b5a, 0xa6, + 0x2cf4, 0x5, + 0x2d28, 0x5, + 0x2d68, 0x7, + 0x2d71, 0xe, + 0x2d97, 0x9, + 0x2e3c, 0x44, + 0x2ef4, 0xc, + 0x2fd6, 0x1a, + 0x2ffc, 0x5, + 0x3100, 0x5, + 0x312e, 0x3, + 0x31bb, 0x5, + 0x31e4, 0xc, + 0x3400, 0x19c0, + 0x4e00, 0x5200, + 0xa48d, 0x3, + 0xa4c7, 0x9, + 0xa62c, 0x14, + 0xa698, 0x7, + 0xa6f8, 0x8, + 0xa794, 0xc, + 0xa7ab, 0x4d, + 0xa82c, 0x4, + 0xa83a, 0x6, + 0xa878, 0x8, + 0xa8c5, 0x9, + 0xa8da, 0x6, + 0xa8fc, 0x4, + 0xa954, 0xb, + 0xa97d, 0x3, + 0xa9da, 0x4, + 0xa9e0, 0x20, + 0xaa37, 0x9, + 0xaa7c, 0x4, + 0xaac3, 0x18, + 0xaaf7, 0xa, + 0xab17, 0x9, + 0xab2f, 0x91, + 0xabfa, 0x2bb6, + 0xd7c7, 0x4, + 0xd7fc, 0x2104, + 0xfada, 0x26, + 0xfb07, 0xc, + 0xfb18, 0x5, + 0xfbc2, 0x11, + 0xfd40, 0x10, + 0xfdc8, 0x28, + 0xfe1a, 0x6, + 0xfe27, 0x9, + 0xfe6c, 0x4, + 0xfefd, 0x4, + 0xffbf, 0x3, + 0xffdd, 0x3, + 0xffef, 0xd, +]; +const NORMAL1: &'static [u16] = &[ + 0x5e, 0x22, + 0xfb, 0x5, + 0x103, 0x4, + 0x134, 0x3, + 0x18b, 0x5, + 0x19c, 0x34, + 0x1fe, 0x82, + 0x29d, 0x3, + 0x2d1, 0x2f, + 0x324, 0xc, + 0x34b, 0x35, + 0x3c4, 0x4, + 0x3d6, 0x2a, + 0x4aa, 0x356, + 0x839, 0x3, + 0x860, 0xa0, + 0x91c, 0x3, + 0x93a, 0x5, + 0x940, 0x40, + 0x9b8, 0x6, + 0x9c0, 0x40, + 0xa07, 0x5, + 0xa34, 0x4, + 0xa3b, 0x4, + 0xa48, 0x8, + 0xa59, 0x7, + 0xa80, 0x80, + 0xb36, 0x3, + 0xb73, 0x5, + 0xb80, 0x80, + 0xc49, 0x217, + 0xe7f, 0x181, + 0x104e, 0x4, + 0x1070, 0x10, + 0x10c2, 0xe, + 0x10e9, 0x7, + 0x10fa, 0x6, + 0x1144, 0x3c, + 0x11c9, 0x7, + 0x11da, 0x4a6, + 0x16b8, 0x8, + 0x16ca, 0x936, + 0x236f, 0x91, + 0x2463, 0xd, + 0x2474, 0xb8c, + 0x342f, 0x33d1, + 0x6a39, 0x4c7, + 0x6f45, 0xb, + 0x6f7f, 0x10, + 0x6fa0, 0x4060, + 0xb002, 0x1ffe, + 0xd0f6, 0xa, + 0xd173, 0x8, + 0xd1de, 0x22, + 0xd246, 0xba, + 0xd357, 0x9, + 0xd372, 0x8e, + 0xd547, 0x3, + 0xd800, 0x1600, + 0xee3c, 0x6, + 0xee43, 0x4, + 0xee9c, 0x5, + 0xeebc, 0x34, + 0xeef2, 0x10e, + 0xf02c, 0x4, + 0xf094, 0xc, + 0xf0e0, 0x20, + 0xf10b, 0x5, + 0xf16c, 0x4, + 0xf19b, 0x4b, + 0xf203, 0xd, + 0xf23b, 0x5, + 0xf249, 0x7, + 0xf252, 0xae, + 0xf321, 0xf, + 0xf37d, 0x3, + 0xf394, 0xc, + 0xf3cb, 0x15, + 0xf3f1, 0xf, + 0xf4fd, 0x3, + 0xf544, 0xc, + 0xf568, 0x93, + 0xf641, 0x4, + 0xf650, 0x30, + 0xf6c6, 0x3a, + 0xf774, 0x88c, +]; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0ad1f671f155b..bf0c3ae987a2d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -161,5 +161,6 @@ pub mod hash; pub mod fmt; // note: does not need to be public +mod char_private; mod iter_private; mod tuple; diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index c8906fed3d2fa..e01f83ed70ab0 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -142,18 +142,28 @@ fn test_escape_default() { assert_eq!(s, "a"); let s = string('~'); assert_eq!(s, "~"); + let s = string('é'); + assert_eq!(s, "é"); let s = string('\x00'); assert_eq!(s, "\\u{0}"); let s = string('\x1f'); assert_eq!(s, "\\u{1f}"); let s = string('\x7f'); assert_eq!(s, "\\u{7f}"); + let s = string('\u{80}'); + assert_eq!(s, "\\u{80}"); let s = string('\u{ff}'); - assert_eq!(s, "\\u{ff}"); + assert_eq!(s, "\u{ff}"); let s = string('\u{11b}'); - assert_eq!(s, "\\u{11b}"); + assert_eq!(s, "\u{11b}"); let s = string('\u{1d4b6}'); - assert_eq!(s, "\\u{1d4b6}"); + assert_eq!(s, "\u{1d4b6}"); + let s = string('\u{200b}'); // zero width space + assert_eq!(s, "\\u{200b}"); + let s = string('\u{e000}'); // private use 1 + assert_eq!(s, "\\u{e000}"); + let s = string('\u{100000}'); // private use 2 + assert_eq!(s, "\\u{100000}"); } #[test] From 34f766e3416ba81663ec4ae5ecc699707e22f759 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sun, 26 Jun 2016 15:23:44 +0200 Subject: [PATCH 082/150] Fix indentation in src/libcore/lib.rs --- src/libcore/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index bf0c3ae987a2d..fabb3900ec648 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,17 +103,17 @@ mod int_macros; #[macro_use] mod uint_macros; -#[path = "num/isize.rs"] pub mod isize; -#[path = "num/i8.rs"] pub mod i8; -#[path = "num/i16.rs"] pub mod i16; -#[path = "num/i32.rs"] pub mod i32; -#[path = "num/i64.rs"] pub mod i64; +#[path = "num/isize.rs"] pub mod isize; +#[path = "num/i8.rs"] pub mod i8; +#[path = "num/i16.rs"] pub mod i16; +#[path = "num/i32.rs"] pub mod i32; +#[path = "num/i64.rs"] pub mod i64; #[path = "num/usize.rs"] pub mod usize; -#[path = "num/u8.rs"] pub mod u8; -#[path = "num/u16.rs"] pub mod u16; -#[path = "num/u32.rs"] pub mod u32; -#[path = "num/u64.rs"] pub mod u64; +#[path = "num/u8.rs"] pub mod u8; +#[path = "num/u16.rs"] pub mod u16; +#[path = "num/u32.rs"] pub mod u32; +#[path = "num/u64.rs"] pub mod u64; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; From 0685900fbd1ea1f6be5c3454dcde753ac3484c01 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 29 Jun 2016 11:35:40 +0200 Subject: [PATCH 083/150] Fix run-pass/ifmt test --- src/test/run-pass/ifmt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index ed56519d23628..8b5536de12e49 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -70,15 +70,15 @@ pub fn main() { t!(format!("{}", '☃'), "☃"); t!(format!("{}", 10), "10"); t!(format!("{}", 10_usize), "10"); - t!(format!("{:?}", '☃'), "'\\u{2603}'"); + t!(format!("{:?}", '☃'), "'☃'"); t!(format!("{:?}", 10), "10"); t!(format!("{:?}", 10_usize), "10"); t!(format!("{:?}", "true"), "\"true\""); t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); - t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"), - r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#); + t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), + r#""foo\u{0}bar\u{1}baz\u{7f}qux""#); t!(format!("{:o}", 10_usize), "12"); t!(format!("{:x}", 10_usize), "a"); t!(format!("{:X}", 10_usize), "A"); From 84876662417aab8f90d685cf6bdd9471f2353022 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Jul 2016 16:21:51 -0700 Subject: [PATCH 084/150] std: Ignore tests where threads outlive main Long ago we discovered that threads which outlive main and then exit while the rest of the program is exiting causes Windows to hang (#20704). That's what was happening in this test so let's just not run this test any more. --- src/liballoc/arc.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index e762e4d8ce9a2..64b780413f884 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -21,6 +21,10 @@ //! //! Sharing some immutable data between threads: //! +// Note that we **do not** run these tests here. The windows builders get super +// unhappy of a thread outlives the main thread and then exits at the same time +// (something deadlocks) so we just avoid this entirely by not running these +// tests. //! ```no_run //! use std::sync::Arc; //! use std::thread; @@ -97,7 +101,8 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// by putting it inside `Mutex` and then share `Mutex` immutably /// with `Arc` as shown below. /// -/// ``` +// See comment at the top of this file for why the test is no_run +/// ```no_run /// use std::sync::{Arc, Mutex}; /// use std::thread; /// From 90bb8d469c495f48cf0da67c7811fd887a8b0655 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 23 Jul 2016 01:57:21 +0200 Subject: [PATCH 085/150] Add DirBuilder doc examples --- src/libstd/fs.rs | 19 ++++++++++++++++++- src/libstd/sys/unix/ext/fs.rs | 10 ++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692ad..c74e508a69b30 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1397,6 +1397,14 @@ pub fn set_permissions>(path: P, perm: Permissions) impl DirBuilder { /// Creates a new set of options with default mode/security settings for all /// platforms and also non-recursive. + /// + /// # Examples + /// + /// ``` + /// use std::fs::DirBuilder; + /// + /// let builder = DirBuilder::new(); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn new() -> DirBuilder { DirBuilder { @@ -1409,7 +1417,16 @@ impl DirBuilder { /// all parent directories if they do not exist with the same security and /// permissions settings. /// - /// This option defaults to `false` + /// This option defaults to `false`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::DirBuilder; + /// + /// let mut builder = DirBuilder::new(); + /// builder.recursive(true); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn recursive(&mut self, recursive: bool) -> &mut Self { self.recursive = recursive; diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index bb90a977433e0..d1f26fec249a9 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -239,6 +239,16 @@ pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. + /// + /// # Examples + /// + /// ```ignore + /// use std::fs::DirBuilder; + /// use std::os::unix::fs::DirBuilderExt; + /// + /// let mut builder = DirBuilder::new(); + /// builder.mode(0o755); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] fn mode(&mut self, mode: u32) -> &mut Self; } From 6ebe6e8f8041a7a7058cbc1ec481751de45fb5ef Mon Sep 17 00:00:00 2001 From: abhi Date: Sat, 23 Jul 2016 13:15:09 +0530 Subject: [PATCH 086/150] Update underscore usage (#34903) --- src/doc/book/syntax-index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 3e889f51f542d..0259db221b6bc 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -94,7 +94,7 @@ * `|` (`|…| expr`): closures. See [Closures]. * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. -* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)]. +* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). ## Other Syntax @@ -231,6 +231,7 @@ [Primitive Types (Tuples)]: primitive-types.html#tuples [Raw Pointers]: raw-pointers.html [Reference (Byte String Literals)]: ../reference.html#byte-string-literals +[Reference (Integer literals)]: ../reference.html#integer-literals [Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals [Reference (Raw String Literals)]: ../reference.html#raw-string-literals [References and Borrowing]: references-and-borrowing.html From 1e0043eb6c445fb96981b6d46dae4c93af4fbda3 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 22 Jul 2016 21:43:59 -0400 Subject: [PATCH 087/150] Fix incorrect 'memory leak' example for `Vec::set_len`. Example was written in https://github.com/rust-lang/rust/pull/34911 Issue was brought up in this comment: https://github.com/rust-lang/rust/commit/a005b2cd2ac679da7393e537aa05e2b7d32d36d5#commitcomment-18346958 --- src/libcollections/vec.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 2d77b38879b8e..967baccd2740a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -593,11 +593,12 @@ impl Vec { /// ``` /// /// In this example, there is a memory leak since the memory locations - /// owned by the vector were not freed prior to the `set_len` call: + /// owned by the inner vectors were not freed prior to the `set_len` call: /// /// ``` - /// let mut vec = vec!['r', 'u', 's', 't']; - /// + /// let mut vec = vec![vec![1, 0, 0], + /// vec![0, 1, 0], + /// vec![0, 0, 1]]; /// unsafe { /// vec.set_len(0); /// } From c77f8ce7c3284441a00faed6782d08eb5a78296c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 22 Jul 2016 20:23:25 -0400 Subject: [PATCH 088/150] Doc example improvements for `slice::windows`. * Modify existing example to not rely on printing to see results * Add an example demonstrating when slice is shorter than `size` --- src/libcollections/slice.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 2c54dc13c8d0b..1f8eea56fc69c 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -544,14 +544,21 @@ impl [T] { /// /// # Example /// - /// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`, - /// `[3,4]`): + /// ``` + /// let slice = ['r', 'u', 's', 't']; + /// let mut iter = slice.windows(2); + /// assert_eq!(iter.next().unwrap(), &['r', 'u']); + /// assert_eq!(iter.next().unwrap(), &['u', 's']); + /// assert_eq!(iter.next().unwrap(), &['s', 't']); + /// assert!(iter.next().is_none()); + /// ``` /// - /// ```rust - /// let v = &[1, 2, 3, 4]; - /// for win in v.windows(2) { - /// println!("{:?}", win); - /// } + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] From 41745f30f751364bdce14428b7d3ffa5dd028903 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 17 Jul 2016 17:22:25 +0000 Subject: [PATCH 089/150] macros: Improve `tt` fragments --- src/libsyntax/ext/tt/transcribe.rs | 16 +++++++++++++--- src/libsyntax/tokenstream.rs | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 7c0d10669f30e..29a300b172e75 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -14,7 +14,7 @@ use syntax_pos::{Span, DUMMY_SP}; use errors::{Handler, DiagnosticBuilder}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use parse::token::{DocComment, MatchNt, SubstNt}; -use parse::token::{Token, NtIdent, SpecialMacroVar}; +use parse::token::{Token, Interpolated, NtIdent, NtTT, SpecialMacroVar}; use parse::token; use parse::lexer::TokenAndSpan; use tokenstream::{self, TokenTree}; @@ -278,9 +278,9 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } // FIXME #2887: think about span stuff here TokenTree::Token(sp, SubstNt(ident)) => { - r.stack.last_mut().unwrap().idx += 1; match lookup_cur_matched(r, ident) { None => { + r.stack.last_mut().unwrap().idx += 1; r.cur_span = sp; r.cur_tok = SubstNt(ident); return ret_val; @@ -292,14 +292,24 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { // (a) idents can be in lots of places, so it'd be a pain // (b) we actually can, since it's a token. MatchedNonterminal(NtIdent(ref sn)) => { + r.stack.last_mut().unwrap().idx += 1; r.cur_span = sn.span; r.cur_tok = token::Ident(sn.node); return ret_val; } + MatchedNonterminal(NtTT(ref tt)) => { + r.stack.push(TtFrame { + forest: TokenTree::Token(sp, Interpolated(NtTT(tt.clone()))), + idx: 0, + dotdotdoted: false, + sep: None, + }); + } MatchedNonterminal(ref other_whole_nt) => { + r.stack.last_mut().unwrap().idx += 1; // FIXME(pcwalton): Bad copy. r.cur_span = sp; - r.cur_tok = token::Interpolated((*other_whole_nt).clone()); + r.cur_tok = Interpolated((*other_whole_nt).clone()); return ret_val; } MatchedSeq(..) => { diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 0ad09fd0f7dfb..d38edf816880e 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -135,6 +135,7 @@ impl TokenTree { } TokenTree::Token(_, token::SpecialVarNt(..)) => 2, TokenTree::Token(_, token::MatchNt(..)) => 3, + TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1, TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2, TokenTree::Sequence(_, ref seq) => seq.tts.len(), TokenTree::Token(..) => 0, @@ -197,6 +198,9 @@ impl TokenTree { TokenTree::Token(sp, token::Ident(kind))]; v[index].clone() } + (&TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(ref tt))), _) => { + tt.clone().unwrap() + } (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), _ => panic!("Cannot expand a token tree"), } From ccc955c84c3edb1aab58a5e6afe08cc1f57b7697 Mon Sep 17 00:00:00 2001 From: Robert Williamson Date: Sat, 23 Jul 2016 16:13:25 -0600 Subject: [PATCH 090/150] Fix HashMap's values_mut example to use println! --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a03249e006356..97af99030c8f7 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -877,7 +877,7 @@ impl HashMap /// } /// /// for val in map.values() { - /// print!("{}", val); + /// println!("{}", val); /// } /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] From dad29a6d03429874ddf5ce6f53045bae2e0d6fac Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 16:07:06 +0200 Subject: [PATCH 091/150] Add missing links --- src/libstd/fs.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692ad..d1453b05a791d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -58,28 +58,37 @@ pub struct File { /// Metadata information about a file. /// -/// This structure is returned from the `metadata` function or method and +/// This structure is returned from the [`metadata`] function or method and /// represents known metadata about a file such as its permissions, size, /// modification times, etc. +/// +/// [`metadata`]: fn.metadata.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Metadata(fs_imp::FileAttr); /// Iterator over the entries in a directory. /// -/// This iterator is returned from the `read_dir` function of this module and -/// will yield instances of `io::Result`. Through a `DirEntry` +/// This iterator is returned from the [`read_dir`] function of this module and +/// will yield instances of `io::Result`. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// +/// [`read_dir`]: fn.read_dir.html +/// [`DirEntry`]: struct.DirEntry.html +/// /// # Errors /// -/// This `io::Result` will be an `Err` if there's some sort of intermittent +/// This [`io::Result`] will be an `Err` if there's some sort of intermittent /// IO error during iteration. +/// +/// [`io::Result`]: ../io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ReadDir(fs_imp::ReadDir); -/// Entries returned by the `ReadDir` iterator. +/// Entries returned by the [`ReadDir`] iterator. +/// +/// [`ReadDir`]: struct.ReadDir.html /// /// An instance of `DirEntry` represents an entry inside of a directory on the /// filesystem. Each entry can be inspected via methods to learn about the full @@ -89,17 +98,23 @@ pub struct DirEntry(fs_imp::DirEntry); /// Options and flags which can be used to configure how a file is opened. /// -/// This builder exposes the ability to configure how a `File` is opened and -/// what operations are permitted on the open file. The `File::open` and -/// `File::create` methods are aliases for commonly used options using this +/// This builder exposes the ability to configure how a [`File`] is opened and +/// what operations are permitted on the open file. The [`File::open`] and +/// [`File::create`] methods are aliases for commonly used options using this /// builder. /// -/// 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 +/// [`File`]: struct.File.html +/// [`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()`], +/// 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 /// [result]: ../io/type.Result.html /// [file]: struct.File.html /// @@ -131,10 +146,12 @@ pub struct OpenOptions(fs_imp::OpenOptions); /// Representation of the various permissions on a file. /// -/// This module only currently provides one bit of information, `readonly`, +/// This module only currently provides one bit of information, [`readonly`], /// which is exposed on all currently supported platforms. Unix-specific /// functionality, such as mode bits, is available through the /// `os::unix::PermissionsExt` trait. +/// +/// [`readonly`]: struct.Permissions.html#method.readonly #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Permissions(fs_imp::FilePermissions); From 16699635bc467b0940c11675dd73e7e444088c4e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 16:52:28 +0200 Subject: [PATCH 092/150] Add DirEntry doc examples --- src/libstd/fs.rs | 55 +++++++++++++++++++++++++++++++++++ src/libstd/sys/unix/ext/fs.rs | 16 ++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index d1453b05a791d..6547cb6acbe44 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -846,6 +846,26 @@ impl DirEntry { /// On Windows this function is cheap to call (no extra system calls /// needed), but on Unix platforms this function is the equivalent of /// calling `symlink_metadata` on the path. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// if let Ok(metadata) = entry.metadata() { + /// // Now let's show our entry's permissions! + /// println!("{:?}: {:?}", entry.path(), metadata.permissions()); + /// } else { + /// println!("Couldn't get metadata for {:?}", entry.path()); + /// } + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn metadata(&self) -> io::Result { self.0.metadata().map(Metadata) @@ -861,6 +881,26 @@ impl DirEntry { /// On Windows and most Unix platforms this function is free (no extra /// system calls needed), but some Unix platforms may require the equivalent /// call to `symlink_metadata` to learn about the target file type. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// if let Ok(file_type) = entry.file_type() { + /// // Now let's show our entry's file type! + /// println!("{:?}: {:?}", entry.path(), file_type); + /// } else { + /// println!("Couldn't get file type for {:?}", entry.path()); + /// } + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_type(&self) -> io::Result { self.0.file_type().map(FileType) @@ -868,6 +908,21 @@ impl DirEntry { /// Returns the bare file name of this directory entry without any other /// leading path component. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// println!("{:?}", entry.file_name()); + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_name(&self) -> OsString { self.0.file_name() diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index bb90a977433e0..17c093e6cac68 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -196,6 +196,22 @@ impl FileTypeExt for fs::FileType { pub trait DirEntryExt { /// Returns the underlying `d_ino` field in the contained `dirent` /// structure. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::DirEntryExt; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// println!("{:?}: {}", entry.file_name(), entry.ino()); + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] fn ino(&self) -> u64; } From debb2ac76bd8b4ef8de0f470351a2b187afc91df Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 17:00:49 +0200 Subject: [PATCH 093/150] Improve Open doc --- src/libstd/fs.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692ad..4d4d44bae309a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -156,12 +156,14 @@ pub struct DirBuilder { impl File { /// Attempts to open a file in read-only mode. /// - /// See the `OpenOptions::open` method for more details. + /// See the [`OpenOptions::open`] method for more details. /// /// # Errors /// /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to `OpenOptions::open`. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -183,7 +185,9 @@ impl File { /// This function will create a file if it does not exist, /// and will truncate it if it does. /// - /// See the `OpenOptions::open` function for more details. + /// See the [`OpenOptions::open`] function for more details. + /// + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -224,7 +228,7 @@ impl File { self.inner.fsync() } - /// This function is similar to `sync_all`, except that it may not + /// This function is similar to [`sync_all`], except that it may not /// synchronize file metadata to the filesystem. /// /// This is intended for use cases that must synchronize content, but don't @@ -232,7 +236,9 @@ impl File { /// operations. /// /// Note that some platforms may simply implement this in terms of - /// `sync_all`. + /// [`sync_all`]. + /// + /// [`sync_all`]: struct.File.html#method.sync_all /// /// # Examples /// @@ -304,6 +310,18 @@ impl File { /// The returned `File` is a reference to the same state that this object /// references. Both handles will read and write with the same cursor /// position. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let file_copy = try!(f.try_clone()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_try_clone", since = "1.9.0")] pub fn try_clone(&self) -> io::Result { Ok(File { From 9aca38e56872ffcae9a8f64b83d6d074ab802d3c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 24 Jul 2016 15:49:26 -0400 Subject: [PATCH 094/150] move coerce-match{,-calls} into run-pass-valgrind Closes #21696. --- src/test/{run-pass => run-pass-valgrind}/coerce-match-calls.rs | 0 src/test/{run-pass => run-pass-valgrind}/coerce-match.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/{run-pass => run-pass-valgrind}/coerce-match-calls.rs (100%) rename src/test/{run-pass => run-pass-valgrind}/coerce-match.rs (100%) diff --git a/src/test/run-pass/coerce-match-calls.rs b/src/test/run-pass-valgrind/coerce-match-calls.rs similarity index 100% rename from src/test/run-pass/coerce-match-calls.rs rename to src/test/run-pass-valgrind/coerce-match-calls.rs diff --git a/src/test/run-pass/coerce-match.rs b/src/test/run-pass-valgrind/coerce-match.rs similarity index 100% rename from src/test/run-pass/coerce-match.rs rename to src/test/run-pass-valgrind/coerce-match.rs From f438801528fd03a12339c843e6d516ca3526e8e1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 22 Jul 2016 17:11:38 -0500 Subject: [PATCH 095/150] add include ../tools.mk to the Makefile --- src/test/run-make/issue-33329/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-make/issue-33329/Makefile b/src/test/run-make/issue-33329/Makefile index cd00ebc2d0a67..c53f51d5bf584 100644 --- a/src/test/run-make/issue-33329/Makefile +++ b/src/test/run-make/issue-33329/Makefile @@ -1,3 +1,5 @@ +-include ../tools.mk + all: $(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | \ grep "error: Error loading target specification: Could not find specification for target" From 96932cf3d0fa247c30a117e78fe23020b865f2ee Mon Sep 17 00:00:00 2001 From: abhi Date: Mon, 25 Jul 2016 15:00:32 +0530 Subject: [PATCH 096/150] Remove no_stack_check tests (#34915) Part of fixes for #34915 --- ...nction-prologue-stepping-no-stack-check.rs | 369 ------------------ 1 file changed, 369 deletions(-) delete mode 100644 src/test/debuginfo/function-prologue-stepping-no-stack-check.rs diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs deleted file mode 100644 index b5b6ca7572703..0000000000000 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ /dev/null @@ -1,369 +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-android: FIXME(#10381) -// min-lldb-version: 310 - -// This test case checks if function arguments already have the correct value -// when breaking at the beginning of a function. Functions with the -// #[no_stack_check] attribute have the same prologue as regular C functions -// compiled with GCC or Clang and therefore are better handled by GDB. As a -// consequence, and as opposed to regular Rust functions, we can set the -// breakpoints via the function name (and don't have to fall back on using line -// numbers). For LLDB this shouldn't make a difference because it can handle -// both cases. - -// compile-flags:-g - -// === GDB TESTS =================================================================================== - -// gdb-command:rbreak immediate_args -// gdb-command:rbreak binding -// gdb-command:rbreak assignment -// gdb-command:rbreak function_call -// gdb-command:rbreak identifier -// gdb-command:rbreak return_expr -// gdb-command:rbreak arithmetic_expr -// gdb-command:rbreak if_expr -// gdb-command:rbreak while_expr -// gdb-command:rbreak loop_expr -// gdb-command:run - -// IMMEDIATE ARGS -// gdb-command:print a -// gdb-check:$1 = 1 -// gdb-command:print b -// gdb-check:$2 = true -// gdb-command:print c -// gdb-check:$3 = 2.5 -// gdb-command:continue - -// NON IMMEDIATE ARGS -// gdb-command:print a -// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} -// gdb-command:print b -// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} -// gdb-command:continue - -// BINDING -// gdb-command:print a -// gdb-check:$6 = 19 -// gdb-command:print b -// gdb-check:$7 = 20 -// gdb-command:print c -// gdb-check:$8 = 21.5 -// gdb-command:continue - -// ASSIGNMENT -// gdb-command:print a -// gdb-check:$9 = 22 -// gdb-command:print b -// gdb-check:$10 = 23 -// gdb-command:print c -// gdb-check:$11 = 24.5 -// gdb-command:continue - -// FUNCTION CALL -// gdb-command:print x -// gdb-check:$12 = 25 -// gdb-command:print y -// gdb-check:$13 = 26 -// gdb-command:print z -// gdb-check:$14 = 27.5 -// gdb-command:continue - -// EXPR -// gdb-command:print x -// gdb-check:$15 = 28 -// gdb-command:print y -// gdb-check:$16 = 29 -// gdb-command:print z -// gdb-check:$17 = 30.5 -// gdb-command:continue - -// RETURN EXPR -// gdb-command:print x -// gdb-check:$18 = 31 -// gdb-command:print y -// gdb-check:$19 = 32 -// gdb-command:print z -// gdb-check:$20 = 33.5 -// gdb-command:continue - -// ARITHMETIC EXPR -// gdb-command:print x -// gdb-check:$21 = 34 -// gdb-command:print y -// gdb-check:$22 = 35 -// gdb-command:print z -// gdb-check:$23 = 36.5 -// gdb-command:continue - -// IF EXPR -// gdb-command:print x -// gdb-check:$24 = 37 -// gdb-command:print y -// gdb-check:$25 = 38 -// gdb-command:print z -// gdb-check:$26 = 39.5 -// gdb-command:continue - -// WHILE EXPR -// gdb-command:print x -// gdb-check:$27 = 40 -// gdb-command:print y -// gdb-check:$28 = 41 -// gdb-command:print z -// gdb-check:$29 = 42 -// gdb-command:continue - -// LOOP EXPR -// gdb-command:print x -// gdb-check:$30 = 43 -// gdb-command:print y -// gdb-check:$31 = 44 -// gdb-command:print z -// gdb-check:$32 = 45 -// gdb-command:continue - - -// === LLDB TESTS ================================================================================== - -// lldb-command:breakpoint set --name immediate_args -// lldb-command:breakpoint set --name non_immediate_args -// lldb-command:breakpoint set --name binding -// lldb-command:breakpoint set --name assignment -// lldb-command:breakpoint set --name function_call -// lldb-command:breakpoint set --name identifier -// lldb-command:breakpoint set --name return_expr -// lldb-command:breakpoint set --name arithmetic_expr -// lldb-command:breakpoint set --name if_expr -// lldb-command:breakpoint set --name while_expr -// lldb-command:breakpoint set --name loop_expr -// lldb-command:run - -// IMMEDIATE ARGS -// lldb-command:print a -// lldb-check:[...]$0 = 1 -// lldb-command:print b -// lldb-check:[...]$1 = true -// lldb-command:print c -// lldb-check:[...]$2 = 2.5 -// lldb-command:continue - -// NON IMMEDIATE ARGS -// lldb-command:print a -// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 } -// lldb-command:print b -// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 } -// lldb-command:continue - -// BINDING -// lldb-command:print a -// lldb-check:[...]$5 = 19 -// lldb-command:print b -// lldb-check:[...]$6 = 20 -// lldb-command:print c -// lldb-check:[...]$7 = 21.5 -// lldb-command:continue - -// ASSIGNMENT -// lldb-command:print a -// lldb-check:[...]$8 = 22 -// lldb-command:print b -// lldb-check:[...]$9 = 23 -// lldb-command:print c -// lldb-check:[...]$10 = 24.5 -// lldb-command:continue - -// FUNCTION CALL -// lldb-command:print x -// lldb-check:[...]$11 = 25 -// lldb-command:print y -// lldb-check:[...]$12 = 26 -// lldb-command:print z -// lldb-check:[...]$13 = 27.5 -// lldb-command:continue - -// EXPR -// lldb-command:print x -// lldb-check:[...]$14 = 28 -// lldb-command:print y -// lldb-check:[...]$15 = 29 -// lldb-command:print z -// lldb-check:[...]$16 = 30.5 -// lldb-command:continue - -// RETURN EXPR -// lldb-command:print x -// lldb-check:[...]$17 = 31 -// lldb-command:print y -// lldb-check:[...]$18 = 32 -// lldb-command:print z -// lldb-check:[...]$19 = 33.5 -// lldb-command:continue - -// ARITHMETIC EXPR -// lldb-command:print x -// lldb-check:[...]$20 = 34 -// lldb-command:print y -// lldb-check:[...]$21 = 35 -// lldb-command:print z -// lldb-check:[...]$22 = 36.5 -// lldb-command:continue - -// IF EXPR -// lldb-command:print x -// lldb-check:[...]$23 = 37 -// lldb-command:print y -// lldb-check:[...]$24 = 38 -// lldb-command:print z -// lldb-check:[...]$25 = 39.5 -// lldb-command:continue - -// WHILE EXPR -// lldb-command:print x -// lldb-check:[...]$26 = 40 -// lldb-command:print y -// lldb-check:[...]$27 = 41 -// lldb-command:print z -// lldb-check:[...]$28 = 42 -// lldb-command:continue - -// LOOP EXPR -// lldb-command:print x -// lldb-check:[...]$29 = 43 -// lldb-command:print y -// lldb-check:[...]$30 = 44 -// lldb-command:print z -// lldb-check:[...]$31 = 45 -// lldb-command:continue - -#![allow(dead_code, unused_assignments, unused_variables)] -#![feature(omit_gdb_pretty_printer_section)] -#![omit_gdb_pretty_printer_section] - -#[no_stack_check] -fn immediate_args(a: isize, b: bool, c: f64) { - println!(""); -} - -struct BigStruct { - a: u64, - b: u64, - c: u64, - d: u64, - e: u64, - f: u64, - g: u64, - h: u64 -} - -#[no_stack_check] -fn non_immediate_args(a: BigStruct, b: BigStruct) { - println!(""); -} - -#[no_stack_check] -fn binding(a: i64, b: u64, c: f64) { - let x = 0; - println!(""); -} - -#[no_stack_check] -fn assignment(mut a: u64, b: u64, c: f64) { - a = b; - println!(""); -} - -#[no_stack_check] -fn function_call(x: u64, y: u64, z: f64) { - println!("Hi!") -} - -#[no_stack_check] -fn identifier(x: u64, y: u64, z: f64) -> u64 { - x -} - -#[no_stack_check] -fn return_expr(x: u64, y: u64, z: f64) -> u64 { - return x; -} - -#[no_stack_check] -fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { - x + y -} - -#[no_stack_check] -fn if_expr(x: u64, y: u64, z: f64) -> u64 { - if x + y < 1000 { - x - } else { - y - } -} - -#[no_stack_check] -fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { - while x + y < 1000 { - x += z - } - return x; -} - -#[no_stack_check] -fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { - loop { - x += z; - - if x + y > 1000 { - return x; - } - } -} - -fn main() { - immediate_args(1, true, 2.5); - - non_immediate_args( - BigStruct { - a: 3, - b: 4, - c: 5, - d: 6, - e: 7, - f: 8, - g: 9, - h: 10 - }, - BigStruct { - a: 11, - b: 12, - c: 13, - d: 14, - e: 15, - f: 16, - g: 17, - h: 18 - } - ); - - binding(19, 20, 21.5); - assignment(22, 23, 24.5); - function_call(25, 26, 27.5); - identifier(28, 29, 30.5); - return_expr(31, 32, 33.5); - arithmetic_expr(34, 35, 36.5); - if_expr(37, 38, 39.5); - while_expr(40, 41, 42); - loop_expr(43, 44, 45); -} From f694809a0d06ea1d754ff6a9cd00e038392f6e9a Mon Sep 17 00:00:00 2001 From: Andrea Pretto Date: Mon, 25 Jul 2016 11:46:59 +0200 Subject: [PATCH 097/150] Fixed missing comma in the csv dumper. --- src/librustc_save_analysis/csv_dumper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index e7cc534c5b555..0fd95500422ff 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -427,7 +427,7 @@ 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,{}\ + 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) From 5fbcf08dd8cfc347c13d84c8ea20e3bfce6793fc Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sun, 24 Jul 2016 22:09:56 -0700 Subject: [PATCH 098/150] Looser LSDA parsing --- src/libpanic_unwind/dwarf/eh.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 32fdf5c204801..1e9e9e30f5cfe 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -108,10 +108,9 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { } } } - // If ip is not present in the table, call terminate. This is for - // a destructor inside a cleanup, or a library routine the compiler - // was not expecting to throw - EHAction::Terminate + // Ip is not present in the table. This should not hapen... but it does: issie #35011. + // So rather than returning EHAction::Terminate, we do this. + EHAction::None } else { // SjLj version: // The "IP" is an index into the call-site table, with two exceptions: From 5c0ce872fbbdb9364c970869a1ad7be486c29b37 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 25 Jul 2016 18:19:11 +0100 Subject: [PATCH 099/150] rustdoc: Fix tuple struct where clause rendering For tuple structs the where clause comes after the definition. --- src/librustdoc/html/render.rs | 15 +++++++++++++-- src/test/rustdoc/issue-34928.rs | 16 ++++++++++++++++ src/test/rustdoc/where.rs | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/issue-34928.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2e2fc011ddbe6..e4e886c853347 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2409,10 +2409,13 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, if structhead {"struct "} else {""}, it.name.as_ref().unwrap())?; if let Some(g) = g { - write!(w, "{}{}", *g, WhereClause(g))? + write!(w, "{}", g)? } match ty { doctree::Plain => { + if let Some(g) = g { + write!(w, "{}", WhereClause(g))? + } write!(w, " {{\n{}", tab)?; for field in fields { if let clean::StructFieldItem(ref ty) = field.inner { @@ -2445,9 +2448,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, _ => unreachable!() } } - write!(w, ");")?; + write!(w, ")")?; + if let Some(g) = g { + write!(w, "{}", WhereClause(g))? + } + write!(w, ";")?; } doctree::Unit => { + // Needed for PhantomData. + if let Some(g) = g { + write!(w, "{}", WhereClause(g))? + } write!(w, ";")?; } } diff --git a/src/test/rustdoc/issue-34928.rs b/src/test/rustdoc/issue-34928.rs new file mode 100644 index 0000000000000..b2104a0c80f5d --- /dev/null +++ b/src/test/rustdoc/issue-34928.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. + +#![crate_name = "foo"] + +pub trait Bar {} + +// @has foo/struct.Foo.html '//pre' 'pub struct Foo(pub T) where T: Bar;' +pub struct Foo(pub T) where T: Bar; diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 91ec69d9a3cbb..d8dc115abf91e 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -12,7 +12,7 @@ pub trait MyTrait { fn dummy(&self) { } } -// @has foo/struct.Alpha.html '//pre' "pub struct Alpha where A: MyTrait" +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_) where A: MyTrait" pub struct Alpha(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravo where B: MyTrait" pub trait Bravo where B: MyTrait { fn get(&self, B: B); } From cdb0867493fd9b3b42d29ce3bbca75dbe6e278b9 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Mon, 25 Jul 2016 13:08:48 -0700 Subject: [PATCH 100/150] Unpublicize inference relations --- src/librustc/infer/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2ea2978b2940d..4e0c5b58b64d1 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -48,18 +48,18 @@ use self::higher_ranked::HrMatchResult; use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::unify_key::ToType; -pub mod bivariate; -pub mod combine; -pub mod equate; +mod bivariate; +mod combine; +mod equate; pub mod error_reporting; -pub mod glb; +mod glb; mod higher_ranked; pub mod lattice; -pub mod lub; +mod lub; pub mod region_inference; pub mod resolve; mod freshen; -pub mod sub; +mod sub; pub mod type_variable; pub mod unify_key; From a279f2f62d0b04af02f5a9e356d380f2ae6216d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 22 Jul 2016 09:44:09 -0700 Subject: [PATCH 101/150] Weaken test `compile-fail/lifetime-inference-give-expl-lifetime-param`. --- .../lifetime-inference-give-expl-lifetime-param.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index e34a3c4569d0a..6da87fca3f356 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -49,7 +49,8 @@ struct Baz<'x> { impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'a isize) -> (&'a isize, &'a isize) + //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &' + // FIXME #35038: The above suggestion is different on Linux and Mac. (self.bar, x) //~ ERROR E0312 //~^ ERROR E0312 } From a139772e7751017d66d82877b3666d58df7ef00b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 24 Jul 2016 22:10:36 -0400 Subject: [PATCH 102/150] Rewrite/expansion of `slice::split` doc examples. --- src/libcollections/slice.rs | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 1f8eea56fc69c..ccef6c02f9d22 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -691,15 +691,40 @@ impl [T] { /// /// # Examples /// - /// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`, - /// `[20]`, `[50]`): + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); /// ``` - /// let v = [10, 40, 30, 20, 60, 50]; /// - /// for group in v.split(|num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] From a5e5ea1646367b82864af3a2a508993d76b792af Mon Sep 17 00:00:00 2001 From: cgswords Date: Fri, 15 Jul 2016 13:13:17 -0700 Subject: [PATCH 103/150] General MetaItem encapsulation rewrites. --- src/librustc/lint/context.rs | 22 ++--- src/librustc_driver/lib.rs | 36 ++++---- src/librustc_incremental/assert_dep_graph.rs | 33 ++++--- src/librustc_incremental/calculate_svh.rs | 3 +- src/librustc_lint/builtin.rs | 15 ++-- src/librustc_metadata/decoder.rs | 10 +-- src/librustc_metadata/encoder.rs | 37 ++++---- src/librustc_metadata/macro_import.rs | 12 +-- src/librustdoc/clean/mod.rs | 79 ++++++++++------ src/libsyntax/attr.rs | 94 +++++++++++++++++--- src/libsyntax/ext/build.rs | 23 ++--- src/libsyntax/ext/expand.rs | 5 +- src/libsyntax/feature_gate.rs | 15 ++-- src/libsyntax_ext/deriving/mod.rs | 19 ++-- 14 files changed, 232 insertions(+), 171 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ce3d72de9ae99..0a1e7005f9fb9 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -366,19 +366,19 @@ pub fn gather_attr(attr: &ast::Attribute) attr::mark_used(attr); let meta = &attr.node.value; - let metas = match meta.node { - ast::MetaItemKind::List(_, ref metas) => metas, - _ => { - out.push(Err(meta.span)); - return out; - } - }; + let metas = if let Some(metas) = meta.meta_item_list() { + metas + } else { + out.push(Err(meta.span)); + return out; + }; for meta in metas { - out.push(match meta.node { - ast::MetaItemKind::Word(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), - _ => Err(meta.span), - }); + out.push(if meta.is_word() { + Ok((meta.name().clone(), level, meta.span)) + } else { + Err(meta.span) + }); } out diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 0a8df923b846b..9df1dea45671f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -95,6 +95,7 @@ use std::thread; use rustc::session::early_error; use syntax::{ast, json}; +use syntax::attr::AttrMetaMethods; use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; @@ -392,15 +393,13 @@ fn check_cfg(sopts: &config::Options, let mut saw_invalid_predicate = false; for item in sopts.cfg.iter() { - match item.node { - ast::MetaItemKind::List(ref pred, _) => { - saw_invalid_predicate = true; - handler.emit(&MultiSpan::new(), - &format!("invalid predicate in --cfg command line argument: `{}`", - pred), - errors::Level::Fatal); - } - _ => {}, + if item.is_meta_item_list() { + saw_invalid_predicate = true; + saw_invalid_predicate = true; + handler.emit(&MultiSpan::new(), + &format!("invalid predicate in --cfg command line argument: `{}`", + pred), + errors::Level::Fatal); } } @@ -649,20 +648,19 @@ impl RustcDefaultCalls { if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() { continue; } - match cfg.node { - ast::MetaItemKind::Word(ref word) => println!("{}", word), - ast::MetaItemKind::NameValue(ref name, ref value) => { - println!("{}=\"{}\"", name, match value.node { - ast::LitKind::Str(ref s, _) => s, - _ => continue, - }); + if cfg.is_word() { + println!("{}", cfg.name()); + } else if cfg.is_value_str() { + let rhs = cfg.value_str(); + match rhs { + Some(s) => println!("{}=\"{}\"", cfg.name(), s), + None => continue, } + } else if cfg.is_meta_item_list() { // Right now there are not and should not be any // MetaItemKind::List items in the configuration returned by // `build_configuration`. - ast::MetaItemKind::List(..) => { - panic!("MetaItemKind::List encountered in default cfg") - } + panic!("MetaItemKind::List encountered in default cfg") } } } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index d38f979e33c5a..0d327414c8fc5 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -110,13 +110,13 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { if attr.check_name(IF_THIS_CHANGED) { let mut id = None; for meta_item in attr.meta_item_list().unwrap_or_default() { - match meta_item.node { - ast::MetaItemKind::Word(ref s) if id.is_none() => id = Some(s.clone()), - _ => { - self.tcx.sess.span_err( - meta_item.span, - &format!("unexpected meta-item {:?}", meta_item.node)); - } + if meta_item.is_word() && id.is_none() { + id = Some(meta_item.name().clone()); + } else { + // FIXME better-encapsulate meta_item (don't directly access `node`) + self.tcx.sess.span_err( + meta_item.span(), + &format!("unexpected meta-item {:?}", meta_item.node)); } } let id = id.unwrap_or(InternedString::new(ID)); @@ -127,16 +127,15 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { let mut dep_node_interned = None; let mut id = None; for meta_item in attr.meta_item_list().unwrap_or_default() { - match meta_item.node { - ast::MetaItemKind::Word(ref s) if dep_node_interned.is_none() => - dep_node_interned = Some(s.clone()), - ast::MetaItemKind::Word(ref s) if id.is_none() => - id = Some(s.clone()), - _ => { - self.tcx.sess.span_err( - meta_item.span, - &format!("unexpected meta-item {:?}", meta_item.node)); - } + if meta_item.is_word() && dep_node_interned.is_none() { + dep_node_interned = Some(meta_item.name().clone()); + } else if meta_item.is_word() && id.is_none() { + id = Some(meta_item.name().clone()); + } else { + // FIXME better-encapsulate meta_item (don't directly access `node`) + self.tcx.sess.span_err( + meta_item.span(), + &format!("unexpected meta-item {:?}", meta_item.node)); } } let dep_node = match dep_node_interned { diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index cbc246ac2a11b..5d26bcd48a3bc 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -11,6 +11,7 @@ //! Calculation of a Strict Version Hash for crates. For a length //! comment explaining the general idea, see `librustc/middle/svh.rs`. +use syntax::attr::AttributeMethods; use std::hash::{Hash, SipHasher, Hasher}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::svh::Svh; @@ -69,7 +70,7 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { // to avoid hashing the AttrId for attr in &krate.attrs { debug!("krate attr {:?}", attr); - attr.node.value.hash(&mut state); + attr.meta().hash(&mut state); } Svh::new(state.finish()) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 18f9733040e0f..a498004b390a4 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; use syntax_pos::{self, Span}; use rustc::hir::{self, PatKind}; @@ -299,9 +299,10 @@ impl MissingDoc { } let has_doc = attrs.iter().any(|a| { - match a.node.value.node { - ast::MetaItemKind::NameValue(ref name, _) if *name == "doc" => true, - _ => false + if a.is_value_str() && a.name() == "doc" { + true + } else { + false } }); if !has_doc { @@ -1094,10 +1095,10 @@ impl LintPass for UnstableFeatures { impl LateLintPass for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { - if attr::contains_name(&[attr.node.value.clone()], "feature") { - if let Some(items) = attr.node.value.meta_item_list() { + if attr::contains_name(&[attr.meta().clone()], "feature") { + if let Some(items) = attr.meta().meta_item_list() { for item in items { - ctx.span_lint(UNSTABLE_FEATURES, item.span, "unstable feature"); + ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); } } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 409cec282bce9..63345a15e6a9b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1160,15 +1160,7 @@ fn get_attributes(md: rbml::Doc) -> Vec { // an attribute assert_eq!(meta_items.len(), 1); let meta_item = meta_items.into_iter().nth(0).unwrap(); - codemap::Spanned { - node: ast::Attribute_ { - id: attr::mk_attr_id(), - style: ast::AttrStyle::Outer, - value: meta_item, - is_sugared_doc: is_sugared_doc, - }, - span: syntax_pos::DUMMY_SP - } + attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc) }).collect() }, None => vec![], diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7314259423592..91b1b82211a16 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -44,7 +44,7 @@ use std::rc::Rc; use std::u32; use syntax::abi::Abi; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; -use syntax::attr; +use syntax::attr::{self,AttrMetaMethods,AttributeMethods}; use errors::Handler; use syntax; use syntax_pos::BytePos; @@ -1431,31 +1431,28 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { } fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) { - match mi.node { - ast::MetaItemKind::Word(ref name) => { + if mi.is_word() { + let name = mi.name(); rbml_w.start_tag(tag_meta_item_word); - rbml_w.wr_tagged_str(tag_meta_item_name, name); + rbml_w.wr_tagged_str(tag_meta_item_name, &name); rbml_w.end_tag(); - } - ast::MetaItemKind::NameValue(ref name, ref value) => { - match value.node { - ast::LitKind::Str(ref value, _) => { - rbml_w.start_tag(tag_meta_item_name_value); - rbml_w.wr_tagged_str(tag_meta_item_name, name); - rbml_w.wr_tagged_str(tag_meta_item_value, value); - rbml_w.end_tag(); - } - _ => {/* FIXME (#623): encode other variants */ } - } - } - ast::MetaItemKind::List(ref name, ref items) => { + } else if mi.is_value_str() { + let name = mi.name(); + /* FIXME (#623): support other literal kinds */ + let value = mi.value_str().unwrap(); + rbml_w.start_tag(tag_meta_item_name_value); + rbml_w.wr_tagged_str(tag_meta_item_name, &name); + rbml_w.wr_tagged_str(tag_meta_item_value, &value); + rbml_w.end_tag(); + } else { // it must be a list + let name = mi.name(); + let items = mi.meta_item_list().unwrap(); rbml_w.start_tag(tag_meta_item_list); - rbml_w.wr_tagged_str(tag_meta_item_name, name); + rbml_w.wr_tagged_str(tag_meta_item_name, &name); for inner_item in items { encode_meta_item(rbml_w, &inner_item); } rbml_w.end_tag(); - } } } @@ -1464,7 +1461,7 @@ fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { for attr in attrs { rbml_w.start_tag(tag_attribute); rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); - encode_meta_item(rbml_w, &attr.node.value); + encode_meta_item(rbml_w, attr.meta()); rbml_w.end_tag(); } rbml_w.end_tag(); diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 7dadf8d108a71..4be044c1df307 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -60,10 +60,10 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { } if let (Some(sel), Some(names)) = (import.as_mut(), names) { for attr in names { - if let ast::MetaItemKind::Word(ref name) = attr.node { - sel.insert(name.clone(), attr.span); + if attr.is_word() { + sel.insert(attr.name().clone(), attr.span()); } else { - span_err!(self.sess, attr.span, E0466, "bad macro import"); + span_err!(self.sess, attr.span(), E0466, "bad macro import"); } } } @@ -78,10 +78,10 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { }; for attr in names { - if let ast::MetaItemKind::Word(ref name) = attr.node { - reexport.insert(name.clone(), attr.span); + if attr.is_word() { + reexport.insert(attr.name().clone(), attr.span()); } else { - call_bad_macro_reexport(self.sess, attr.span); + call_bad_macro_reexport(self.sess, attr.span()); } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0211b2c9bc7ba..8d69c55ecf124 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -498,21 +498,20 @@ pub enum Attribute { impl Clean for ast::MetaItem { fn clean(&self, cx: &DocContext) -> Attribute { - match self.node { - ast::MetaItemKind::Word(ref s) => Word(s.to_string()), - ast::MetaItemKind::List(ref s, ref l) => { - List(s.to_string(), l.clean(cx)) - } - ast::MetaItemKind::NameValue(ref s, ref v) => { - NameValue(s.to_string(), lit_to_string(v)) - } - } + if self.is_word() { + Word(self.name().to_string()) + } else if let Some(v) = self.value_str() { + NameValue(self.name().to_string(), v.to_string()) + } else { // must be a list + let l = self.meta_item_list().unwrap(); + List(self.name().to_string(), l.clean(cx)) + } } } impl Clean for ast::Attribute { fn clean(&self, cx: &DocContext) -> Attribute { - self.with_desugared_doc(|a| a.node.value.clean(cx)) + self.with_desugared_doc(|a| a.meta().clean(cx)) } } @@ -535,6 +534,28 @@ impl attr::AttrMetaMethods for Attribute { } } fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { None } + + fn is_word(&self) -> bool { + match *self { + Word(_) => true, + _ => false, + } + } + + fn is_value_str(&self) -> bool { + match *self { + NameValue(..) => true, + _ => false, + } + } + + fn is_meta_item_list(&self) -> bool { + match *self { + List(..) => true, + _ => false, + } + } + fn span(&self) -> syntax_pos::Span { unimplemented!() } } @@ -2568,25 +2589,25 @@ impl ToSource for syntax_pos::Span { } } -fn lit_to_string(lit: &ast::Lit) -> String { - match lit.node { - ast::LitKind::Str(ref st, _) => st.to_string(), - ast::LitKind::ByteStr(ref data) => format!("{:?}", data), - ast::LitKind::Byte(b) => { - let mut res = String::from("b'"); - for c in (b as char).escape_default() { - res.push(c); - } - res.push('\''); - res - }, - ast::LitKind::Char(c) => format!("'{}'", c), - ast::LitKind::Int(i, _t) => i.to_string(), - ast::LitKind::Float(ref f, _t) => f.to_string(), - ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(), - ast::LitKind::Bool(b) => b.to_string(), - } -} +// fn lit_to_string(lit: &ast::Lit) -> String { +// match lit.node { +// ast::LitKind::Str(ref st, _) => st.to_string(), +// ast::LitKind::ByteStr(ref data) => format!("{:?}", data), +// ast::LitKind::Byte(b) => { +// let mut res = String::from("b'"); +// for c in (b as char).escape_default() { +// res.push(c); +// } +// res.push('\''); +// res +// }, +// ast::LitKind::Char(c) => format!("'{}'", c), +// ast::LitKind::Int(i, _t) => i.to_string(), +// ast::LitKind::Float(ref f, _t) => f.to_string(), +// ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(), +// ast::LitKind::Bool(b) => b.to_string(), +// } +// } fn name_from_pat(p: &hir::Pat) -> String { use rustc::hir::*; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 67f73d4dd4f71..8bd3f5195ccd8 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -17,8 +17,8 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind}; use ast::{Expr, Item, Local, Stmt, StmtKind}; -use codemap::{spanned, dummy_spanned, Spanned}; -use syntax_pos::{Span, BytePos}; +use codemap::{respan, spanned, dummy_spanned, Spanned}; +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}; @@ -92,6 +92,13 @@ pub trait AttrMetaMethods { /// Gets a list of inner meta items from a list MetaItem type. fn meta_item_list(&self) -> Option<&[P]>; + /// Indicates if the attribute is a Word. + fn is_word(&self) -> bool; + /// Indicates if the attribute is a Value String. + fn is_value_str(&self) -> bool; + /// Indicates if the attribute is a Meta-Item List. + fn is_meta_item_list(&self) -> bool; + fn span(&self) -> Span; } @@ -108,8 +115,14 @@ impl AttrMetaMethods for Attribute { self.meta().value_str() } fn meta_item_list(&self) -> Option<&[P]> { - self.node.value.meta_item_list() + self.meta().meta_item_list() } + + fn is_word(&self) -> bool { self.meta().is_word() } + fn is_value_str(&self) -> bool { self.meta().is_value_str() } + + fn is_meta_item_list(&self) -> bool { self.meta().is_meta_item_list() } + fn span(&self) -> Span { self.meta().span } } @@ -140,6 +153,18 @@ impl AttrMetaMethods for MetaItem { _ => None } } + + fn is_word(&self) -> bool { + match self.node { + MetaItemKind::Word(_) => true, + _ => false, + } + } + + fn is_value_str(&self) -> bool { self.value_str().is_some() } + + fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } + fn span(&self) -> Span { self.span } } @@ -150,6 +175,9 @@ impl AttrMetaMethods for P { fn meta_item_list(&self) -> Option<&[P]> { (**self).meta_item_list() } + fn is_word(&self) -> bool { (**self).is_word() } + fn is_value_str(&self) -> bool { (**self).is_value_str() } + fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() } fn span(&self) -> Span { (**self).span() } } @@ -194,22 +222,38 @@ impl AttributeMethods for Attribute { pub fn mk_name_value_item_str(name: InternedString, value: InternedString) -> P { let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked)); - mk_name_value_item(name, value_lit) + mk_spanned_name_value_item(DUMMY_SP, name, value_lit) } pub fn mk_name_value_item(name: InternedString, value: ast::Lit) -> P { - P(dummy_spanned(MetaItemKind::NameValue(name, value))) + mk_spanned_name_value_item(DUMMY_SP, name, value) } pub fn mk_list_item(name: InternedString, items: Vec>) -> P { - P(dummy_spanned(MetaItemKind::List(name, items))) + mk_spanned_list_item(DUMMY_SP, name, items) } pub fn mk_word_item(name: InternedString) -> P { - P(dummy_spanned(MetaItemKind::Word(name))) + mk_spanned_word_item(DUMMY_SP, name) +} + +pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Lit) + -> P { + P(respan(sp,MetaItemKind::NameValue(name, value))) +} + +pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec>) + -> P { + P(respan(sp, MetaItemKind::List(name, items))) } +pub fn mk_spanned_word_item(sp: Span, name: InternedString) -> P { + P(respan(sp,MetaItemKind::Word(name))) +} + + + thread_local! { static NEXT_ATTR_ID: Cell = Cell::new(0) } pub fn mk_attr_id() -> AttrId { @@ -223,21 +267,43 @@ pub fn mk_attr_id() -> AttrId { /// Returns an inner attribute with the given value. pub fn mk_attr_inner(id: AttrId, item: P) -> Attribute { - dummy_spanned(Attribute_ { - id: id, - style: ast::AttrStyle::Inner, - value: item, - is_sugared_doc: false, - }) + mk_spanned_attr_inner(DUMMY_SP, id, item) } +/// Returns an innter attribute with the given value and span. +pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: P) -> Attribute { + respan(sp, + Attribute_ { + id: id, + style: ast::AttrStyle::Inner, + value: item, + is_sugared_doc: false, + }) +} + + /// Returns an outer attribute with the given value. pub fn mk_attr_outer(id: AttrId, item: P) -> Attribute { + mk_spanned_attr_outer(DUMMY_SP, id, item) +} + +/// Returns an outer attribute with the given value and span. +pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: P) -> Attribute { + respan(sp, + Attribute_ { + id: id, + style: ast::AttrStyle::Outer, + value: item, + is_sugared_doc: false, + }) +} + +pub fn mk_doc_attr_outer(id: AttrId, item: P, is_sugared_doc: bool) -> Attribute { dummy_spanned(Attribute_ { id: id, style: ast::AttrStyle::Outer, value: item, - is_sugared_doc: false, + is_sugared_doc: is_sugared_doc, }) } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 435241f426ec6..5d6429f7bdfff 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1135,30 +1135,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn attribute(&self, sp: Span, mi: P) -> ast::Attribute { - respan(sp, ast::Attribute_ { - id: attr::mk_attr_id(), - style: ast::AttrStyle::Outer, - value: mi, - is_sugared_doc: false, - }) + attr::mk_spanned_attr_outer(sp, attr::mk_attr_id(), mi) } fn meta_word(&self, sp: Span, w: InternedString) -> P { - P(respan(sp, ast::MetaItemKind::Word(w))) + attr::mk_spanned_word_item(sp, w) } - fn meta_list(&self, - sp: Span, - name: InternedString, - mis: Vec> ) + fn meta_list(&self, sp: Span, name: InternedString, mis: Vec>) -> P { - P(respan(sp, ast::MetaItemKind::List(name, mis))) + attr::mk_spanned_list_item(sp, name, mis) } - fn meta_name_value(&self, - sp: Span, - name: InternedString, - value: ast::LitKind) + fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind) -> P { - P(respan(sp, ast::MetaItemKind::NameValue(name, respan(sp, value)))) + attr::mk_spanned_name_value_item(sp, name, respan(sp, value)) } fn item_use(&self, sp: Span, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 18342f2e38c1b..5293d2ab0001a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -302,9 +302,8 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool }; if is_use { - match attr.node.value.node { - ast::MetaItemKind::Word(..) => (), - _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"), + if !attr.is_word() { + fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"); } return true; } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 27485ee65fcc0..5a718dd48e374 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1108,14 +1108,13 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F } Some(list) => { for mi in list { - let name = match mi.node { - ast::MetaItemKind::Word(ref word) => (*word).clone(), - _ => { - span_err!(span_handler, mi.span, E0556, - "malformed feature, expected just one word"); - continue - } - }; + let name = if mi.is_word() { + mi.name() + } else { + span_err!(span_handler, mi.span, E0556, + "malformed feature, expected just one word"); + continue + }; if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter() .find(|& &(n, _, _, _)| name == n) { *(setter(&mut features)) = true; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 80e2a923e5569..e09a64e73449b 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -10,7 +10,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. -use syntax::ast::{self, MetaItem, MetaItemKind}; +use syntax::ast::{MetaItem, self}; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; @@ -98,15 +98,14 @@ fn expand_derive(cx: &mut ExtCtxt, let mut eq_span = None; for titem in traits.iter().rev() { - let tname = match titem.node { - MetaItemKind::Word(ref tname) => tname, - _ => { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - } - }; - - if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) { + let tname = if titem.is_word() { + titem.name() } + else { + cx.span_err(titem.span, "malformed `derive` entry"); + continue; + }; + + if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) { feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, "custom_derive", titem.span, From 5553901146fa80c652abdc514b38360a0ae7418d Mon Sep 17 00:00:00 2001 From: cgswords Date: Sun, 17 Jul 2016 21:45:06 -0700 Subject: [PATCH 104/150] Adressed PR comments. --- src/librustc/lint/context.rs | 18 ++++++++-------- src/librustc_driver/lib.rs | 9 +++----- src/librustc_incremental/assert_dep_graph.rs | 8 ++----- src/librustc_lint/builtin.rs | 8 +------ src/librustdoc/clean/mod.rs | 22 +------------------- src/libsyntax/attr.rs | 21 +++++++++---------- src/libsyntax_pos/lib.rs | 4 ++++ 7 files changed, 30 insertions(+), 60 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 0a1e7005f9fb9..27e1d0520dc9a 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -367,18 +367,18 @@ pub fn gather_attr(attr: &ast::Attribute) let meta = &attr.node.value; let metas = if let Some(metas) = meta.meta_item_list() { - metas - } else { - out.push(Err(meta.span)); - return out; - }; + metas + } else { + out.push(Err(meta.span)); + return out; + }; for meta in metas { out.push(if meta.is_word() { - Ok((meta.name().clone(), level, meta.span)) - } else { - Err(meta.span) - }); + Ok((meta.name().clone(), level, meta.span)) + } else { + Err(meta.span) + }); } out diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 9df1dea45671f..07a2605026abe 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -394,11 +394,10 @@ fn check_cfg(sopts: &config::Options, let mut saw_invalid_predicate = false; for item in sopts.cfg.iter() { if item.is_meta_item_list() { - saw_invalid_predicate = true; saw_invalid_predicate = true; handler.emit(&MultiSpan::new(), &format!("invalid predicate in --cfg command line argument: `{}`", - pred), + item.name()), errors::Level::Fatal); } } @@ -651,10 +650,8 @@ impl RustcDefaultCalls { if cfg.is_word() { println!("{}", cfg.name()); } else if cfg.is_value_str() { - let rhs = cfg.value_str(); - match rhs { - Some(s) => println!("{}=\"{}\"", cfg.name(), s), - None => continue, + if let Some(s) = cfg.value_str() { + println!("{}=\"{}\"", cfg.name(), s); } } else if cfg.is_meta_item_list() { // Right now there are not and should not be any diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 0d327414c8fc5..774c5ca6d6b23 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -114,9 +114,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { id = Some(meta_item.name().clone()); } else { // FIXME better-encapsulate meta_item (don't directly access `node`) - self.tcx.sess.span_err( - meta_item.span(), - &format!("unexpected meta-item {:?}", meta_item.node)); + span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) } } let id = id.unwrap_or(InternedString::new(ID)); @@ -133,9 +131,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { id = Some(meta_item.name().clone()); } else { // FIXME better-encapsulate meta_item (don't directly access `node`) - self.tcx.sess.span_err( - meta_item.span(), - &format!("unexpected meta-item {:?}", meta_item.node)); + span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) } } let dep_node = match dep_node_interned { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a498004b390a4..7547e28625c18 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -298,13 +298,7 @@ impl MissingDoc { } } - let has_doc = attrs.iter().any(|a| { - if a.is_value_str() && a.name() == "doc" { - true - } else { - false - } - }); + let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); if !has_doc { cx.span_lint(MISSING_DOCS, sp, &format!("missing documentation for {}", desc)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8d69c55ecf124..6883c22d67525 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -504,7 +504,7 @@ impl Clean for ast::MetaItem { NameValue(self.name().to_string(), v.to_string()) } else { // must be a list let l = self.meta_item_list().unwrap(); - List(self.name().to_string(), l.clean(cx)) + List(self.name().to_string(), l.clean(cx)) } } } @@ -2589,26 +2589,6 @@ impl ToSource for syntax_pos::Span { } } -// fn lit_to_string(lit: &ast::Lit) -> String { -// match lit.node { -// ast::LitKind::Str(ref st, _) => st.to_string(), -// ast::LitKind::ByteStr(ref data) => format!("{:?}", data), -// ast::LitKind::Byte(b) => { -// let mut res = String::from("b'"); -// for c in (b as char).escape_default() { -// res.push(c); -// } -// res.push('\''); -// res -// }, -// ast::LitKind::Char(c) => format!("'{}'", c), -// ast::LitKind::Int(i, _t) => i.to_string(), -// ast::LitKind::Float(ref f, _t) => f.to_string(), -// ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(), -// ast::LitKind::Bool(b) => b.to_string(), -// } -// } - fn name_from_pat(p: &hir::Pat) -> String { use rustc::hir::*; debug!("Trying to get a name from pattern: {:?}", p); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 8bd3f5195ccd8..b622f6861b383 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -94,10 +94,16 @@ pub trait AttrMetaMethods { /// Indicates if the attribute is a Word. fn is_word(&self) -> bool; + /// Indicates if the attribute is a Value String. - fn is_value_str(&self) -> bool; + fn is_value_str(&self) -> bool { + self.value_str().is_some() + } + /// Indicates if the attribute is a Meta-Item List. - fn is_meta_item_list(&self) -> bool; + fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } fn span(&self) -> Span; } @@ -119,9 +125,6 @@ impl AttrMetaMethods for Attribute { } fn is_word(&self) -> bool { self.meta().is_word() } - fn is_value_str(&self) -> bool { self.meta().is_value_str() } - - fn is_meta_item_list(&self) -> bool { self.meta().is_meta_item_list() } fn span(&self) -> Span { self.meta().span } } @@ -161,10 +164,6 @@ impl AttrMetaMethods for MetaItem { } } - fn is_value_str(&self) -> bool { self.value_str().is_some() } - - fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } - fn span(&self) -> Span { self.span } } @@ -240,7 +239,7 @@ pub fn mk_word_item(name: InternedString) -> P { pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Lit) -> P { - P(respan(sp,MetaItemKind::NameValue(name, value))) + P(respan(sp, MetaItemKind::NameValue(name, value))) } pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec>) @@ -249,7 +248,7 @@ pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec P { - P(respan(sp,MetaItemKind::Word(name))) + P(respan(sp, MetaItemKind::Word(name))) } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index c96be8fec2b02..b1ec7fd0ab896 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -254,6 +254,10 @@ 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 5e390322c3ca016469eca9b5dc8ce761a9786a0b Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Mon, 25 Jul 2016 14:19:14 -0700 Subject: [PATCH 105/150] Rename infcx lifetimes in inference relations --- src/librustc/infer/bivariate.rs | 12 ++++++------ src/librustc/infer/combine.rs | 24 ++++++++++++------------ src/librustc/infer/equate.rs | 12 ++++++------ src/librustc/infer/glb.rs | 16 ++++++++-------- src/librustc/infer/lub.rs | 16 ++++++++-------- src/librustc/infer/sub.rs | 12 ++++++------ 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index 96b14a6c321cd..610e25e0f8a8d 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -32,20 +32,20 @@ use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Relate, RelateResult, TypeRelation}; -pub struct Bivariate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Bivariate<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: CombineFields<'infcx, 'gcx, 'tcx> } -impl<'a, 'gcx, 'tcx> Bivariate<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Bivariate<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> Bivariate<'infcx, 'gcx, 'tcx> { + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Bivariate<'infcx, 'gcx, 'tcx> { Bivariate { fields: fields } } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Bivariate<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Bivariate" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index c9235d063cba0..36ea228956d4c 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -52,21 +52,21 @@ use syntax::ast; use syntax_pos::Span; #[derive(Clone)] -pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, +pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>, pub a_is_expected: bool, pub trace: TypeTrace<'tcx>, pub cause: Option, pub obligations: PredicateObligations<'tcx>, } -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_tys(&self, relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> - where R: TypeRelation<'a, 'gcx, 'tcx> + where R: TypeRelation<'infcx, 'gcx, 'tcx> { let a_is_expected = relation.a_is_expected(); @@ -150,35 +150,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn switch_expected(&self) -> CombineFields<'a, 'gcx, 'tcx> { + pub fn switch_expected(&self) -> CombineFields<'infcx, 'gcx, 'tcx> { CombineFields { a_is_expected: !self.a_is_expected, ..(*self).clone() } } - pub fn equate(&self) -> Equate<'a, 'gcx, 'tcx> { + pub fn equate(&self) -> Equate<'infcx, 'gcx, 'tcx> { Equate::new(self.clone()) } - pub fn bivariate(&self) -> Bivariate<'a, 'gcx, 'tcx> { + pub fn bivariate(&self) -> Bivariate<'infcx, 'gcx, 'tcx> { Bivariate::new(self.clone()) } - pub fn sub(&self) -> Sub<'a, 'gcx, 'tcx> { + pub fn sub(&self) -> Sub<'infcx, 'gcx, 'tcx> { Sub::new(self.clone()) } - pub fn lub(&self) -> Lub<'a, 'gcx, 'tcx> { + pub fn lub(&self) -> Lub<'infcx, 'gcx, 'tcx> { Lub::new(self.clone()) } - pub fn glb(&self) -> Glb<'a, 'gcx, 'tcx> { + pub fn glb(&self) -> Glb<'infcx, 'gcx, 'tcx> { Glb::new(self.clone()) } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 408f22cf15c77..f3dc44e8efd08 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -18,12 +18,12 @@ use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::PredicateObligations; /// Ensures `a` is made equal to `b`. Returns `a` on success. -pub struct Equate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Equate<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: CombineFields<'infcx, 'gcx, 'tcx> } -impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Equate<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> Equate<'infcx, 'gcx, 'tcx> { + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Equate<'infcx, 'gcx, 'tcx> { Equate { fields: fields } } @@ -32,10 +32,10 @@ impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Equate" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index b7085f0829f8a..51386083ab3c2 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -18,12 +18,12 @@ use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::PredicateObligations; /// "Greatest lower bound" (common subtype) -pub struct Glb<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Glb<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: CombineFields<'infcx, 'gcx, 'tcx> } -impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Glb<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> Glb<'infcx, 'gcx, 'tcx> { + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Glb<'infcx, 'gcx, 'tcx> { Glb { fields: fields } } @@ -32,10 +32,10 @@ impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Glb" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } @@ -75,8 +75,8 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { - fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, 'tcx> { + fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index bd46f3a26a2de..bd87c91dea58c 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -18,12 +18,12 @@ use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::PredicateObligations; /// "Least upper bound" (common supertype) -pub struct Lub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Lub<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: CombineFields<'infcx, 'gcx, 'tcx> } -impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Lub<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> Lub<'infcx, 'gcx, 'tcx> { + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Lub<'infcx, 'gcx, 'tcx> { Lub { fields: fields } } @@ -32,10 +32,10 @@ impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Lub" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } @@ -75,8 +75,8 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { - fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, 'tcx> { + fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 680dd0d63556b..404763b3bd30a 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -19,12 +19,12 @@ use traits::PredicateObligations; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx>, +pub struct Sub<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: CombineFields<'infcx, 'gcx, 'tcx>, } -impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> { - pub fn new(f: CombineFields<'a, 'gcx, 'tcx>) -> Sub<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> Sub<'infcx, 'gcx, 'tcx> { + pub fn new(f: CombineFields<'infcx, 'gcx, 'tcx>) -> Sub<'infcx, 'gcx, 'tcx> { Sub { fields: f } } @@ -33,9 +33,9 @@ impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Sub" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.infcx.tcx } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } fn with_cause(&mut self, cause: Cause, f: F) -> R From dddaf34cfc3d8c143d4a7cd59349c7da1a2e4622 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Mon, 25 Jul 2016 15:07:57 -0700 Subject: [PATCH 106/150] Move `a_is_expected` out of `CombineFields` --- src/librustc/infer/bivariate.rs | 13 +++++---- src/librustc/infer/combine.rs | 39 ++++++++++--------------- src/librustc/infer/equate.rs | 17 ++++++----- src/librustc/infer/glb.rs | 19 ++++++------ src/librustc/infer/higher_ranked/mod.rs | 19 ++++++------ src/librustc/infer/lub.rs | 19 ++++++------ src/librustc/infer/mod.rs | 15 +++++----- src/librustc/infer/sub.rs | 27 ++++++++++------- 8 files changed, 86 insertions(+), 82 deletions(-) diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index 610e25e0f8a8d..d790391cd4c40 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -33,12 +33,13 @@ use ty::TyVar; use ty::relate::{Relate, RelateResult, TypeRelation}; pub struct Bivariate<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx> + fields: CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } impl<'infcx, 'gcx, 'tcx> Bivariate<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Bivariate<'infcx, 'gcx, 'tcx> { - Bivariate { fields: fields } + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Bivariate<'infcx, 'gcx, 'tcx> { + Bivariate { fields: fields, a_is_expected: a_is_expected } } } @@ -47,7 +48,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Bivariate<'infcx, fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -86,12 +87,12 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Bivariate<'infcx, } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, 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.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 36ea228956d4c..41369299e726f 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -54,7 +54,6 @@ use syntax_pos::Span; #[derive(Clone)] pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>, - pub a_is_expected: bool, pub trace: TypeTrace<'tcx>, pub cause: Option, pub obligations: PredicateObligations<'tcx>, @@ -155,37 +154,31 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn switch_expected(&self) -> CombineFields<'infcx, 'gcx, 'tcx> { - CombineFields { - a_is_expected: !self.a_is_expected, - ..(*self).clone() - } - } - - pub fn equate(&self) -> Equate<'infcx, 'gcx, 'tcx> { - Equate::new(self.clone()) + pub fn equate(&self, a_is_expected: bool) -> Equate<'infcx, 'gcx, 'tcx> { + Equate::new(self.clone(), a_is_expected) } - pub fn bivariate(&self) -> Bivariate<'infcx, 'gcx, 'tcx> { - Bivariate::new(self.clone()) + pub fn bivariate(&self, a_is_expected: bool) -> Bivariate<'infcx, 'gcx, 'tcx> { + Bivariate::new(self.clone(), a_is_expected) } - pub fn sub(&self) -> Sub<'infcx, 'gcx, 'tcx> { - Sub::new(self.clone()) + pub fn sub(&self, a_is_expected: bool) -> Sub<'infcx, 'gcx, 'tcx> { + Sub::new(self.clone(), a_is_expected) } - pub fn lub(&self) -> Lub<'infcx, 'gcx, 'tcx> { - Lub::new(self.clone()) + pub fn lub(&self, a_is_expected: bool) -> Lub<'infcx, 'gcx, 'tcx> { + Lub::new(self.clone(), a_is_expected) } - pub fn glb(&self) -> Glb<'infcx, 'gcx, 'tcx> { - Glb::new(self.clone()) + pub fn glb(&self, a_is_expected: bool) -> Glb<'infcx, 'gcx, 'tcx> { + Glb::new(self.clone(), a_is_expected) } pub fn instantiate(&self, a_ty: Ty<'tcx>, dir: RelationDir, - b_vid: ty::TyVid) + b_vid: ty::TyVid, + a_is_expected: bool) -> RelateResult<'tcx, ()> { let mut stack = Vec::new(); @@ -255,10 +248,10 @@ 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().relate(&a_ty, &b_ty), - EqTo => self.equate().relate(&a_ty, &b_ty), - SubtypeOf => self.sub().relate(&a_ty, &b_ty), - SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty), + BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_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(ty::Contravariant, &a_ty, &b_ty), }?; } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index f3dc44e8efd08..7980ba91c5e01 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -19,12 +19,13 @@ use traits::PredicateObligations; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx> + fields: CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } impl<'infcx, 'gcx, 'tcx> Equate<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Equate<'infcx, 'gcx, 'tcx> { - Equate { fields: fields } + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Equate<'infcx, 'gcx, 'tcx> { + Equate { fields: fields, a_is_expected: a_is_expected } } pub fn obligations(self) -> PredicateObligations<'tcx> { @@ -37,7 +38,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'infcx, 'gc fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, _: ty::Variance, @@ -63,12 +64,12 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'infcx, 'gc } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id)?; + self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id)?; + self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?; Ok(a) } @@ -93,7 +94,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'infcx, 'gc -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_sub(a, b)?; - self.fields.higher_ranked_sub(b, a) + self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; + self.fields.higher_ranked_sub(b, a, self.a_is_expected) } } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 51386083ab3c2..7893846b21457 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -19,12 +19,13 @@ use traits::PredicateObligations; /// "Greatest lower bound" (common subtype) pub struct Glb<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx> + fields: CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } impl<'infcx, 'gcx, 'tcx> Glb<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Glb<'infcx, 'gcx, 'tcx> { - Glb { fields: fields } + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Glb<'infcx, 'gcx, 'tcx> { + Glb { fields: fields, a_is_expected: a_is_expected } } pub fn obligations(self) -> PredicateObligations<'tcx> { @@ -37,7 +38,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -46,10 +47,10 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate().relate(a, b), + ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.lub().relate(a, b), + ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } } @@ -71,7 +72,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_glb(a, b) + self.fields.higher_ranked_glb(a, b, self.a_is_expected) } } @@ -81,7 +82,7 @@ impl<'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, 't } fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); + let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&v, &a)?; sub.relate(&v, &b)?; Ok(()) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 03a09917c5343..386c1ba272f3c 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -40,7 +40,7 @@ pub struct HrMatchResult { } impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn higher_ranked_sub(&self, a: &Binder, b: &Binder) + pub fn higher_ranked_sub(&self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("b_prime={:?}", b_prime); // Compare types now that bound regions have been replaced. - let result = self.sub().relate(&a_prime, &b_prime)?; + let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?; + self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?; // We are finished with the skolemized regions now so pop // them off. @@ -109,7 +109,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { pub fn higher_ranked_match(&self, span: Span, a_pair: &Binder<(T, U)>, - b_match: &T) + b_match: &T, + a_is_expected: bool) -> RelateResult<'tcx, HrMatchResult> where T: Relate<'tcx>, U: TypeFoldable<'tcx> @@ -129,7 +130,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("higher_ranked_match: skol_map={:?}", skol_map); // Equate types now that bound regions have been replaced. - try!(self.equate().relate(&a_match, &b_match)); + try!(self.equate(a_is_expected).relate(&a_match, &b_match)); // Map each skolemized region to a vector of other regions that it // must be equated with. (Note that this vector may include other @@ -221,7 +222,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { }); } - pub fn higher_ranked_lub(&self, a: &Binder, b: &Binder) + pub fn higher_ranked_lub(&self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -239,7 +240,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Collect constraints. let result0 = - self.lub().relate(&a_with_fresh, &b_with_fresh)?; + self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; let result0 = self.infcx.resolve_type_vars_if_possible(&result0); debug!("lub result0 = {:?}", result0); @@ -311,7 +312,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } } - pub fn higher_ranked_glb(&self, a: &Binder, b: &Binder) + pub fn higher_ranked_glb(&self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -333,7 +334,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Collect constraints. let result0 = - self.glb().relate(&a_with_fresh, &b_with_fresh)?; + self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; let result0 = self.infcx.resolve_type_vars_if_possible(&result0); debug!("glb result0 = {:?}", result0); diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index bd87c91dea58c..6f3bd004f1fbd 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -19,12 +19,13 @@ use traits::PredicateObligations; /// "Least upper bound" (common supertype) pub struct Lub<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx> + fields: CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } impl<'infcx, 'gcx, 'tcx> Lub<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>) -> Lub<'infcx, 'gcx, 'tcx> { - Lub { fields: fields } + pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Lub<'infcx, 'gcx, 'tcx> { + Lub { fields: fields, a_is_expected: a_is_expected } } pub fn obligations(self) -> PredicateObligations<'tcx> { @@ -37,7 +38,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -46,10 +47,10 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate().relate(a, b), + ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.glb().relate(a, b), + ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } @@ -71,7 +72,7 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_lub(a, b) + self.fields.higher_ranked_lub(a, b, self.a_is_expected) } } @@ -81,7 +82,7 @@ impl<'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, 't } fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); + let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&a, &v)?; sub.relate(&b, &v)?; Ok(()) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4e0c5b58b64d1..9ee0da4d0edd6 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -799,11 +799,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return variables; } - fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + fn combine_fields(&'a self, trace: TypeTrace<'tcx>) -> CombineFields<'a, 'gcx, 'tcx> { CombineFields { infcx: self, - a_is_expected: a_is_expected, trace: trace, cause: None, obligations: PredicateObligations::new(), @@ -814,7 +813,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut equate = self.combine_fields(a_is_expected, trace).equate(); + let mut equate = self.combine_fields(trace).equate(a_is_expected); let result = equate.relate(a, b); result.map(|t| InferOk { value: t, obligations: equate.obligations() }) } @@ -823,7 +822,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut sub = self.combine_fields(a_is_expected, trace).sub(); + let mut sub = self.combine_fields(trace).sub(a_is_expected); let result = sub.relate(a, b); result.map(|t| InferOk { value: t, obligations: sub.obligations() }) } @@ -832,7 +831,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut lub = self.combine_fields(a_is_expected, trace).lub(); + let mut lub = self.combine_fields(trace).lub(a_is_expected); let result = lub.relate(a, b); result.map(|t| InferOk { value: t, obligations: lub.obligations() }) } @@ -841,7 +840,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut glb = self.combine_fields(a_is_expected, trace).glb(); + let mut glb = self.combine_fields(trace).glb(a_is_expected); let result = glb.relate(a, b); result.map(|t| InferOk { value: t, obligations: glb.obligations() }) } @@ -1646,8 +1645,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty)); - let combine = self.combine_fields(true, trace); - let result = combine.higher_ranked_match(span, &match_pair, &match_b)?; + let combine = self.combine_fields(trace); + let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?; Ok(InferOk { value: result, obligations: combine.obligations }) } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 404763b3bd30a..7a25ea9f3c2be 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -21,22 +21,30 @@ use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. pub struct Sub<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { fields: CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } impl<'infcx, 'gcx, 'tcx> Sub<'infcx, 'gcx, 'tcx> { - pub fn new(f: CombineFields<'infcx, 'gcx, 'tcx>) -> Sub<'infcx, 'gcx, 'tcx> { - Sub { fields: f } + pub fn new(f: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Sub<'infcx, 'gcx, 'tcx> { + Sub { fields: f, a_is_expected: a_is_expected } } pub fn obligations(self) -> PredicateObligations<'tcx> { self.fields.obligations } + + fn with_expected_switched R>(&mut self, f: F) -> R { + self.a_is_expected = !self.a_is_expected; + let result = f(self); + self.a_is_expected = !self.a_is_expected; + result + } } impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Sub" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn with_cause(&mut self, cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R @@ -56,10 +64,10 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'infcx, 'gcx, -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate().relate(a, b), + ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.switch_expected().sub().relate(b, a), + ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), } } @@ -80,12 +88,11 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'infcx, 'gcx, } (&ty::TyInfer(TyVar(a_id)), _) => { self.fields - .switch_expected() - .instantiate(b, SupertypeOf, a_id)?; + .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id)?; + self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; Ok(a) } @@ -116,6 +123,6 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'infcx, 'gcx, -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_sub(a, b) + self.fields.higher_ranked_sub(a, b, self.a_is_expected) } } From e88df943dd7d8dba40d1bfadec5740309f6bb6e9 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Mon, 25 Jul 2016 16:37:30 -0700 Subject: [PATCH 107/150] Use &mut for CombineFields in inference relations --- src/librustc/infer/bivariate.rs | 10 +++++----- src/librustc/infer/combine.rs | 22 ++++++++++----------- src/librustc/infer/equate.rs | 15 +++++--------- src/librustc/infer/glb.rs | 19 +++++++----------- src/librustc/infer/higher_ranked/mod.rs | 8 ++++---- src/librustc/infer/lattice.rs | 2 +- src/librustc/infer/lub.rs | 19 +++++++----------- src/librustc/infer/mod.rs | 26 ++++++++++++------------- src/librustc/infer/sub.rs | 15 +++++--------- 9 files changed, 58 insertions(+), 78 deletions(-) diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index d790391cd4c40..e54522b84336b 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -32,18 +32,18 @@ use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Relate, RelateResult, TypeRelation}; -pub struct Bivariate<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx>, +pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, } -impl<'infcx, 'gcx, 'tcx> Bivariate<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Bivariate<'infcx, 'gcx, 'tcx> { +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<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Bivariate<'infcx, 'gcx, 'tcx> { +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() } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 41369299e726f..fc5b52ee30a50 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -154,27 +154,27 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn equate(&self, a_is_expected: bool) -> Equate<'infcx, 'gcx, 'tcx> { - Equate::new(self.clone(), a_is_expected) + pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> { + Equate::new(self, a_is_expected) } - pub fn bivariate(&self, a_is_expected: bool) -> Bivariate<'infcx, 'gcx, 'tcx> { - Bivariate::new(self.clone(), 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(&self, a_is_expected: bool) -> Sub<'infcx, 'gcx, 'tcx> { - Sub::new(self.clone(), 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) } - pub fn lub(&self, a_is_expected: bool) -> Lub<'infcx, 'gcx, 'tcx> { - Lub::new(self.clone(), a_is_expected) + pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> { + Lub::new(self, a_is_expected) } - pub fn glb(&self, a_is_expected: bool) -> Glb<'infcx, 'gcx, 'tcx> { - Glb::new(self.clone(), a_is_expected) + pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> { + Glb::new(self, a_is_expected) } - pub fn instantiate(&self, + pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, b_vid: ty::TyVid, diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 7980ba91c5e01..09800412e0bf8 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -15,25 +15,20 @@ use super::type_variable::{EqTo}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; /// Ensures `a` is made equal to `b`. Returns `a` on success. -pub struct Equate<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx>, +pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, } -impl<'infcx, 'gcx, 'tcx> Equate<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Equate<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Equate<'combine, 'infcx, 'gcx, 'tcx> { Equate { fields: fields, a_is_expected: a_is_expected } } - - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations - } } -impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'combine, 'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Equate" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 7893846b21457..46d5991b7adbc 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -15,25 +15,20 @@ use super::Subtype; use ty::{self, Ty, TyCtxt}; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; /// "Greatest lower bound" (common subtype) -pub struct Glb<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx>, +pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, } -impl<'infcx, 'gcx, 'tcx> Glb<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Glb<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Glb<'combine, 'infcx, 'gcx, 'tcx> { Glb { fields: fields, a_is_expected: a_is_expected } } - - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations - } } -impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'combine, 'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Glb" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } @@ -76,12 +71,12 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, } } -impl<'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Glb<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Glb<'combine, 'infcx, 'gcx, 'tcx> { fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&v, &a)?; sub.relate(&v, &b)?; diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 386c1ba272f3c..743d6135fbb5b 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -40,7 +40,7 @@ pub struct HrMatchResult { } impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn higher_ranked_sub(&self, a: &Binder, b: &Binder, a_is_expected: bool) + pub fn higher_ranked_sub(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { /// NB. It should not happen that there are LBR appearing in `U` /// that do not appear in `T`. If that happens, those regions are /// unconstrained, and this routine replaces them with `'static`. - pub fn higher_ranked_match(&self, + pub fn higher_ranked_match(&mut self, span: Span, a_pair: &Binder<(T, U)>, b_match: &T, @@ -222,7 +222,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { }); } - pub fn higher_ranked_lub(&self, a: &Binder, b: &Binder, a_is_expected: bool) + pub fn higher_ranked_lub(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -312,7 +312,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } } - pub fn higher_ranked_glb(&self, a: &Binder, b: &Binder, a_is_expected: bool) + pub fn higher_ranked_glb(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index 1a2bc4b5cf2e1..eda78428e61ad 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -40,7 +40,7 @@ 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. - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 6f3bd004f1fbd..2639e06f2e5cd 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -15,25 +15,20 @@ use super::Subtype; use ty::{self, Ty, TyCtxt}; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; /// "Least upper bound" (common supertype) -pub struct Lub<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx>, +pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, } -impl<'infcx, 'gcx, 'tcx> Lub<'infcx, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Lub<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Lub<'combine, 'infcx, 'gcx, 'tcx> { Lub { fields: fields, a_is_expected: a_is_expected } } - - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations - } } -impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'combine, 'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Lub" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } @@ -76,12 +71,12 @@ impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, } } -impl<'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Lub<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Lub<'combine, 'infcx, 'gcx, 'tcx> { fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&a, &v)?; sub.relate(&b, &v)?; diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9ee0da4d0edd6..58d2b963bbf15 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -813,36 +813,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut equate = self.combine_fields(trace).equate(a_is_expected); - let result = equate.relate(a, b); - result.map(|t| InferOk { value: t, obligations: equate.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.equate(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut sub = self.combine_fields(trace).sub(a_is_expected); - let result = sub.relate(a, b); - result.map(|t| InferOk { value: t, obligations: sub.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.sub(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut lub = self.combine_fields(trace).lub(a_is_expected); - let result = lub.relate(a, b); - result.map(|t| InferOk { value: t, obligations: lub.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.lub(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut glb = self.combine_fields(trace).glb(a_is_expected); - let result = glb.relate(a, b); - result.map(|t| InferOk { value: t, obligations: glb.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.glb(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } fn start_snapshot(&self) -> CombinedSnapshot { @@ -1645,7 +1645,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty)); - let combine = self.combine_fields(trace); + let mut combine = self.combine_fields(trace); let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?; Ok(InferOk { value: result, obligations: combine.obligations }) } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 7a25ea9f3c2be..a3e50a23d3f46 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -15,24 +15,19 @@ use super::type_variable::{SubtypeOf, SupertypeOf}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: CombineFields<'infcx, 'gcx, 'tcx>, +pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, } -impl<'infcx, 'gcx, 'tcx> Sub<'infcx, 'gcx, 'tcx> { - pub fn new(f: CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Sub<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Sub<'combine, 'infcx, 'gcx, 'tcx> { Sub { fields: f, a_is_expected: a_is_expected } } - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations - } - fn with_expected_switched R>(&mut self, f: F) -> R { self.a_is_expected = !self.a_is_expected; let result = f(self); @@ -41,7 +36,7 @@ impl<'infcx, 'gcx, 'tcx> Sub<'infcx, 'gcx, 'tcx> { } } -impl<'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'combine, 'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Sub" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } fn a_is_expected(&self) -> bool { self.a_is_expected } From 4bcf013438711aaeaa00ed0424a05e13d129b74b Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Mon, 25 Jul 2016 17:46:01 -0700 Subject: [PATCH 108/150] Tidy up --- src/librustc/infer/bivariate.rs | 8 ++++++-- src/librustc/infer/combine.rs | 3 ++- src/librustc/infer/equate.rs | 8 ++++++-- src/librustc/infer/glb.rs | 12 +++++++++--- src/librustc/infer/lub.rs | 12 +++++++++--- src/librustc/infer/sub.rs | 8 ++++++-- 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index e54522b84336b..125f815feda6f 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -38,12 +38,16 @@ pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx } 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> { + 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> { +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() } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index fc5b52ee30a50..b4818f963b3ba 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -251,7 +251,8 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_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(ty::Contravariant, &a_ty, &b_ty), + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, &a_ty, &b_ty), }?; } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 09800412e0bf8..e06f7303acb29 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -23,12 +23,16 @@ pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { } impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Equate<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Equate<'combine, 'infcx, 'gcx, 'tcx> + { Equate { fields: fields, a_is_expected: a_is_expected } } } -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Equate<'combine, 'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Equate<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Equate" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 46d5991b7adbc..5dd85a31a9a20 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -23,12 +23,16 @@ pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { } impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Glb<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Glb<'combine, 'infcx, 'gcx, 'tcx> + { Glb { fields: fields, a_is_expected: a_is_expected } } } -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'combine, 'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Glb<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Glb" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } @@ -71,7 +75,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Glb<'com } } -impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Glb<'combine, 'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> + for Glb<'combine, 'infcx, 'gcx, 'tcx> +{ fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 2639e06f2e5cd..ad1b32ffaeb32 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -23,12 +23,16 @@ pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { } impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Lub<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Lub<'combine, 'infcx, 'gcx, 'tcx> + { Lub { fields: fields, a_is_expected: a_is_expected } } } -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'combine, 'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Lub<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Lub" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } @@ -71,7 +75,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Lub<'com } } -impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> for Lub<'combine, 'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> + for Lub<'combine, 'infcx, 'gcx, 'tcx> +{ fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index a3e50a23d3f46..2f7f5254727db 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -24,7 +24,9 @@ pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { } impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) -> Sub<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Sub<'combine, 'infcx, 'gcx, 'tcx> + { Sub { fields: f, a_is_expected: a_is_expected } } @@ -36,7 +38,9 @@ impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { } } -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'combine, 'infcx, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Sub<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Sub" } fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } fn a_is_expected(&self) -> bool { self.a_is_expected } From 47db8deff6b50512d1c6e702d4df6bd9027efe04 Mon Sep 17 00:00:00 2001 From: Rahiel Kasim Date: Tue, 26 Jul 2016 11:14:46 +0200 Subject: [PATCH 109/150] doc/book/trait-objects: remove empty lines at start of examples --- src/doc/book/trait-objects.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md index b31a34a0425a4..b1aee579aabc2 100644 --- a/src/doc/book/trait-objects.md +++ b/src/doc/book/trait-objects.md @@ -123,7 +123,6 @@ dispatch with trait objects by casting: # 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(); } @@ -140,7 +139,6 @@ or by coercing: # 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(); } From 1aa8dad854155221db7cec19b6105c673e4a871e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 30 Apr 2016 16:37:44 +0200 Subject: [PATCH 110/150] DoubleEndedIterator for Args The number of arguments given to a process is always known, which makes implementing DoubleEndedIterator possible. That way, the Iterator::rev() method becomes usable, among others. Signed-off-by: Sebastian Thiel Tidy for DoubleEndedIterator I chose to not create a new feature for it, even though technically, this makes me lie about the original availability of the implementation. Verify with @alexchrichton Setup feature flag for new std::env::Args iterators Add test for Args reverse iterator It's somewhat depending on the input of the test program, but made in such a way that should be somewhat flexible to changes to the way it is called. Deduplicate windows ArgsOS code for DEI DEI = DoubleEndedIterator Move env::args().rev() test to run-pass It must be controlling it's arguments for full isolation. Remove superfluous feature name Assert all arguments returned by env::args().rev() Let's be very sure it works as we expect, why take chances. Fix rval of os_string_from_ptr A trait cannot be returned, but only the corresponding object. Deref pointers to actually operate on the argument Put unsafe to correct location --- src/libstd/env.rs | 11 +++++ src/libstd/sys/unix/os.rs | 4 ++ src/libstd/sys/windows/os.rs | 27 +++++++----- .../run-pass/env-args-reverse-iterator.rs | 44 +++++++++++++++++++ 4 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 src/test/run-pass/env-args-reverse-iterator.rs diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 6956dc0d901a4..01bc733d440eb 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -587,6 +587,13 @@ impl ExactSizeIterator for Args { fn len(&self) -> usize { self.inner.len() } } +#[stable(feature = "env_iterators", since = "1.11.0")] +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|s| s.into_string().unwrap()) + } +} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; @@ -599,6 +606,10 @@ impl ExactSizeIterator for ArgsOs { fn len(&self) -> usize { self.inner.len() } } +#[stable(feature = "env_iterators", since = "1.11.0")] +impl DoubleEndedIterator for ArgsOs { + fn next_back(&mut self) -> Option { self.inner.next_back() } +} /// Constants associated with the current target #[stable(feature = "env", since = "1.0.0")] pub mod consts { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 21ce6b19ceb13..a8cb1ce49d2d9 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -308,6 +308,10 @@ impl ExactSizeIterator for Args { fn len(&self) -> usize { self.iter.len() } } +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + /// Returns the command line arguments /// /// Returns a list of the command line arguments. diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 32ca32e76cb62..0cea7f81e3632 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -278,23 +278,30 @@ pub struct Args { cur: *mut *mut u16, } +unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { + let mut len = 0; + while *ptr.offset(len) != 0 { len += 1; } + + // Push it onto the list. + let ptr = ptr as *const u16; + let buf = slice::from_raw_parts(ptr, len as usize); + OsStringExt::from_wide(buf) +} + impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option { - self.range.next().map(|i| unsafe { - let ptr = *self.cur.offset(i); - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len as usize); - OsStringExt::from_wide(buf) - }) + self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } } +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) + } +} + impl ExactSizeIterator for Args { fn len(&self) -> usize { self.range.len() } } diff --git a/src/test/run-pass/env-args-reverse-iterator.rs b/src/test/run-pass/env-args-reverse-iterator.rs new file mode 100644 index 0000000000000..d22fa6494f036 --- /dev/null +++ b/src/test/run-pass/env-args-reverse-iterator.rs @@ -0,0 +1,44 @@ +// 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::env::args; +use std::process::Command; + +fn assert_reverse_iterator_for_program_arguments(program_name: &str) { + let args: Vec<_> = args().rev().collect(); + + assert!(args.len() == 4); + assert_eq!(args[0], "c"); + assert_eq!(args[1], "b"); + assert_eq!(args[2], "a"); + assert_eq!(args[3], program_name); + + println!("passed"); +} + +fn main() { + let mut args = args(); + let me = args.next().unwrap(); + + if let Some(_) = args.next() { + assert_reverse_iterator_for_program_arguments(&me); + return + } + + let output = Command::new(&me) + .arg("a") + .arg("b") + .arg("c") + .output() + .unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); +} From 68efea08fa1cf800b3b76683992ec77a89323d53 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 26 Jul 2016 01:39:54 +0200 Subject: [PATCH 111/150] Restore `char::escape_default` and add `char::escape` instead --- src/libcollections/lib.rs | 1 + src/libcollections/str.rs | 8 ++++++ src/libcollectionstest/str.rs | 16 +++++++++++- src/libcore/char.rs | 38 +++++++++++++++++++++++++++- src/libcore/fmt/mod.rs | 4 +-- src/libcoretest/char.rs | 47 +++++++++++++++++++++++++++++++++-- src/librustc_unicode/char.rs | 37 ++++++++++++++++++++++++++- src/librustc_unicode/lib.rs | 1 + 8 files changed, 145 insertions(+), 7 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index f027d074cb6f0..333219bc5e5b0 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -33,6 +33,7 @@ #![feature(allow_internal_unstable)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(char_escape)] #![feature(core_intrinsics)] #![feature(dropck_parametricity)] #![feature(fmt_internals)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 55308a46f0ac5..a63ea9d3ec777 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1697,6 +1697,14 @@ impl str { return s; } + /// Escapes each char in `s` with `char::escape`. + #[unstable(feature = "str_escape", + reason = "return type may change to be an iterator", + issue = "27791")] + pub fn escape(&self) -> String { + self.chars().flat_map(|c| c.escape()).collect() + } + /// Escapes each char in `s` with `char::escape_default`. #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 4d85c9d545e5a..870f8a3a1ec6f 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -704,7 +704,7 @@ fn test_escape_unicode() { } #[test] -fn test_escape_default() { +fn test_escape() { assert_eq!("abc".escape_default(), "abc"); assert_eq!("a c".escape_default(), "a c"); assert_eq!("éèê".escape_default(), "éèê"); @@ -717,6 +717,20 @@ fn test_escape_default() { assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); } +#[test] +fn test_escape_default() { + assert_eq!("abc".escape_default(), "abc"); + assert_eq!("a c".escape_default(), "a c"); + assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}"); + assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); +} + #[test] fn test_total_ord() { assert_eq!("1234".cmp("123"), Greater); diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 0d39217bd726c..3e435b47110a0 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -264,6 +264,8 @@ pub trait CharExt { fn escape_unicode(self) -> EscapeUnicode; #[stable(feature = "core", since = "1.6.0")] fn escape_default(self) -> EscapeDefault; + #[unstable(feature = "char_escape", issue = "0")] + fn escape(self) -> Escape; #[stable(feature = "core", since = "1.6.0")] fn len_utf8(self) -> usize; #[stable(feature = "core", since = "1.6.0")] @@ -316,6 +318,19 @@ impl CharExt for char { #[inline] fn escape_default(self) -> EscapeDefault { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) + }; + EscapeDefault { state: init_state } + } + + #[inline] + fn escape(self) -> Escape { let init_state = match self { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), @@ -324,7 +339,7 @@ impl CharExt for char { c if is_printable(c) => EscapeDefaultState::Char(c), c => EscapeDefaultState::Unicode(c.escape_unicode()), }; - EscapeDefault { state: init_state } + Escape(EscapeDefault { state: init_state }) } #[inline] @@ -601,6 +616,27 @@ impl ExactSizeIterator for EscapeDefault { } } +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape()`] method on [`char`]. See its +/// documentation for more. +/// +/// [`escape()`]: ../../std/primitive.char.html#method.escape +/// [`char`]: ../../std/primitive.char.html +#[unstable(feature = "char_escape", issue = "0")] +#[derive(Clone, Debug)] +pub struct Escape(EscapeDefault); + +#[unstable(feature = "char_escape", issue = "0")] +impl Iterator for Escape { + type Item = char; + fn next(&mut self) -> Option { self.0.next() } + fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +#[unstable(feature = "char_escape", issue = "0")] +impl ExactSizeIterator for Escape { } + /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. /// diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index e5eb8f21382be..3bcdce57af0d1 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1383,7 +1383,7 @@ impl Debug for str { f.write_char('"')?; let mut from = 0; for (i, c) in self.char_indices() { - let esc = c.escape_default(); + let esc = c.escape(); // If char needs escaping, flush backlog so far and write, else skip if esc.len() != 1 { f.write_str(&self[from..i])?; @@ -1409,7 +1409,7 @@ impl Display for str { impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; - for c in self.escape_default() { + for c in self.escape() { f.write_char(c)? } f.write_char('\'') diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index e01f83ed70ab0..ec757b0b5d389 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -124,9 +124,9 @@ fn test_is_digit() { } #[test] -fn test_escape_default() { +fn test_escape() { fn string(c: char) -> String { - c.escape_default().collect() + c.escape().collect() } let s = string('\n'); assert_eq!(s, "\\n"); @@ -166,6 +166,49 @@ fn test_escape_default() { assert_eq!(s, "\\u{100000}"); } +#[test] +fn test_escape_default() { + fn string(c: char) -> String { + c.escape_default().collect() + } + let s = string('\n'); + assert_eq!(s, "\\n"); + let s = string('\r'); + assert_eq!(s, "\\r"); + let s = string('\''); + assert_eq!(s, "\\'"); + let s = string('"'); + assert_eq!(s, "\\\""); + let s = string(' '); + assert_eq!(s, " "); + let s = string('a'); + assert_eq!(s, "a"); + let s = string('~'); + assert_eq!(s, "~"); + let s = string('é'); + assert_eq!(s, "\\u{e9}"); + let s = string('\x00'); + assert_eq!(s, "\\u{0}"); + let s = string('\x1f'); + assert_eq!(s, "\\u{1f}"); + let s = string('\x7f'); + assert_eq!(s, "\\u{7f}"); + let s = string('\u{80}'); + assert_eq!(s, "\\u{80}"); + let s = string('\u{ff}'); + assert_eq!(s, "\\u{ff}"); + let s = string('\u{11b}'); + assert_eq!(s, "\\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\\u{1d4b6}"); + let s = string('\u{200b}'); // zero width space + assert_eq!(s, "\\u{200b}"); + let s = string('\u{e000}'); // private use 1 + assert_eq!(s, "\\u{e000}"); + let s = string('\u{100000}'); // private use 2 + assert_eq!(s, "\\u{100000}"); +} + #[test] fn test_escape_unicode() { fn string(c: char) -> String { c.escape_unicode().collect() } diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 7445ff94eb502..683d5289ab53c 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -36,7 +36,7 @@ use tables::{conversions, derived_property, general_category, property}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDefault, EscapeUnicode}; +pub use core::char::{EncodeUtf16, EncodeUtf8, Escape, EscapeDefault, EscapeUnicode}; // unstable reexports #[unstable(feature = "decode_utf8", issue = "33906")] @@ -267,6 +267,41 @@ impl char { C::escape_unicode(self) } + /// Returns an iterator that yields the literal escape code of a `char`. + /// + /// This will escape the characters similar to the `Debug` implementations + /// of `str` or `char`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// for i in '\n'.escape_default() { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// \ + /// n + /// ``` + /// + /// Collecting into a `String`: + /// + /// ``` + /// let quote: String = '\n'.escape_default().collect(); + /// + /// assert_eq!(quote, "\\n"); + /// ``` + #[unstable(feature = "char_escape", issue = "0")] + #[inline] + pub fn escape(self) -> Escape { + C::escape(self) + } + /// Returns an iterator that yields the literal escape code of a `char`. /// /// The default is chosen with a bias toward producing literals that are diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index f91a754ab57db..8c91d3b6a929b 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -32,6 +32,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![no_std] +#![feature(char_escape)] #![feature(core_char_ext)] #![feature(decode_utf8)] #![feature(lang_items)] From 14a7f4dedcdc25c2c1abf36addc52c8a48cdb7f9 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 27 Jul 2016 03:01:48 +0800 Subject: [PATCH 112/150] Fix #35031 --- src/libcollections/fmt.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index c5312d0d9bbd9..be0ef85d6b114 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -434,37 +434,31 @@ //! in this case, if one uses the format string `{:.*}`, then the `` part refers //! to the *value* to print, and the `precision` must come in the input preceding ``. //! -//! For example, these: +//! For example, the following calls all print the same thing `Hello x is 0.01000`: //! //! ``` -//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)} +//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)} //! println!("Hello {0} is {1:.5}", "x", 0.01); //! -//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)} +//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)} //! println!("Hello {1} is {2:.0$}", 5, "x", 0.01); //! -//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)} +//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)} //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {second of next two args (0.01) with precision +//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision //! // specified in first of next two args (5)} //! println!("Hello {} is {:.*}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {arg 2 (0.01) with precision +//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision //! // specified in its predecessor (5)} //! println!("Hello {} is {2:.*}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified +//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified //! // in arg "prec" (5)} //! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); //! ``` //! -//! All print the same thing: -//! -//! ```text -//! Hello x is 0.01000 -//! ``` -//! //! While these: //! //! ``` From ec8518e4fbde1b578137883cc7c4fe6805723a3f Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Tue, 26 Jul 2016 18:53:47 -0700 Subject: [PATCH 113/150] Fix typos --- src/libpanic_unwind/dwarf/eh.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 1e9e9e30f5cfe..2284a9bbb73e1 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -108,7 +108,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { } } } - // Ip is not present in the table. This should not hapen... but it does: issie #35011. + // Ip is not present in the table. This should not happen... but it does: issue #35011. // So rather than returning EHAction::Terminate, we do this. EHAction::None } else { From a72767970adbe3600d1b66eff118ba4dd732c804 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Wed, 27 Jul 2016 13:12:35 -0400 Subject: [PATCH 114/150] Update docs for assert! and debug_assert! --- src/libcore/macros.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 43868d124a22e..e3207a0a86c4f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -32,8 +32,19 @@ macro_rules! panic { /// Ensure that a boolean expression is `true` at runtime. /// -/// This will invoke the `panic!` macro if the provided expression cannot be -/// evaluated to `true` at runtime. +/// This will ensure the termination of the program if the provided expression +/// cannot be evaluated to `true` at runtime by means of an unrecoverable error +/// (not necessarily a `panic!`, can also be an `abort`). +/// +/// Assertions are always checked in both debug and release builds, and cannot +/// be disabled. +/// +/// Unsafe code relies on `assert!` to enforce run-time invariants that, if +/// violated could lead to unsafety. +/// +/// Other use-cases of `assert!` include +/// [testing](https://doc.rust-lang.org/book/testing.html) and enforcing +/// run-time invariants in safe code (whose violation cannot result in unsafety). /// /// This macro has a second version, where a custom panic message can be provided. /// @@ -123,6 +134,13 @@ macro_rules! assert_eq { /// expensive to be present in a release build but may be helpful during /// development. /// +/// An unchecked assertion allows a program in an inconsistent state to keep +/// running, which might have unexpected consequences but does not introduce +/// unsafety as long as this only happens in safe code. The performance cost +/// of assertions, is however, not measurable in general. Replacing `assert!` +/// with `debug_assert!` is thus only encourage after thorough profiling, and +/// more importantly, only in safe code! +/// /// # Examples /// /// ``` From 9c83fa41b05dd0a2ffedc88e9b97508341e2b92a Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Fri, 15 Apr 2016 09:13:28 -0500 Subject: [PATCH 115/150] librustc_back: expose all target options via JSON Not all TargetOptions are exposed via the JSON interface to create different targets. This exposes all the missing items and reorders them to match the structure so that it is easier in the future to identify missing items. Signed-off-by: Doug Goldstein --- src/librustc_back/target/mod.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 99bc26848025e..78edcd5554122 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -434,35 +434,47 @@ impl Target { } ); } - key!(cpu); - key!(ar); + key!(is_builtin, bool); key!(linker); + key!(ar); + key!(pre_link_args, list); + key!(pre_link_objects_exe, list); + key!(pre_link_objects_dll, list); + key!(late_link_args, list); + key!(post_link_objects, list); + key!(post_link_args, list); + key!(cpu); + key!(features); + key!(dynamic_linking, bool); + key!(executables, bool); key!(relocation_model); key!(code_model); + key!(disable_redzone, bool); + key!(eliminate_frame_pointer, bool); + key!(function_sections, bool); key!(dll_prefix); key!(dll_suffix); key!(exe_suffix); key!(staticlib_prefix); key!(staticlib_suffix); - key!(features); - key!(dynamic_linking, bool); - key!(executables, bool); - key!(disable_redzone, bool); - key!(eliminate_frame_pointer, bool); - key!(function_sections, bool); key!(target_family, optional); key!(is_like_osx, bool); + key!(is_like_solaris, bool); key!(is_like_windows, bool); key!(is_like_msvc, bool); + key!(is_like_android, bool); key!(linker_is_gnu, bool); key!(has_rpath, bool); key!(no_compiler_rt, bool); key!(no_default_libraries, bool); - key!(pre_link_args, list); - key!(post_link_args, list); + key!(position_independent_executables, bool); key!(archive_format); key!(allow_asm, bool); key!(custom_unwind_resume, bool); + key!(lib_allocation_crate); + key!(exe_allocation_crate); + key!(has_elf_tls, bool); + key!(obj_is_bitcode, bool); key!(max_atomic_width, u64); base From c7b6ed27bcbe63906825d6e541a7a1f62bdd03c9 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Thu, 7 Apr 2016 22:29:01 -0500 Subject: [PATCH 116/150] librustc_back: add ToJson trait to Target Target's can already be built up from JSON files as well as built into librustc_back so this adds the ability to convert any Target back into JSON. Signed-off-by: Doug Goldstein --- src/librustc_back/target/mod.rs | 98 ++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 78edcd5554122..067885c92fdf4 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -44,7 +44,8 @@ //! the target's settings, though `target-feature` and `link-args` will *add* //! to the list specified by the target, rather than replace. -use serialize::json::Json; +use serialize::json::{Json, ToJson}; +use std::collections::BTreeMap; use std::default::Default; use std::io::prelude::*; use syntax::abi::Abi; @@ -364,7 +365,12 @@ impl Target { /// Load a target descriptor from a JSON object. pub fn from_json(obj: Json) -> Target { - // this is 1. ugly, 2. error prone. + // While ugly, this code must remain this way to retain + // compatibility with existing JSON fields and the internal + // expected naming of the Target and TargetOptions structs. + // To ensure compatibility is retained, the built-in targets + // are round-tripped through this code to catch cases where + // the JSON parser is not updated to match the structs. let get_req_field = |name: &str| { match obj.find(name) @@ -535,6 +541,94 @@ impl Target { } } +impl ToJson for Target { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + let default: TargetOptions = Default::default(); + + macro_rules! target_val { + ($attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + d.insert(name.to_string(), self.$attr.to_json()); + } ); + ($attr:ident, $key_name:expr) => ( { + let name = $key_name; + d.insert(name.to_string(), self.$attr.to_json()); + } ); + } + + macro_rules! target_option_val { + ($attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + if default.$attr != self.options.$attr { + d.insert(name.to_string(), self.options.$attr.to_json()); + } + } ); + ($attr:ident, $key_name:expr) => ( { + let name = $key_name; + if default.$attr != self.options.$attr { + d.insert(name.to_string(), self.options.$attr.to_json()); + } + } ); + } + + target_val!(llvm_target); + target_val!(target_endian); + target_val!(target_pointer_width); + target_val!(arch); + target_val!(target_os, "os"); + target_val!(target_env, "env"); + target_val!(target_vendor, "vendor"); + target_val!(arch); + target_val!(data_layout); + + target_option_val!(is_builtin); + target_option_val!(linker); + target_option_val!(ar); + target_option_val!(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!(post_link_objects); + target_option_val!(post_link_args); + target_option_val!(cpu); + target_option_val!(features); + target_option_val!(dynamic_linking); + target_option_val!(executables); + target_option_val!(relocation_model); + target_option_val!(code_model); + target_option_val!(disable_redzone); + target_option_val!(eliminate_frame_pointer); + target_option_val!(function_sections); + target_option_val!(dll_prefix); + target_option_val!(dll_suffix); + target_option_val!(exe_suffix); + target_option_val!(staticlib_prefix); + target_option_val!(staticlib_suffix); + target_option_val!(target_family); + target_option_val!(is_like_osx); + target_option_val!(is_like_solaris); + target_option_val!(is_like_windows); + target_option_val!(is_like_msvc); + target_option_val!(is_like_android); + target_option_val!(linker_is_gnu); + target_option_val!(has_rpath); + target_option_val!(no_compiler_rt); + target_option_val!(no_default_libraries); + target_option_val!(position_independent_executables); + target_option_val!(archive_format); + target_option_val!(allow_asm); + target_option_val!(custom_unwind_resume); + target_option_val!(lib_allocation_crate); + target_option_val!(exe_allocation_crate); + target_option_val!(has_elf_tls); + target_option_val!(obj_is_bitcode); + target_option_val!(max_atomic_width); + + Json::Object(d) + } +} + fn maybe_jemalloc() -> String { if cfg!(feature = "jemalloc") { "alloc_jemalloc".to_string() From eafecbf86855c30d2f6d9c518165edec4cca8248 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Sun, 24 Jul 2016 11:47:39 -0500 Subject: [PATCH 117/150] librustc_back: convert fn target() to return Result Change all the target generation functions to return a Result so that targets that are unable to be instantiated can be expressed as an Err instead of a panic!(). This should improve #33497 as well. --- src/librustc_back/target/aarch64_apple_ios.rs | 11 +++--- .../target/aarch64_linux_android.rs | 8 ++--- .../target/aarch64_unknown_linux_gnu.rs | 8 ++--- src/librustc_back/target/apple_ios_base.rs | 23 +++++++------ .../target/arm_linux_androideabi.rs | 8 ++--- .../target/arm_unknown_linux_gnueabi.rs | 8 ++--- .../target/arm_unknown_linux_gnueabihf.rs | 8 ++--- src/librustc_back/target/armv7_apple_ios.rs | 11 +++--- .../target/armv7_linux_androideabi.rs | 8 ++--- .../target/armv7_unknown_linux_gnueabihf.rs | 8 ++--- src/librustc_back/target/armv7s_apple_ios.rs | 11 +++--- .../target/asmjs_unknown_emscripten.rs | 6 ++-- src/librustc_back/target/i386_apple_ios.rs | 11 +++--- .../target/i586_pc_windows_msvc.rs | 8 ++--- .../target/i586_unknown_linux_gnu.rs | 8 ++--- src/librustc_back/target/i686_apple_darwin.rs | 8 ++--- .../target/i686_linux_android.rs | 8 ++--- .../target/i686_pc_windows_gnu.rs | 8 ++--- .../target/i686_pc_windows_msvc.rs | 8 ++--- .../target/i686_unknown_dragonfly.rs | 8 ++--- .../target/i686_unknown_freebsd.rs | 8 ++--- .../target/i686_unknown_linux_gnu.rs | 8 ++--- .../target/i686_unknown_linux_musl.rs | 8 ++--- src/librustc_back/target/le32_unknown_nacl.rs | 8 ++--- .../target/mips_unknown_linux_gnu.rs | 8 ++--- .../target/mips_unknown_linux_musl.rs | 8 ++--- .../target/mipsel_unknown_linux_gnu.rs | 8 ++--- .../target/mipsel_unknown_linux_musl.rs | 8 ++--- src/librustc_back/target/mod.rs | 34 ++++++++++--------- .../target/powerpc64_unknown_linux_gnu.rs | 8 ++--- .../target/powerpc64le_unknown_linux_gnu.rs | 8 ++--- .../target/powerpc_unknown_linux_gnu.rs | 8 ++--- .../target/x86_64_apple_darwin.rs | 8 ++--- src/librustc_back/target/x86_64_apple_ios.rs | 11 +++--- .../target/x86_64_pc_windows_gnu.rs | 8 ++--- .../target/x86_64_pc_windows_msvc.rs | 8 ++--- .../target/x86_64_rumprun_netbsd.rs | 8 ++--- .../target/x86_64_sun_solaris.rs | 8 ++--- .../target/x86_64_unknown_bitrig.rs | 8 ++--- .../target/x86_64_unknown_dragonfly.rs | 8 ++--- .../target/x86_64_unknown_freebsd.rs | 8 ++--- .../target/x86_64_unknown_linux_gnu.rs | 8 ++--- .../target/x86_64_unknown_linux_musl.rs | 8 ++--- .../target/x86_64_unknown_netbsd.rs | 8 ++--- .../target/x86_64_unknown_openbsd.rs | 8 ++--- 45 files changed, 212 insertions(+), 202 deletions(-) diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 481338d1cee56..6530ccb0630db 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::Arm64)); + Ok(Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,7 +26,7 @@ pub fn target() -> Target { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, max_atomic_width: 128, - .. opts(Arch::Arm64) + .. base }, - } + }) } diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 81be546e0c89d..307823137a710 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.max_atomic_width = 128; // As documented in http://developer.android.com/ndk/guides/cpu-features.html // the neon (ASIMD) and FP must exist on all android aarch64 targets. base.features = "+neon,+fp-armv8".to_string(); - Target { + Ok(Target { llvm_target: "aarch64-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index aec1bae60c812..14d0c8bedec1c 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.max_atomic_width = 128; - Target { + Ok(Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -23,5 +23,5 @@ pub fn target() -> Target { target_os: "linux".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index d182fd9605640..8bd9feabdbebe 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -36,7 +36,7 @@ impl Arch { } } -pub fn get_sdk_root(sdk_name: &str) -> String { +pub fn get_sdk_root(sdk_name: &str) -> Result { let res = Command::new("xcrun") .arg("--show-sdk-path") .arg("-sdk") @@ -55,12 +55,12 @@ pub fn get_sdk_root(sdk_name: &str) -> String { }); match res { - Ok(output) => output.trim().to_string(), - Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e) + Ok(output) => Ok(output.trim().to_string()), + Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)) } } -fn pre_link_args(arch: Arch) -> Vec { +fn build_pre_link_args(arch: Arch) -> Result, String> { let sdk_name = match arch { Armv7 | Armv7s | Arm64 => "iphoneos", I386 | X86_64 => "iphonesimulator" @@ -68,8 +68,10 @@ fn pre_link_args(arch: Arch) -> Vec { let arch_name = arch.to_string(); - vec!["-arch".to_string(), arch_name.to_string(), - "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)] + let sdk_root = try!(get_sdk_root(sdk_name)); + + Ok(vec!["-arch".to_string(), arch_name.to_string(), + "-Wl,-syslibroot".to_string(), sdk_root]) } fn target_cpu(arch: Arch) -> String { @@ -82,13 +84,14 @@ fn target_cpu(arch: Arch) -> String { }.to_string() } -pub fn opts(arch: Arch) -> TargetOptions { - TargetOptions { +pub fn opts(arch: Arch) -> Result { + let pre_link_args = try!(build_pre_link_args(arch)); + Ok(TargetOptions { cpu: target_cpu(arch), dynamic_linking: false, executables: true, - pre_link_args: pre_link_args(arch), + pre_link_args: pre_link_args, has_elf_tls: false, .. super::apple_base::opts() - } + }) } diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index e1b170422c60d..f3a18b13c6783 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+vfp3,+d16".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "arm-linux-androideabi".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 60c4a7c3c90ce..e666a8460e5ea 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { features: "+v6".to_string(), .. base }, - } + }) } diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index 72128e30641c6..d65c89abc2064 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { features: "+v6,+vfp2".to_string(), .. base } - } + }) } diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index a2486a1330a53..a806204d0a6bc 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::Armv7)); + Ok(Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -24,7 +25,7 @@ pub fn target() -> Target { options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), max_atomic_width: 64, - .. opts(Arch::Armv7) + .. base } - } + }) } diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index fd8f35da16f61..1c59262e04198 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+thumb2,+vfp3,+d16".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "armv7-none-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 7bcca3a3934be..52269f0cd4a08 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let base = super::linux_base::opts(); - Target { + Ok(Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -28,6 +28,6 @@ pub fn target() -> Target { max_atomic_width: 64, .. base } - } + }) } diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index e5379aa1b42cd..aaa3570fa62ee 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::Armv7s)); + Ok(Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -24,7 +25,7 @@ pub fn target() -> Target { options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), max_atomic_width: 64, - .. opts(Arch::Armv7s) + .. base } - } + }) } diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index e6200177944bb..07eb191471c46 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -10,7 +10,7 @@ use super::{Target, TargetOptions}; -pub fn target() -> Target { +pub fn target() -> Result { let opts = TargetOptions { linker: "emcc".to_string(), ar: "emar".to_string(), @@ -25,7 +25,7 @@ pub fn target() -> Target { max_atomic_width: 32, .. Default::default() }; - Target { + Ok(Target { llvm_target: "asmjs-unknown-emscripten".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -35,5 +35,5 @@ pub fn target() -> Target { data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "asmjs".to_string(), options: opts, - } + }) } diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index cf4020eeb5874..f391d4118ea74 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::I386)); + Ok(Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -23,7 +24,7 @@ pub fn target() -> Target { target_vendor: "apple".to_string(), options: TargetOptions { max_atomic_width: 64, - .. opts(Arch::I386) + .. base } - } + }) } diff --git a/src/librustc_back/target/i586_pc_windows_msvc.rs b/src/librustc_back/target/i586_pc_windows_msvc.rs index 12bed370eae94..445ee6c412283 100644 --- a/src/librustc_back/target/i586_pc_windows_msvc.rs +++ b/src/librustc_back/target/i586_pc_windows_msvc.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::TargetResult; -pub fn target() -> Target { - let mut base = super::i686_pc_windows_msvc::target(); +pub fn target() -> TargetResult { + let mut base = try!(super::i686_pc_windows_msvc::target()); base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-pc-windows-msvc".to_string(); - return base + Ok(base) } diff --git a/src/librustc_back/target/i586_unknown_linux_gnu.rs b/src/librustc_back/target/i586_unknown_linux_gnu.rs index 6eb6455638190..1ca8606149bff 100644 --- a/src/librustc_back/target/i586_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i586_unknown_linux_gnu.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::TargetResult; -pub fn target() -> Target { - let mut base = super::i686_unknown_linux_gnu::target(); +pub fn target() -> TargetResult { + let mut base = try!(super::i686_unknown_linux_gnu::target()); base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-unknown-linux-gnu".to_string(); - return base + Ok(base) } diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index 302691e9a5922..4876a3489d470 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "yonah".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-apple-darwin".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "apple".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index 2376de123980b..1de629238a13c 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.max_atomic_width = 64; @@ -19,7 +19,7 @@ pub fn target() -> Target { base.cpu = "pentiumpro".to_string(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string(); - Target { + Ok(Target { llvm_target: "i686-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -29,5 +29,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), 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 c2cc624c9f9e6..2c19b8109c362 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; @@ -19,7 +19,7 @@ pub fn target() -> Target { // space available to x86 Windows binaries on x86_64. base.pre_link_args.push("-Wl,--large-address-aware".to_string()); - Target { + Ok(Target { llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -29,5 +29,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "pc".to_string(), 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 8c1bacc280767..cb02fcc308c2d 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; @@ -24,7 +24,7 @@ pub fn target() -> Target { // https://msdn.microsoft.com/en-us/library/9a89h429.aspx base.pre_link_args.push("/SAFESEH".to_string()); - Target { + Ok(Target { llvm_target: "i686-pc-windows-msvc".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -34,5 +34,5 @@ pub fn target() -> Target { target_env: "msvc".to_string(), target_vendor: "pc".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index 6446ac45f7d6e..f96ec004b481e 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-dragonfly".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index a7903d5db6413..3489ecfe614d9 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-freebsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), 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 7813d5570762d..f2e865c015e35 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), 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 5274429583742..a0a8de46e2f59 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_back/target/i686_unknown_linux_musl.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); base.pre_link_args.push("-Wl,-melf_i386".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-linux-musl".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index f4f0262d476da..25132f8a044d6 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use super::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let opts = TargetOptions { linker: "pnacl-clang".to_string(), ar: "pnacl-ar".to_string(), @@ -28,7 +28,7 @@ pub fn target() -> Target { max_atomic_width: 32, .. Default::default() }; - Target { + Ok(Target { llvm_target: "le32-unknown-nacl".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -38,5 +38,5 @@ pub fn target() -> Target { data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(), arch: "le32".to_string(), options: opts, - } + }) } diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index ceb17e53a5552..ab967f6b40fbe 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mips-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { max_atomic_width: 32, ..super::linux_base::opts() }, - } + }) } diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index 35366659d581f..4a69bce53bc97 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mips-unknown-linux-musl".to_string(), target_endian: "big".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { max_atomic_width: 32, ..super::linux_base::opts() } - } + }) } diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index ac1536b3d009b..b66fb62cd591e 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mipsel-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { max_atomic_width: 32, ..super::linux_base::opts() }, - } + }) } diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index a9ea52c427862..24d1a66ec2d2f 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mipsel-unknown-linux-musl".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { max_atomic_width: 32, ..super::linux_base::opts() } - } + }) } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 067885c92fdf4..4849a76e11d90 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -64,6 +64,8 @@ mod solaris_base; mod windows_base; mod windows_msvc_base; +pub type TargetResult = Result; + macro_rules! supported_targets { ( $(($triple:expr, $module:ident)),+ ) => ( $(mod $module;)* @@ -71,17 +73,17 @@ macro_rules! supported_targets { /// List of supported targets pub const TARGETS: &'static [&'static str] = &[$($triple),*]; - fn load_specific(target: &str) -> Option { + fn load_specific(target: &str) -> TargetResult { match target { $( $triple => { - let mut t = $module::target(); + let mut t = try!($module::target()); t.options.is_builtin = true; debug!("Got builtin target: {:?}", t); - Some(t) + Ok(t) }, )+ - _ => None + _ => Err(format!("Unable to find target: {}", target)) } } ) @@ -364,7 +366,7 @@ impl Target { } /// Load a target descriptor from a JSON object. - pub fn from_json(obj: Json) -> Target { + pub fn from_json(obj: Json) -> TargetResult { // While ugly, this code must remain this way to retain // compatibility with existing JSON fields and the internal // expected naming of the Target and TargetOptions structs. @@ -376,9 +378,9 @@ impl Target { match obj.find(name) .map(|s| s.as_string()) .and_then(|os| os.map(|s| s.to_string())) { - Some(val) => val, + Some(val) => Ok(val), None => { - panic!("Field {} in target specification is required", name) + return Err(format!("Field {} in target specification is required", name)) } } }; @@ -390,12 +392,12 @@ impl Target { }; let mut base = Target { - llvm_target: get_req_field("llvm-target"), - target_endian: get_req_field("target-endian"), - target_pointer_width: get_req_field("target-pointer-width"), - data_layout: get_req_field("data-layout"), - arch: get_req_field("arch"), - target_os: get_req_field("os"), + llvm_target: try!(get_req_field("llvm-target")), + target_endian: try!(get_req_field("target-endian")), + target_pointer_width: try!(get_req_field("target-pointer-width")), + data_layout: try!(get_req_field("data-layout")), + arch: try!(get_req_field("arch")), + target_os: try!(get_req_field("os")), target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), options: Default::default(), @@ -483,7 +485,7 @@ impl Target { key!(obj_is_bitcode, bool); key!(max_atomic_width, u64); - base + Ok(base) } /// Search RUST_TARGET_PATH for a JSON file specifying the given target @@ -506,10 +508,10 @@ impl Target { f.read_to_end(&mut contents).map_err(|e| e.to_string())?; let obj = json::from_reader(&mut &contents[..]) .map_err(|e| e.to_string())?; - Ok(Target::from_json(obj)) + Target::from_json(obj) } - if let Some(t) = load_specific(target) { + if let Ok(t) = load_specific(target) { return Ok(t) } diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index be4be8e6fc964..1c04e763417c4 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +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.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), 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 b0a81ce7ec501..906e28d2f20cb 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +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.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "powerpc64le-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), 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 aea57dc4b7f95..aebf9cd68717d 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.pre_link_args.push("-m32".to_string()); base.max_atomic_width = 32; - Target { + Ok(Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_pointer_width: "32".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index 5542c9120a402..65e4b1400fcf8 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "core2".to_string(); base.max_atomic_width = 128; // core2 support cmpxchg16b base.eliminate_frame_pointer = false; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-apple-darwin".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "apple".to_string(), 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 8638241f8610b..4afc9bcb946c2 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::X86_64)); + Ok(Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -23,7 +24,7 @@ pub fn target() -> Target { target_vendor: "apple".to_string(), options: TargetOptions { max_atomic_width: 64, - .. opts(Arch::X86_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 e243054d0230e..086e0e6bf4fe7 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +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.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "pc".to_string(), 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 a23a807a0257e..064f06e9b31d6 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "msvc".to_string(), target_vendor: "pc".to_string(), 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 af5d21c4d93e4..537d15f4603bb 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.pre_link_args.push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); @@ -24,7 +24,7 @@ pub fn target() -> Target { base.no_default_libraries = false; base.exe_allocation_crate = "alloc_system".to_string(); - Target { + Ok(Target { llvm_target: "x86_64-rumprun-netbsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -34,5 +34,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "rumprun".to_string(), 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 8f2c905cf2ee4..2a1feb937f742 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_back/target/x86_64_sun_solaris.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); base.pre_link_args.push("-m64".to_string()); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "x86_64-pc-solaris".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "sun".to_string(), 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 87753da540a36..81710b99b80be 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-bitrig".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), 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 2535071f3089c..7e40d49b870ad 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), 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 d3ad0578aeb6e..f38cdd4bec55f 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-freebsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), 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 7908e0d581ba1..ef81d397a8f1e 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), 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 3301e0e0dc93f..4bad7754b3907 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), 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 7e6d1b78469e2..5145e52d6b4c9 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-netbsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), 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 823b0994b0a00..339dbd591a02e 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-openbsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } From bd194a77d57c5487baf1f9bb169e44dd844235e6 Mon Sep 17 00:00:00 2001 From: Jonathan Creekmore Date: Sat, 23 Jul 2016 07:22:58 -0500 Subject: [PATCH 118/150] librustc_back: json tests for builtin targets Expand the supported_targets!() macro to also generate a set of JSON encode/decode tests to verify that the parser will encode and decode all of the fields needed for all of the builtin targets. Additionally, add PartialEq to Target and TargetOptions in support of the tests. --- src/librustc_back/target/mod.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 4849a76e11d90..84cb6c9ba7de3 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -79,6 +79,10 @@ macro_rules! supported_targets { $triple => { let mut t = try!($module::target()); t.options.is_builtin = true; + + // round-trip through the JSON parser to ensure at + // run-time that the parser works correctly + t = try!(Target::from_json(t.to_json())); debug!("Got builtin target: {:?}", t); Ok(t) }, @@ -86,6 +90,28 @@ macro_rules! supported_targets { _ => Err(format!("Unable to find target: {}", target)) } } + + #[cfg(test)] + mod test_json_encode_decode { + use serialize::json::ToJson; + use super::Target; + $(use super::$module;)* + + $( + #[test] + fn $module() { + // Grab the TargetResult struct. If we successfully retrieved + // a Target, then the test JSON encoding/decoding can run for this + // Target on this testing platform (i.e., checking the iOS targets + // only on a Mac test platform). + let _ = $module::target().map(|original| { + let as_json = original.to_json(); + let parsed = Target::from_json(as_json).unwrap(); + assert_eq!(original, parsed); + }); + } + )* + } ) } @@ -148,7 +174,7 @@ supported_targets! { /// Everything `rustc` knows about how to compile for a specific target. /// /// Every field here must be specified, and has no default value. -#[derive(Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] pub struct Target { /// Target triple to pass to LLVM. pub llvm_target: String, @@ -175,7 +201,7 @@ pub struct Target { /// /// This has an implementation of `Default`, see each field for what the default is. In general, /// these try to take "minimal defaults" that don't assume anything about the runtime they run in. -#[derive(Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] pub struct TargetOptions { /// Whether the target is built-in or loaded from a custom target specification. pub is_builtin: bool, From 54c61ff959de5f79afe59ba5051b087aed220408 Mon Sep 17 00:00:00 2001 From: Jonathan Creekmore Date: Tue, 26 Jul 2016 17:44:27 -0700 Subject: [PATCH 119/150] librustc_back: filter targets for only valid ones Since we can know which targets are instantiable on a particular host, it does not make sense to list invalid targets in the target print code. Filter the list of targets to only include the targets that can be instantiated. --- src/librustc_back/target/mod.rs | 10 +++++++++- src/librustc_driver/lib.rs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 84cb6c9ba7de3..f5314809228b5 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -71,7 +71,7 @@ macro_rules! supported_targets { $(mod $module;)* /// List of supported targets - pub const TARGETS: &'static [&'static str] = &[$($triple),*]; + const TARGETS: &'static [&'static str] = &[$($triple),*]; fn load_specific(target: &str) -> TargetResult { match target { @@ -91,6 +91,14 @@ macro_rules! supported_targets { } } + pub fn get_targets() -> Box> { + Box::new(TARGETS.iter().filter_map(|t| -> Option { + load_specific(t) + .map(|t| t.llvm_target) + .ok() + })) + } + #[cfg(test)] mod test_json_encode_decode { use serialize::json::ToJson; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 0a8df923b846b..eff920608dc2a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -609,7 +609,7 @@ impl RustcDefaultCalls { for req in &sess.opts.prints { match *req { PrintRequest::TargetList => { - let mut targets = rustc_back::target::TARGETS.to_vec(); + let mut targets = rustc_back::target::get_targets().collect::>(); targets.sort(); println!("{}", targets.join("\n")); }, From 032ea41e99b39f6af2aa26c0ba049d0d215d8ebb Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 13:22:38 -0400 Subject: [PATCH 120/150] book/ffi: nullable pointer, libc cleanups Expand the "nullable pointer optimization" section with a code example. Change examples to use std::os::raw instead of libc, when applicable. --- src/doc/book/ffi.md | 67 +++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 3cbe5d6026774..873d078f053e4 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -461,12 +461,11 @@ 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; +use std::os::raw::c_int; #[link(name = "readline")] extern { - static rl_readline_version: libc::c_int; + static rl_readline_version: c_int; } fn main() { @@ -480,15 +479,14 @@ 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::os::raw::c_char; use std::ptr; #[link(name = "readline")] extern { - static mut rl_prompt: *const libc::c_char; + static mut rl_prompt: *const c_char; } fn main() { @@ -513,14 +511,13 @@ calling foreign functions. Some foreign functions, most notably the Windows API, conventions. Rust provides a way to tell the compiler which convention to use: ```rust -# #![feature(libc)] -extern crate libc; +use std::os::raw::c_int; #[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 SetEnvironmentVariableA(n: *const u8, v: *const u8) -> c_int; } # fn main() { } ``` @@ -575,16 +572,45 @@ against `libc` and `libm` by default. # The "nullable pointer optimization" -Certain types are defined to not be NULL. This includes references (`&T`, -`&mut T`), boxes (`Box`), and function pointers (`extern "abi" fn()`). -When interfacing with C, pointers that might be NULL are often used. -As a special case, a generic `enum` that contains exactly two variants, one of +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` that contains exactly two variants, one of which contains no data and the other containing a single field, is eligible for the "nullable pointer optimization". When such an enum is instantiated -with one of the non-nullable types, it is represented as a single pointer, -and the non-data variant is represented as the NULL pointer. So -`Option c_int>` is how one represents a nullable -function pointer using the C ABI. +with one of the non-nullable types listed above, it is represented as a single pointer, +and the non-data variant is represented as the null pointer. 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)`). (However, generics are not required to get the optimization. A simple +`enum NullableIntRef { Int(Box), NotInt }` is also represented as a single pointer.) + +Here is an example: + +```rust +use std::os::raw::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. +#[no_mangle] +pub extern fn apply(process: Option c_int>, int: c_int) -> c_int { + match process { + Some(f) => unsafe { f(int) }, + None => int * int + } +} +# fn main() {} +``` + +No `tranmsute` required! # Calling Rust code from C @@ -642,12 +668,11 @@ void bar(void *arg); We can represent this in Rust with the `c_void` type: ```rust -# #![feature(libc)] -extern crate libc; +use std::os::raw::c_void; extern "C" { - pub fn foo(arg: *mut libc::c_void); - pub fn bar(arg: *mut libc::c_void); + pub fn foo(arg: *mut c_void); + pub fn bar(arg: *mut c_void); } # fn main() {} ``` From 48ce20653a470f2d4734fb0ee4a89905da23b15c Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 15:05:22 -0400 Subject: [PATCH 121/150] generics-agnostic description --- src/doc/book/ffi.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 873d078f053e4..590c23e89299e 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -578,19 +578,17 @@ interfacing with C, pointers that might be `null` are often used, which would se 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` that contains exactly two variants, one of -which contains no data and the other containing a single field, is eligible -for the "nullable pointer optimization". When such an enum is instantiated -with one of the non-nullable types listed above, it is represented as a single pointer, -and the non-data variant is represented as the null pointer. This is called an -"optimization", but unlike other optimizations it is guaranteed to apply to +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 single field of one of the non-nullable types listed above. This means it is represented +as a single pointer, and the non-data variant is represented as the null pointer. 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)`). (However, generics are not required to get the optimization. A simple -`enum NullableIntRef { Int(Box), NotInt }` is also represented as a single pointer.) +`int (*)(int)`). Here is an example: From cc2fc48dec9ae582ebba9761185afc5e21bf47b6 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 16:13:20 -0400 Subject: [PATCH 122/150] expand nullable pointer example --- src/doc/book/ffi.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 590c23e89299e..fb8896da86d73 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -590,22 +590,42 @@ where `None` corresponds to `null`. So `Option c_int>` i to represent a nullable function pointer using the C ABI (corresponding to the C type `int (*)(int)`). -Here is an example: +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 interface in both directions. ```rust use std::os::raw::c_int; +extern "C" { + /// Register the callback. + 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. -#[no_mangle] -pub extern fn apply(process: Option c_int>, int: c_int) -> c_int { +extern "C" fn apply(process: Option c_int>, int: c_int) -> c_int { match process { Some(f) => unsafe { f(int) }, None => int * int } } -# fn main() {} + +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 `tranmsute` required! From 84366b6f281614f61381962e2e46b73bb471c737 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 17:47:18 -0400 Subject: [PATCH 123/150] recursion --- src/doc/book/ffi.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index fb8896da86d73..5a2ec86c12f56 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -580,10 +580,10 @@ 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 single field of one of the non-nullable types listed above. This means it is represented -as a single pointer, and the non-data variant is represented as the null pointer. This is -called an "optimization", but unlike other optimizations it is guaranteed to apply to -eligible types. +a single field of one of the non-nullable types listed above (or a struct containing such a type). +This means it is represented as a single pointer, and the non-data variant is represented as a +null pointer. 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 From 0016af5f13702feb92f6323417fb9fe495e964d0 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 17:54:39 -0400 Subject: [PATCH 124/150] not just a single field --- src/doc/book/ffi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 5a2ec86c12f56..07b8d8e0da8a9 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -580,7 +580,7 @@ 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 single field of one of the non-nullable types listed above (or a struct containing such a type). +a field of one of the non-nullable types listed above (or a struct containing such a type). This means it is represented as a single pointer, and the non-data variant is represented as a null pointer. This is called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible types. From 1cceca8dfdda4a8bf3daa6a8c23adf7f23acd81a Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 18:00:07 -0400 Subject: [PATCH 125/150] foreign function interface interface --- src/doc/book/ffi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 07b8d8e0da8a9..4a55db38d3814 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -593,7 +593,7 @@ to represent a nullable function pointer using the C ABI (corresponding to the C 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 interface in both directions. +we have function pointers flying across the FFI boundary in both directions. ```rust use std::os::raw::c_int; From fae33352721c4b4d6fbdc66520043ae721121d77 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 21:10:12 -0400 Subject: [PATCH 126/150] extern fns require named parameters Not sure the example is going to stay, but I can try to pass Travis for the bragging rights. --- src/doc/book/ffi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 4a55db38d3814..74c99273fa262 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -600,7 +600,7 @@ use std::os::raw::c_int; extern "C" { /// Register the callback. - fn register(Option c_int>, c_int) -> c_int>); + fn register(cb: Option c_int>, c_int) -> c_int>); } /// This fairly useless function receives a function pointer and an integer From 5276b2967060d749e20674a08a2438a24f0f7b07 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 21:38:04 -0400 Subject: [PATCH 127/150] change confusing wording about discriminant --- src/doc/book/ffi.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 74c99273fa262..e63516e58ccfd 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -581,9 +581,9 @@ 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 (or a struct containing such a type). -This means it is represented as a single pointer, and the non-data variant is represented as a -null pointer. This is called an "optimization", but unlike other optimizations it is guaranteed -to apply to eligible types. +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 From 54ecc210ec720e93c6e493e6fc3e7464cd22002f Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Tue, 14 Jun 2016 15:53:55 -0400 Subject: [PATCH 128/150] hack to make example compile --- src/doc/book/ffi.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index e63516e58ccfd..e1b9789a3144a 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -598,17 +598,21 @@ we have function pointers flying across the FFI boundary in both directions. ```rust use std::os::raw::c_int; +# #[cfg(hidden)] extern "C" { /// Register 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) => unsafe { f(int) }, + Some(f) => f(int), None => int * int } } From 8e7abea93e84af6060ce6eeb530eb82fed3cff60 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 27 Jul 2016 13:51:48 -0400 Subject: [PATCH 129/150] revert libc changes --- src/doc/book/ffi.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index e1b9789a3144a..983bd46a0c9e6 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -461,11 +461,12 @@ global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: ```rust,no_run -use std::os::raw::c_int; +# #![feature(libc)] +extern crate libc; #[link(name = "readline")] extern { - static rl_readline_version: c_int; + static rl_readline_version: libc::c_int; } fn main() { @@ -479,14 +480,15 @@ 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::os::raw::c_char; use std::ptr; #[link(name = "readline")] extern { - static mut rl_prompt: *const c_char; + static mut rl_prompt: *const libc::c_char; } fn main() { @@ -511,13 +513,14 @@ calling foreign functions. Some foreign functions, most notably the Windows API, conventions. Rust provides a way to tell the compiler which convention to use: ```rust -use std::os::raw::c_int; +# #![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) -> c_int; + fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int; } # fn main() { } ``` @@ -690,11 +693,12 @@ void bar(void *arg); We can represent this in Rust with the `c_void` type: ```rust -use std::os::raw::c_void; +# #![feature(libc)] +extern crate libc; extern "C" { - pub fn foo(arg: *mut c_void); - pub fn bar(arg: *mut c_void); + pub fn foo(arg: *mut libc::c_void); + pub fn bar(arg: *mut libc::c_void); } # fn main() {} ``` From 1319b293c67f0fa8e9504c692898d2cee1866a9a Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 27 Jul 2016 13:52:13 -0400 Subject: [PATCH 130/150] fix typo --- src/doc/book/ffi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 983bd46a0c9e6..f9c50f0399add 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -635,7 +635,7 @@ void register(void (*f)(void (*)(int), int)) { } ``` -No `tranmsute` required! +No `transmute` required! # Calling Rust code from C From 29546dd06d733d065fc497902bbcecbbb06ce621 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 27 Jul 2016 13:57:14 -0400 Subject: [PATCH 131/150] remove claim about searching through nested fields for the nullable type, even though that is how it works --- src/doc/book/ffi.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index f9c50f0399add..ca104ff29ace3 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -581,12 +581,12 @@ interfacing with C, pointers that might be `null` are often used, which would se 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 (or a struct containing such a type). -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. +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 @@ -599,7 +599,9 @@ and an integer and it is supposed to run the function with the integer as a para we have function pointers flying across the FFI boundary in both directions. ```rust -use std::os::raw::c_int; +# #![feature(libc)] +extern crate libc; +use libc::c_int; # #[cfg(hidden)] extern "C" { From 91acc3977bdb62b52698b488c63070adbf29af30 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Wed, 27 Jul 2016 15:01:43 -0400 Subject: [PATCH 132/150] Correct minor typo in debug_assert doc --- src/libcore/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index e3207a0a86c4f..c8606b0f16361 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -138,7 +138,7 @@ macro_rules! assert_eq { /// running, which might have unexpected consequences but does not introduce /// unsafety as long as this only happens in safe code. The performance cost /// of assertions, is however, not measurable in general. Replacing `assert!` -/// with `debug_assert!` is thus only encourage after thorough profiling, and +/// with `debug_assert!` is thus only encouraged after thorough profiling, and /// more importantly, only in safe code! /// /// # Examples From 8760b1dd264bfd4f00a772e3229d02b9bb0e25f4 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Wed, 27 Jul 2016 15:03:23 -0400 Subject: [PATCH 133/150] Revert section about panic! in assert! doc --- src/libcore/macros.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c8606b0f16361..260d974e45d6c 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -32,9 +32,8 @@ macro_rules! panic { /// Ensure that a boolean expression is `true` at runtime. /// -/// This will ensure the termination of the program if the provided expression -/// cannot be evaluated to `true` at runtime by means of an unrecoverable error -/// (not necessarily a `panic!`, can also be an `abort`). +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. /// /// Assertions are always checked in both debug and release builds, and cannot /// be disabled. From 9a7367b96035ab1ff7593f929c852181de1bcbfb Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Wed, 27 Jul 2016 15:16:11 -0400 Subject: [PATCH 134/150] Mention debug_assert! in assert! doc --- src/libcore/macros.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 260d974e45d6c..b0c79a3a88547 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -36,7 +36,8 @@ macro_rules! panic { /// evaluated to `true` at runtime. /// /// Assertions are always checked in both debug and release builds, and cannot -/// be disabled. +/// be disabled. See `debug_assert!` for assertions that are not enabled in +/// release builds by default. /// /// Unsafe code relies on `assert!` to enforce run-time invariants that, if /// violated could lead to unsafety. From 3d09b4a0d58200da84fe19cd3b0003d61e5b1791 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 27 Jul 2016 12:10:31 +0200 Subject: [PATCH 135/150] Rename `char::escape` to `char::escape_debug` and add tracking issue --- src/libcollections/lib.rs | 2 +- src/libcollections/str.rs | 6 ++--- src/libcollectionstest/str.rs | 22 ++++++++--------- src/libcore/char.rs | 24 +++++++++---------- src/libcore/fmt/mod.rs | 4 ++-- src/libcoretest/char.rs | 4 ++-- src/libcoretest/lib.rs | 3 ++- src/librustc_unicode/char.rs | 8 +++---- src/librustc_unicode/lib.rs | 2 +- src/libstd/lib.rs | 15 ++++++------ src/libstd/sys/common/wtf8.rs | 6 ++--- .../sync-send-iterators-in-libcore.rs | 2 +- 12 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 333219bc5e5b0..7fc6e54d69f73 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -33,7 +33,7 @@ #![feature(allow_internal_unstable)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(char_escape)] +#![cfg_attr(not(test), feature(char_escape_debug))] #![feature(core_intrinsics)] #![feature(dropck_parametricity)] #![feature(fmt_internals)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index a63ea9d3ec777..4c64019de097e 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1697,12 +1697,12 @@ impl str { return s; } - /// Escapes each char in `s` with `char::escape`. + /// Escapes each char in `s` with `char::escape_debug`. #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] - pub fn escape(&self) -> String { - self.chars().flat_map(|c| c.escape()).collect() + pub fn escape_debug(&self) -> String { + self.chars().flat_map(|c| c.escape_debug()).collect() } /// Escapes each char in `s` with `char::escape_default`. diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 870f8a3a1ec6f..a61925cd3be5a 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -704,17 +704,17 @@ fn test_escape_unicode() { } #[test] -fn test_escape() { - assert_eq!("abc".escape_default(), "abc"); - assert_eq!("a c".escape_default(), "a c"); - assert_eq!("éèê".escape_default(), "éèê"); - assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); - assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); - assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_default(), "\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); - assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); +fn test_escape_debug() { + assert_eq!("abc".escape_debug(), "abc"); + assert_eq!("a c".escape_debug(), "a c"); + assert_eq!("éèê".escape_debug(), "éèê"); + assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); } #[test] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 3e435b47110a0..a3440fe8aa644 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -264,8 +264,8 @@ pub trait CharExt { fn escape_unicode(self) -> EscapeUnicode; #[stable(feature = "core", since = "1.6.0")] fn escape_default(self) -> EscapeDefault; - #[unstable(feature = "char_escape", issue = "0")] - fn escape(self) -> Escape; + #[unstable(feature = "char_escape_debug", issue = "35068")] + fn escape_debug(self) -> EscapeDebug; #[stable(feature = "core", since = "1.6.0")] fn len_utf8(self) -> usize; #[stable(feature = "core", since = "1.6.0")] @@ -330,7 +330,7 @@ impl CharExt for char { } #[inline] - fn escape(self) -> Escape { + fn escape_debug(self) -> EscapeDebug { let init_state = match self { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), @@ -339,7 +339,7 @@ impl CharExt for char { c if is_printable(c) => EscapeDefaultState::Char(c), c => EscapeDefaultState::Unicode(c.escape_unicode()), }; - Escape(EscapeDefault { state: init_state }) + EscapeDebug(EscapeDefault { state: init_state }) } #[inline] @@ -618,24 +618,24 @@ impl ExactSizeIterator for EscapeDefault { /// An iterator that yields the literal escape code of a `char`. /// -/// This `struct` is created by the [`escape()`] method on [`char`]. See its +/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its /// documentation for more. /// -/// [`escape()`]: ../../std/primitive.char.html#method.escape +/// [`escape_debug()`]: ../../std/primitive.char.html#method.escape_debug /// [`char`]: ../../std/primitive.char.html -#[unstable(feature = "char_escape", issue = "0")] +#[unstable(feature = "char_escape_debug", issue = "35068")] #[derive(Clone, Debug)] -pub struct Escape(EscapeDefault); +pub struct EscapeDebug(EscapeDefault); -#[unstable(feature = "char_escape", issue = "0")] -impl Iterator for Escape { +#[unstable(feature = "char_escape_debug", issue = "35068")] +impl Iterator for EscapeDebug { type Item = char; fn next(&mut self) -> Option { self.0.next() } fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } } -#[unstable(feature = "char_escape", issue = "0")] -impl ExactSizeIterator for Escape { } +#[unstable(feature = "char_escape_debug", issue = "35068")] +impl ExactSizeIterator for EscapeDebug { } /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 3bcdce57af0d1..173c55e35d51e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1383,7 +1383,7 @@ impl Debug for str { f.write_char('"')?; let mut from = 0; for (i, c) in self.char_indices() { - let esc = c.escape(); + let esc = c.escape_debug(); // If char needs escaping, flush backlog so far and write, else skip if esc.len() != 1 { f.write_str(&self[from..i])?; @@ -1409,7 +1409,7 @@ impl Display for str { impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; - for c in self.escape() { + for c in self.escape_debug() { f.write_char(c)? } f.write_char('\'') diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index ec757b0b5d389..4632419336d7f 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -124,9 +124,9 @@ fn test_is_digit() { } #[test] -fn test_escape() { +fn test_escape_debug() { fn string(c: char) -> String { - c.escape().collect() + c.escape_debug().collect() } let s = string('\n'); assert_eq!(s, "\\n"); diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 1ef2b58351fe5..ef0042808f98b 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -14,6 +14,7 @@ #![feature(borrow_state)] #![feature(box_syntax)] #![feature(cell_extras)] +#![feature(char_escape_debug)] #![feature(const_fn)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -29,10 +30,10 @@ #![feature(slice_patterns)] #![feature(step_by)] #![feature(test)] +#![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] -#![feature(try_from)] extern crate core; extern crate test; diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 683d5289ab53c..7e308684a2567 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -36,7 +36,7 @@ use tables::{conversions, derived_property, general_category, property}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EncodeUtf16, EncodeUtf8, Escape, EscapeDefault, EscapeUnicode}; +pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode}; // unstable reexports #[unstable(feature = "decode_utf8", issue = "33906")] @@ -296,10 +296,10 @@ impl char { /// /// assert_eq!(quote, "\\n"); /// ``` - #[unstable(feature = "char_escape", issue = "0")] + #[unstable(feature = "char_escape_debug", issue = "35068")] #[inline] - pub fn escape(self) -> Escape { - C::escape(self) + pub fn escape_debug(self) -> EscapeDebug { + C::escape_debug(self) } /// Returns an iterator that yields the literal escape code of a `char`. diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index 8c91d3b6a929b..3ae905eba279b 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -32,7 +32,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![no_std] -#![feature(char_escape)] +#![feature(char_escape_debug)] #![feature(core_char_ext)] #![feature(decode_utf8)] #![feature(lang_items)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d05a5a0961483..865d067cdb6dc 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -218,8 +218,9 @@ #![feature(associated_consts)] #![feature(borrow_state)] #![feature(box_syntax)] -#![feature(cfg_target_vendor)] #![feature(cfg_target_thread_local)] +#![feature(cfg_target_vendor)] +#![feature(char_escape_debug)] #![feature(char_internals)] #![feature(collections)] #![feature(collections_bound)] @@ -229,10 +230,10 @@ #![feature(dropck_parametricity)] #![feature(float_extras)] #![feature(float_from_str_radix)] -#![feature(fnbox)] #![feature(fn_traits)] -#![feature(heap_api)] +#![feature(fnbox)] #![feature(hashmap_hasher)] +#![feature(heap_api)] #![feature(inclusive_range)] #![feature(int_error_internals)] #![feature(into_cow)] @@ -242,6 +243,7 @@ #![feature(linkage)] #![feature(macro_reexport)] #![cfg_attr(test, feature(map_values_mut))] +#![feature(needs_panic_runtime)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -249,10 +251,11 @@ #![feature(optin_builtin_traits)] #![feature(panic_unwind)] #![feature(placement_in_syntax)] +#![feature(question_mark)] #![feature(rand)] #![feature(raw)] -#![feature(repr_simd)] #![feature(reflect_marker)] +#![feature(repr_simd)] #![feature(rustc_attrs)] #![feature(shared)] #![feature(sip_hash_13)] @@ -266,6 +269,7 @@ #![feature(str_utf16)] #![feature(test, rustc_private)] #![feature(thread_local)] +#![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] @@ -273,9 +277,6 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] -#![feature(question_mark)] -#![feature(try_from)] -#![feature(needs_panic_runtime)] // Issue# 30592: Systematically use alloc_system during stage0 since jemalloc // might be unavailable or disabled diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 2c1a656290f94..c0e6ec46b55b9 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -390,7 +390,7 @@ impl fmt::Debug for Wtf8 { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn write_str_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result { use fmt::Write; - for c in s.chars().flat_map(|c| c.escape_default()) { + for c in s.chars().flat_map(|c| c.escape_debug()) { f.write_char(c)? } Ok(()) @@ -1064,9 +1064,9 @@ mod tests { #[test] fn wtf8buf_show() { - let mut string = Wtf8Buf::from_str("a\té 💩\r"); + let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), r#""a\t\u{e9} \u{1f4a9}\r\u{D800}""#); + assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{D800}\""); } #[test] diff --git a/src/test/run-pass/sync-send-iterators-in-libcore.rs b/src/test/run-pass/sync-send-iterators-in-libcore.rs index 931789948159d..d12bdf182fa4d 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcore.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcore.rs @@ -67,7 +67,7 @@ macro_rules! is_sync_send { fn main() { // for char.rs - all_sync_send!("Я", escape_default, escape_unicode); + all_sync_send!("Я", escape_debug, escape_default, escape_unicode); // for iter.rs all_sync_send_mutable_ref!([1], iter); From 52c50ba276ffbdbe9c1a56e4f0b7d424f6bc22cc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2016 02:53:34 +0200 Subject: [PATCH 136/150] Add doc examples for std::fs::Metadata --- src/libstd/fs.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 48753ccf1c353..38fd93501a528 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -694,6 +694,23 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// if let Ok(time) = metadata.modified() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn modified(&self) -> io::Result { self.0.modified().map(FromInner::from_inner) @@ -712,6 +729,23 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// if let Ok(time) = metadata.accessed() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn accessed(&self) -> io::Result { self.0.accessed().map(FromInner::from_inner) @@ -726,6 +760,23 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// if let Ok(time) = metadata.created() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn created(&self) -> io::Result { self.0.created().map(FromInner::from_inner) From 448550223b4e80d722c18361c465a24889e37c40 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 17 Jul 2016 18:28:48 +0000 Subject: [PATCH 137/150] Add regression test --- src/test/compile-fail/macro-tt-matchers.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/compile-fail/macro-tt-matchers.rs diff --git a/src/test/compile-fail/macro-tt-matchers.rs b/src/test/compile-fail/macro-tt-matchers.rs new file mode 100644 index 0000000000000..f41da77ee9896 --- /dev/null +++ b/src/test/compile-fail/macro-tt-matchers.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(rustc_attrs)] + +macro_rules! foo { + ($x:tt) => (type Alias = $x;) +} + +foo!(Box); + +#[rustc_error] +fn main() {} //~ ERROR compilation successful From 8d3f20f9061273b215a7d86f8783f1ae66f9b3ae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2016 12:55:58 +0200 Subject: [PATCH 138/150] Add doc examples for std::fs::unix::OpenOptionsExt --- src/libstd/sys/unix/ext/fs.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 54340773a42b5..1e0dc3c833e77 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -63,6 +63,18 @@ pub trait OpenOptionsExt { /// If no `mode` is set, the default of `0o666` will be used. /// The operating system masks out bits with the systems `umask`, to produce /// the final permissions. + /// + /// # Examples + /// + /// ```rust,ignore + /// extern crate libc; + /// use std::fs::OpenOptions; + /// use std::os::unix::fs::OpenOptionsExt; + /// + /// let mut options = OpenOptions::new(); + /// options.mode(0o644); // Give read/write for owner and read for others. + /// let file = options.open("foo.txt"); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&mut self, mode: u32) -> &mut Self; From 123bf1e95d05282dc32d9a2403859dd827d84309 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2016 13:04:24 +0200 Subject: [PATCH 139/150] Add OpenOptionsExt doc examples --- src/libstd/sys/unix/ext/fs.rs | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 1e0dc3c833e77..77587918ac94b 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -25,15 +25,53 @@ use sys::platform::fs::MetadataExt as UnixMetadataExt; pub trait PermissionsExt { /// Returns the underlying raw `mode_t` bits that are the standard Unix /// permissions for this file. + /// + /// # Examples + /// + /// ```rust,ignore + /// use std::fs::File; + /// use std::os::unix::fs::PermissionsExt; + /// + /// let f = try!(File::create("foo.txt")); + /// let metadata = try!(f.metadata()); + /// let permissions = metadata.permissions(); + /// + /// println!("permissions: {}", permissions.mode()); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; /// Sets the underlying raw bits for this set of permissions. + /// + /// # Examples + /// + /// ```rust,ignore + /// use std::fs::File; + /// use std::os::unix::fs::PermissionsExt; + /// + /// let f = try!(File::create("foo.txt")); + /// let metadata = try!(f.metadata()); + /// let mut permissions = metadata.permissions(); + /// + /// permissions.set_mode(0o644); // Read/write for owner and read for others. + /// assert_eq!(permissions.mode(), 0o644); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); /// Creates a new instance of `Permissions` from the given set of Unix /// permission bits. + /// + /// # Examples + /// + /// ```rust,ignore + /// use std::fs::Permissions; + /// use std::os::unix::fs::PermissionsExt; + /// + /// // Read/write for owner and read for others. + /// let permissions = Permissions::from_mode(0o644); + /// assert_eq!(permissions.mode(), 0o644); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn from_mode(mode: u32) -> Self; } From f98c55d933d24a806cee85bb0239682b39a23e32 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 26 Jul 2016 22:52:56 -0400 Subject: [PATCH 140/150] Add documentation example for `str::Chars::as_str`. --- src/libcore/str/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index a32c9da9815ff..fdcadd43a0fb6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -459,6 +459,19 @@ impl<'a> Chars<'a> { /// /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// let mut chars = "abc".chars(); + /// + /// assert_eq!(chars.as_str(), "abc"); + /// chars.next(); + /// assert_eq!(chars.as_str(), "bc"); + /// chars.next(); + /// chars.next(); + /// assert_eq!(chars.as_str(), ""); + /// ``` #[stable(feature = "iter_to_slice", since = "1.4.0")] #[inline] pub fn as_str(&self) -> &'a str { From 2b38c4bdea7acf72b8322660de5a4f86d561a65c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:33:23 -0400 Subject: [PATCH 141/150] Extend DepGraph so it can track "work-products" A work product right now is just a `.o` file. In the future it probably includes other kinds of files, such as `.bc` files saving the unoptimized LLVM IR. However, because WorkProductIds must be independent of DefIds, so that they don't need translation, this system may not be suitable *as is* for storing fine-grained information (such as the MIR for individual defs), as it was originally intended. We will want to refactor some for that. --- src/librustc/dep_graph/dep_node.rs | 21 ++++++ src/librustc/dep_graph/graph.rs | 114 ++++++++++++++++++++++++++--- src/librustc/dep_graph/mod.rs | 2 + 3 files changed, 128 insertions(+), 9 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 73b96651b05e2..dd7f0286574d0 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -9,6 +9,7 @@ // except according to those terms. use std::fmt::Debug; +use std::sync::Arc; macro_rules! try_opt { ($e:expr) => ( @@ -45,6 +46,10 @@ pub enum DepNode { // in an extern crate. MetaData(D), + // Represents some artifact that we save to disk. Note that these + // do not have a def-id as part of their identifier. + WorkProduct(Arc), + // Represents different phases in the compiler. CrateReader, CollectLanguageItems, @@ -189,6 +194,11 @@ impl DepNode { TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), LinkBinary => Some(LinkBinary), + + // work product names do not need to be mapped, because + // they are always absolute. + WorkProduct(ref id) => Some(WorkProduct(id.clone())), + Hir(ref d) => op(d).map(Hir), MetaData(ref d) => op(d).map(MetaData), CollectItem(ref d) => op(d).map(CollectItem), @@ -229,3 +239,14 @@ impl DepNode { } } } + +/// A "work product" corresponds to a `.o` (or other) file that we +/// save in between runs. These ids do not have a DefId but rather +/// some independent path or string that persists between runs without +/// the need to be mapped or unmapped. (This ensures we can serialize +/// them even in the absence of a tcx.) +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum WorkProductId { + PartitionObjectFile(String), // see (*TransPartition) below +} + diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 741ad65c29fda..ab7013df33f14 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -9,22 +9,44 @@ // except according to those terms. use hir::def_id::DefId; +use rustc_data_structures::fnv::FnvHashMap; +use std::cell::{Ref, RefCell}; use std::rc::Rc; +use std::sync::Arc; -use super::dep_node::DepNode; +use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; use super::raii; use super::thread::{DepGraphThreadData, DepMessage}; #[derive(Clone)] pub struct DepGraph { - data: Rc + data: Rc +} + +struct DepGraphData { + /// we send messages to the thread to let it build up the dep-graph + /// from the current run + thread: DepGraphThreadData, + + /// when we load, there may be `.o` files, cached mir, or other such + /// things available to us. If we find that they are not dirty, we + /// load the path to the file storing those work-products here into + /// this map. We can later look for and extract that data. + previous_work_products: RefCell, WorkProduct>>, + + /// work-products that we generate in this run + work_products: RefCell, WorkProduct>>, } impl DepGraph { pub fn new(enabled: bool) -> DepGraph { DepGraph { - data: Rc::new(DepGraphThreadData::new(enabled)) + data: Rc::new(DepGraphData { + thread: DepGraphThreadData::new(enabled), + previous_work_products: RefCell::new(FnvHashMap()), + work_products: RefCell::new(FnvHashMap()) + }) } } @@ -32,19 +54,19 @@ impl DepGraph { /// then the other methods on this `DepGraph` will have no net effect. #[inline] pub fn enabled(&self) -> bool { - self.data.enabled() + self.data.thread.enabled() } pub fn query(&self) -> DepGraphQuery { - self.data.query() + self.data.thread.query() } pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> { - raii::IgnoreTask::new(&self.data) + raii::IgnoreTask::new(&self.data.thread) } pub fn in_task<'graph>(&'graph self, key: DepNode) -> raii::DepTask<'graph> { - raii::DepTask::new(&self.data, key) + raii::DepTask::new(&self.data.thread, key) } pub fn with_ignore(&self, op: OP) -> R @@ -62,10 +84,84 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { - self.data.enqueue(DepMessage::Read(v)); + self.data.thread.enqueue(DepMessage::Read(v)); } pub fn write(&self, v: DepNode) { - self.data.enqueue(DepMessage::Write(v)); + self.data.thread.enqueue(DepMessage::Write(v)); + } + + /// Indicates that a previous work product exists for `v`. This is + /// invoked during initial start-up based on what nodes are clean + /// (and what files exist in the incr. directory). + pub fn insert_previous_work_product(&self, v: &Arc, data: WorkProduct) { + debug!("insert_previous_work_product({:?}, {:?})", v, data); + self.data.previous_work_products.borrow_mut() + .insert(v.clone(), data); + } + + /// Indicates that we created the given work-product in this run + /// for `v`. This record will be preserved and loaded in the next + /// run. + pub fn insert_work_product(&self, v: &Arc, data: WorkProduct) { + debug!("insert_work_product({:?}, {:?})", v, data); + self.data.work_products.borrow_mut() + .insert(v.clone(), data); } + + /// Check whether a previous work product exists for `v` and, if + /// so, return the path that leads to it. Used to skip doing work. + pub fn previous_work_product(&self, v: &Arc) -> Option { + self.data.previous_work_products.borrow() + .get(v) + .cloned() + } + + /// Access the map of work-products created during this run. Only + /// used during saving of the dep-graph. + pub fn work_products(&self) -> Ref, WorkProduct>> { + self.data.work_products.borrow() + } +} + +/// A "work product" is an intermediate result that we save into the +/// incremental directory for later re-use. The primary example are +/// the object files that we save for each partition at code +/// generation time. +/// +/// Each work product is associated with a dep-node, representing the +/// process that produced the work-product. If that dep-node is found +/// to be dirty when we load up, then we will delete the work-product +/// at load time. If the work-product is found to be clean, the we +/// will keep a record in the `previous_work_products` list. +/// +/// In addition, work products have an associated hash. This hash is +/// an extra hash that can be used to decide if the work-product from +/// a previous compilation can be re-used (in addition to the dirty +/// edges check). +/// +/// As the primary example, consider the object files we generate for +/// each partition. In the first run, we create partitions based on +/// the symbols that need to be compiled. For each partition P, we +/// hash the symbols in P and create a `WorkProduct` record associated +/// with `DepNode::TransPartition(P)`; the hash is the set of symbols +/// in P. +/// +/// The next time we compile, if the `DepNode::TransPartition(P)` is +/// judged to be clean (which means none of the things we read to +/// generate the partition were found to be dirty), it will be loaded +/// into previous work products. We will then regenerate the set of +/// symbols in the partition P and hash them (note that new symbols +/// may be added -- for example, new monomorphizations -- even if +/// nothing in P changed!). We will compare that hash against the +/// previous hash. If it matches up, we can reuse the object file. +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct WorkProduct { + /// extra hash used to decide if work-product is still suitable; + /// note that this is *not* a hash of the work-product itself. + /// See documentation on `WorkProduct` type for an example. + pub input_hash: u64, + + /// filename storing this work-product (found in the incr. comp. directory) + pub file_name: String, } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index e65f6bbcf7aab..a499cb10f2325 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -20,7 +20,9 @@ mod visit; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::DepNode; +pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; +pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; pub use self::visit::visit_all_items_in_krate; pub use self::raii::DepTask; From ffc13b2f80dfe60895bb415175fa246d7247a33c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:41:29 -0400 Subject: [PATCH 142/150] Store `crate_disambiguator` as an `InternedString` We used to use `Name`, but the session outlives the tokenizer, which means that attempts to read this field after trans has complete otherwise panic. All reads want an `InternedString` anyhow. --- src/librustc/session/mod.rs | 7 +++++-- src/librustc/ty/context.rs | 2 +- src/librustc_driver/driver.rs | 3 ++- src/librustc_incremental/calculate_svh.rs | 8 ++++---- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/encoder.rs | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 5901c42b52582..cee18232ec98a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -80,7 +80,7 @@ pub struct Session { // forms a unique global identifier for the crate. It is used to allow // multiple crates with the same name to coexist. See the // trans::back::symbol_names module for more information. - pub crate_disambiguator: Cell, + pub crate_disambiguator: RefCell, pub features: RefCell, /// The maximum recursion limit for potentially infinitely recursive @@ -106,6 +106,9 @@ pub struct Session { } impl Session { + pub fn local_crate_disambiguator(&self) -> token::InternedString { + self.crate_disambiguator.borrow().clone() + } pub fn struct_span_warn<'a, S: Into>(&'a self, sp: S, msg: &str) @@ -438,7 +441,7 @@ pub fn build_session_(sopts: config::Options, plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FnvHashMap()), - crate_disambiguator: Cell::new(token::intern("")), + crate_disambiguator: RefCell::new(token::intern("").as_str()), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), next_node_id: Cell::new(1), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 56938a7a83858..5444dd9476120 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -504,7 +504,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn crate_disambiguator(self, cnum: ast::CrateNum) -> token::InternedString { if cnum == LOCAL_CRATE { - self.sess.crate_disambiguator.get().as_str() + self.sess.local_crate_disambiguator() } else { self.sess.cstore.crate_disambiguator(cnum) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9a94cc16bfe8c..e1fb7d05b7268 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -566,7 +566,8 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, }); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); - sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess))); + *sess.crate_disambiguator.borrow_mut() = + token::intern(&compute_crate_disambiguator(sess)).as_str(); time(time_passes, "recursion limit", || { middle::recursion_limit::update_recursion_limit(sess, &krate); diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index cbc246ac2a11b..70704f5dec0d2 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { // to ensure it is not incorporating implementation artifacts into // the hash that are not otherwise visible.) - let crate_disambiguator = self.sess.crate_disambiguator.get(); + let crate_disambiguator = self.sess.local_crate_disambiguator(); let krate = self.map.krate(); // FIXME: this should use SHA1, not SipHash. SipHash is not built to @@ -47,10 +47,10 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { // FIXME(#32753) -- at (*) we `to_le` for endianness, but is // this enough, and does it matter anyway? "crate_disambiguator".hash(&mut state); - crate_disambiguator.as_str().len().to_le().hash(&mut state); // (*) - crate_disambiguator.as_str().hash(&mut state); + crate_disambiguator.len().to_le().hash(&mut state); // (*) + crate_disambiguator.hash(&mut state); - debug!("crate_disambiguator: {:?}", crate_disambiguator.as_str()); + debug!("crate_disambiguator: {:?}", crate_disambiguator); debug!("state: {:?}", state); { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d4443c6d09d7c..0b60fc386a7bb 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -243,7 +243,7 @@ impl<'a> CrateReader<'a> { // Check for (potential) conflicts with the local crate if self.local_crate_name == crate_name && - self.sess.crate_disambiguator.get().as_str() == disambiguator { + self.sess.local_crate_disambiguator() == disambiguator { span_fatal!(self.sess, span, E0519, "the current crate is indistinguishable from one of its \ dependencies: it has the same crate-name `{}` and was \ diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7314259423592..c896263de948e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1893,7 +1893,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_crate_name(rbml_w, &ecx.link_meta.crate_name); encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple); encode_hash(rbml_w, &ecx.link_meta.crate_hash); - encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str()); + encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator()); encode_dylib_dependency_formats(rbml_w, &ecx); encode_panic_strategy(rbml_w, &ecx); From cca4804251957646d4840bf33b3b13e3f2b645de Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:44:59 -0400 Subject: [PATCH 143/150] Code to save/load the work-products map from disk Work products are deleted if any of their inputs are dirty. --- src/librustc_driver/driver.rs | 11 ++- src/librustc_incremental/lib.rs | 2 + src/librustc_incremental/persist/data.rs | 12 ++- src/librustc_incremental/persist/load.rs | 121 ++++++++++++++++++----- src/librustc_incremental/persist/mod.rs | 1 + src/librustc_incremental/persist/save.rs | 51 +++++++--- src/librustc_incremental/persist/util.rs | 46 ++++++--- 7 files changed, 191 insertions(+), 53 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index e1fb7d05b7268..a48ff2533485c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -88,7 +88,7 @@ pub fn compile_input(sess: &Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans) = { + let (outputs, trans, id) = { let krate = match phase_1_parse_input(sess, cfg, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -212,11 +212,11 @@ pub fn compile_input(sess: &Session, // Discard interned strings as they are no longer required. token::clear_ident_interner(); - Ok((outputs, trans)) + Ok((outputs, trans, id.clone())) })?? }; - let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); + let phase5_result = phase_5_run_llvm_passes(sess, &id, &trans, &outputs); controller_entry_point!(after_llvm, sess, @@ -1020,6 +1020,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Run LLVM itself, producing a bitcode file, assembly file or object file /// as a side effect. pub fn phase_5_run_llvm_passes(sess: &Session, + crate_name: &str, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { if sess.opts.cg.no_integrated_as { @@ -1041,6 +1042,10 @@ pub fn phase_5_run_llvm_passes(sess: &Session, || write::run_passes(sess, trans, &sess.opts.output_types, outputs)); } + time(sess.time_passes(), + "serialize work products", + move || rustc_incremental::save_work_products(sess, crate_name)); + if sess.err_count() > 0 { Err(sess.err_count()) } else { diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index ed31e0ba51056..352e5979d011e 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -19,6 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(question_mark)] #![feature(rustc_private)] #![feature(staged_api)] @@ -40,3 +41,4 @@ pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::SvhCalculate; pub use persist::load_dep_graph; pub use persist::save_dep_graph; +pub use persist::save_work_products; diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index f57ab19a5256e..95e9a16f29bbe 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -10,8 +10,9 @@ //! The data that we will serialize and deserialize. -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; +use std::sync::Arc; use super::directory::DefPathIndex; @@ -55,6 +56,15 @@ pub struct SerializedHash { pub hash: u64, } +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedWorkProduct { + /// node that produced the work-product + pub id: Arc, + + /// work-product data itself + pub work_product: WorkProduct, +} + /// Data for use when downstream crates get recompiled. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedMetadataHashes { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 0ac1018462ee7..9fef2285aa7eb 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -14,12 +14,13 @@ use rbml::Error; use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; +use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashSet; use rustc_serialize::Decodable as RustcDecodable; use std::io::Read; -use std::fs::File; -use std::path::Path; +use std::fs::{self, File}; +use std::path::{Path}; use super::data::*; use super::directory::*; @@ -38,18 +39,40 @@ type CleanEdges = Vec<(DepNode, DepNode)>; /// actually it doesn't matter all that much.) See `README.md` for /// more general overview. pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + if tcx.sess.opts.incremental.is_none() { + return; + } + let _ignore = tcx.dep_graph.in_ignore(); + load_dep_graph_if_exists(tcx); + dirty_clean::check_dirty_clean_annotations(tcx); +} - if let Some(dep_graph) = dep_graph_path(tcx) { - // FIXME(#32754) lock file? - load_dep_graph_if_exists(tcx, &dep_graph); - dirty_clean::check_dirty_clean_annotations(tcx); +fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let dep_graph_path = dep_graph_path(tcx).unwrap(); + let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) { + Some(p) => p, + None => return // no file + }; + + let work_products_path = tcx_work_products_path(tcx).unwrap(); + let work_products_data = match load_data(tcx.sess, &work_products_path) { + Some(p) => p, + None => return // no file + }; + + match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) { + Ok(()) => return, + Err(err) => bug!("decoding error in dep-graph from `{}` and `{}`: {}", + dep_graph_path.display(), + work_products_path.display(), + err), } } -pub fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &Path) { +fn load_data(sess: &Session, path: &Path) -> Option> { if !path.exists() { - return; + return None; } let mut data = vec![]; @@ -57,31 +80,32 @@ pub fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &Pa File::open(path) .and_then(|mut file| file.read_to_end(&mut data)) { - Ok(_) => { } + Ok(_) => { + Some(data) + } Err(err) => { - tcx.sess.err( + sess.err( &format!("could not load dep-graph from `{}`: {}", path.display(), err)); - return; + None } } - match decode_dep_graph(tcx, &data) { - Ok(dirty) => dirty, - Err(err) => { - bug!("decoding error in dep-graph from `{}`: {}", path.display(), err); - } - } } +/// Decode the dep graph and load the edges/nodes that are still clean +/// into `tcx.dep_graph`. On success, returns a hashset containing all +/// the paths of work-products from clean nodes (any work-products not +/// in this set can be deleted). pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: &[u8]) + dep_graph_data: &[u8], + work_products_data: &[u8]) -> Result<(), Error> { // Deserialize the directory and dep-graph. - let mut decoder = Decoder::new(data, 0); - let directory = try!(DefIdDirectory::decode(&mut decoder)); - let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut decoder)); + let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0); + let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder)); + let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder)); debug!("decode_dep_graph: directory = {:#?}", directory); debug!("decode_dep_graph: serialized_dep_graph = {:#?}", serialized_dep_graph); @@ -121,12 +145,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Add nodes and edges that are not dirty into our main graph. let dep_graph = tcx.dep_graph.clone(); for (source, target) in clean_edges.into_iter().chain(clean_nodes) { - let _task = dep_graph.in_task(target.clone()); - dep_graph.read(source.clone()); - debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target); + + let _task = dep_graph.in_task(target); + dep_graph.read(source); } + // Add in work-products that are still clean, and delete those that are + // dirty. + let mut work_product_decoder = Decoder::new(work_products_data, 0); + let work_products = try!(>::decode(&mut work_product_decoder)); + reconcile_work_products(tcx, work_products, &dirty_nodes); + Ok(()) } @@ -141,9 +171,9 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match hash.node.map_def(|&i| retraced.def_id(i)) { Some(dep_node) => { let current_hash = hcx.hash(&dep_node).unwrap(); - debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}", - dep_node, current_hash, hash.hash); if current_hash != hash.hash { + debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", + dep_node, current_hash, hash.hash); dirty_nodes.insert(dep_node); } } @@ -177,6 +207,8 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)], clean_edges.push((source, target)) } else { // source removed, target must be dirty + debug!("compute_clean_edges: {:?} dirty because {:?} no longer exists", + target, serialized_source); dirty_nodes.insert(target); } } else { @@ -213,3 +245,40 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)], clean_edges } + +/// Go through the list of work-products produced in the previous run. +/// Delete any whose nodes have been found to be dirty or which are +/// otherwise no longer applicable. +fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + work_products: Vec, + dirty_nodes: &DirtyNodes) { + debug!("reconcile_work_products({:?})", work_products); + for swp in work_products { + let dep_node = DepNode::WorkProduct(swp.id.clone()); + if dirty_nodes.contains(&dep_node) { + debug!("reconcile_work_products: dep-node for {:?} is dirty", swp); + delete_dirty_work_product(tcx, swp); + } else { + let path = in_incr_comp_dir(tcx.sess, &swp.work_product.file_name).unwrap(); + if path.exists() { + tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product); + } else { + debug!("reconcile_work_products: file for {:?} does not exist", swp); + } + } + } +} + +fn delete_dirty_work_product(tcx: TyCtxt, + swp: SerializedWorkProduct) { + debug!("delete_dirty_work_product({:?})", swp); + let path = in_incr_comp_dir(tcx.sess, &swp.work_product.file_name).unwrap(); + match fs::remove_file(&path) { + Ok(()) => { } + Err(err) => { + tcx.sess.warn( + &format!("file-system error deleting outdated file `{}`: {}", + path.display(), err)); + } + } +} diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 72ccc29c97b63..30e7d7873ecc1 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -22,3 +22,4 @@ mod util; pub use self::load::load_dep_graph; pub use self::save::save_dep_graph; +pub use self::save::save_work_products; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 99f4d4f307298..305250d59623c 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -11,6 +11,7 @@ use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; use rustc::middle::cstore::LOCAL_CRATE; +use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_serialize::{Encodable as RustcEncodable}; use std::hash::{Hasher, SipHasher}; @@ -24,19 +25,26 @@ use super::hash::*; use super::util::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); + let sess = tcx.sess; let mut hcx = HashContext::new(tcx); - save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph); - save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes); + save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, e)); + save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, e)); } -fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, - opt_path_buf: Option, - encode: F) - where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()> -{ - let tcx = hcx.tcx; +pub fn save_work_products(sess: &Session, local_crate_name: &str) { + debug!("save_work_products()"); + let _ignore = sess.dep_graph.in_ignore(); + let path = sess_work_products_path(sess, local_crate_name); + save_in(sess, path, |e| encode_work_products(sess, e)); +} +fn save_in(sess: &Session, + opt_path_buf: Option, + encode: F) + where F: FnOnce(&mut Encoder) -> io::Result<()> +{ let path_buf = match opt_path_buf { Some(p) => p, None => return @@ -49,7 +57,7 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, match fs::remove_file(&path_buf) { Ok(()) => { } Err(err) => { - tcx.sess.err( + sess.err( &format!("unable to delete old dep-graph at `{}`: {}", path_buf.display(), err)); return; @@ -59,10 +67,10 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, // generate the data in a memory buffer let mut wr = Cursor::new(Vec::new()); - match encode(hcx, &mut Encoder::new(&mut wr)) { + match encode(&mut Encoder::new(&mut wr)) { Ok(()) => { } Err(err) => { - tcx.sess.err( + sess.err( &format!("could not encode dep-graph to `{}`: {}", path_buf.display(), err)); return; @@ -77,7 +85,7 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, { Ok(_) => { } Err(err) => { - tcx.sess.err( + sess.err( &format!("failed to write dep-graph to `{}`: {}", path_buf.display(), err)); return; @@ -192,3 +200,22 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, Ok(()) } + +pub fn encode_work_products(sess: &Session, + encoder: &mut Encoder) + -> io::Result<()> +{ + let work_products: Vec<_> = + sess.dep_graph.work_products() + .iter() + .map(|(id, work_product)| { + SerializedWorkProduct { + id: id.clone(), + work_product: work_product.clone(), + } + }) + .collect(); + + work_products.encode(encoder) +} + diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index a77a9607e7734..f1e81fdb266b9 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -9,6 +9,7 @@ // except according to those terms. use rustc::middle::cstore::LOCAL_CRATE; +use rustc::session::Session; use rustc::ty::TyCtxt; use std::fs; @@ -17,33 +18,56 @@ use std::path::{Path, PathBuf}; use syntax::ast; pub fn dep_graph_path(tcx: TyCtxt) -> Option { - path(tcx, LOCAL_CRATE, "local") + tcx_path(tcx, LOCAL_CRATE, "local") } pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option { - path(tcx, cnum, "metadata") + tcx_path(tcx, cnum, "metadata") } -fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option { +pub fn tcx_work_products_path(tcx: TyCtxt) -> Option { + let crate_name = tcx.crate_name(LOCAL_CRATE); + sess_work_products_path(tcx.sess, &crate_name) +} + +pub fn sess_work_products_path(sess: &Session, + local_crate_name: &str) + -> Option { + let crate_disambiguator = sess.local_crate_disambiguator(); + path(sess, local_crate_name, &crate_disambiguator, "work-products") +} + +pub fn in_incr_comp_dir(sess: &Session, file_name: &str) -> Option { + sess.opts.incremental.as_ref().map(|incr_dir| incr_dir.join(file_name)) +} + +fn tcx_path(tcx: TyCtxt, + cnum: ast::CrateNum, + middle: &str) + -> Option { + path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum), middle) +} + +fn path(sess: &Session, + crate_name: &str, + crate_disambiguator: &str, + middle: &str) + -> Option { // For now, just save/load dep-graph from // directory/dep_graph.rbml - tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| { + sess.opts.incremental.as_ref().and_then(|incr_dir| { match create_dir_racy(&incr_dir) { Ok(()) => {} Err(err) => { - tcx.sess.err( + sess.err( &format!("could not create the directory `{}`: {}", incr_dir.display(), err)); return None; } } - let crate_name = tcx.crate_name(cnum); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - let file_name = format!("{}-{}.{}.bin", - crate_name, - crate_disambiguator, - suffix); + let file_name = format!("{}-{}.{}.bin", crate_name, crate_disambiguator, middle); + Some(incr_dir.join(file_name)) }) } From 58d4b8edd319d0f0d76024504cdfc74f89a001b1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:49:59 -0400 Subject: [PATCH 144/150] Modify trans to skip generating `.o` files This checks the `previous_work_products` data from the dep-graph and tries to simply copy a `.o` file if possible. We also add new work-products into the dep-graph, and create edges to/from the dep-node for a work-product. --- src/librustc_incremental/lib.rs | 2 + src/librustc_incremental/persist/mod.rs | 3 + .../persist/work_product.rs | 61 ++++++++ src/librustc_trans/back/write.rs | 67 +++++++-- src/librustc_trans/base.rs | 137 +++++++++++++----- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/context.rs | 69 +++++++-- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/lib.rs | 14 ++ src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/partitioning.rs | 80 +++++++--- src/librustc_trans/trans_item.rs | 30 +++- src/test/run-make/execution-engine/test.rs | 7 +- src/test/run-make/llvm-phase/test.rs | 7 +- 14 files changed, 385 insertions(+), 98 deletions(-) create mode 100644 src/librustc_incremental/persist/work_product.rs diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 352e5979d011e..0d11b0794feac 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -41,4 +41,6 @@ pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::SvhCalculate; pub use persist::load_dep_graph; pub use persist::save_dep_graph; +pub use persist::save_trans_partition; pub use persist::save_work_products; +pub use persist::in_incr_comp_dir; diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 30e7d7873ecc1..1157f494ce604 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -19,7 +19,10 @@ mod hash; mod load; mod save; mod util; +mod work_product; pub use self::load::load_dep_graph; pub use self::save::save_dep_graph; pub use self::save::save_work_products; +pub use self::work_product::save_trans_partition; +pub use self::util::in_incr_comp_dir; diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs new file mode 100644 index 0000000000000..01ac3f6c391d9 --- /dev/null +++ b/src/librustc_incremental/persist/work_product.rs @@ -0,0 +1,61 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains files for saving intermediate work-products. + +use persist::util::*; +use rustc::dep_graph::{WorkProduct, WorkProductId}; +use rustc::session::Session; +use std::fs; +use std::path::Path; +use std::sync::Arc; + +pub fn save_trans_partition(sess: &Session, + partition_name: &str, + partition_hash: u64, + path_to_obj_file: &Path) { + debug!("save_trans_partition({:?},{},{})", + partition_name, + partition_hash, + path_to_obj_file.display()); + if sess.opts.incremental.is_none() { + return; + } + let id = Arc::new(WorkProductId::PartitionObjectFile(partition_name.to_string())); + let file_name = format!("cgu-{}", partition_name); + let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap(); + + // try to delete the file if it already exists + // + // FIXME(#34955) we can be smarter here -- if we are re-using, no need to do anything + if path_in_incr_dir.exists() { + let _ = fs::remove_file(&path_in_incr_dir); + } + + match + fs::hard_link(path_to_obj_file, &path_in_incr_dir) + .or_else(|_| fs::copy(path_to_obj_file, &path_in_incr_dir).map(|_| ())) + { + Ok(_) => { + let work_product = WorkProduct { + input_hash: partition_hash, + file_name: file_name, + }; + sess.dep_graph.insert_work_product(&id, work_product); + } + Err(err) => { + sess.warn(&format!("error copying object file `{}` \ + to incremental directory as `{}`: {}", + path_to_obj_file.display(), + path_in_incr_dir.display(), + err)); + } + } +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 33cffa8a48013..70925218781bd 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,13 +10,14 @@ use back::lto; use back::link::{get_linker, remove}; +use rustc_incremental::save_trans_partition; use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; use session::config::{self, OutputType}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef}; use llvm::SMDiagnosticRef; -use {CrateTranslation, ModuleTranslation}; +use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation}; use util::common::time; use util::common::path2cstr; use errors::{self, Handler, Level, DiagnosticBuilder}; @@ -26,6 +27,7 @@ use syntax_pos::MultiSpan; use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs; +use std::io; use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; @@ -422,10 +424,11 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo // Unsafe due to LLVM calls. unsafe fn optimize_and_codegen(cgcx: &CodegenContext, mtrans: ModuleTranslation, + mllvm: ModuleLlvm, config: ModuleConfig, output_names: OutputFilenames) { - let llmod = mtrans.llmod; - let llcx = mtrans.llcx; + let llmod = mllvm.llmod; + let llcx = mllvm.llcx; let tm = config.tm; // llcx doesn't outlive this function, so we can put this on the stack. @@ -628,8 +631,14 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, pub fn cleanup_llvm(trans: &CrateTranslation) { for module in trans.modules.iter() { unsafe { - llvm::LLVMDisposeModule(module.llmod); - llvm::LLVMContextDispose(module.llcx); + match module.source { + ModuleSource::Translated(llvm) => { + llvm::LLVMDisposeModule(llvm.llmod); + llvm::LLVMContextDispose(llvm.llcx); + } + ModuleSource::Preexisting(_) => { + } + } } } } @@ -743,6 +752,13 @@ pub fn run_passes(sess: &Session, run_work_multithreaded(sess, work_items, num_workers); } + // If in incr. comp. mode, preserve the `.o` files for potential re-use + for mtrans in trans.modules.iter() { + let path_to_obj = crate_output.temp_path(OutputType::Object, Some(&mtrans.name)); + debug!("wrote module {:?} to {:?}", mtrans.name, path_to_obj); + save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &path_to_obj); + } + // All codegen is finished. unsafe { llvm::LLVMRustDisposeTargetMachine(tm); @@ -913,13 +929,46 @@ fn build_work_item(sess: &Session, } } +fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result<()> { + let p = p.as_ref(); + let q = q.as_ref(); + if q.exists() { + try!(fs::remove_file(&q)); + } + fs::hard_link(p, q) + .or_else(|_| fs::copy(p, q).map(|_| ())) +} + fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) { unsafe { - optimize_and_codegen(cgcx, - work_item.mtrans, - work_item.config, - work_item.output_names); + match work_item.mtrans.source { + ModuleSource::Translated(mllvm) => { + debug!("llvm-optimizing {:?}", work_item.mtrans.name); + optimize_and_codegen(cgcx, + work_item.mtrans, + mllvm, + work_item.config, + work_item.output_names); + } + ModuleSource::Preexisting(ref buf) => { + let obj_out = work_item.output_names.temp_path(OutputType::Object, + Some(&work_item.mtrans.name)); + debug!("copying pre-existing module `{}` from {} to {}", + work_item.mtrans.name, + buf.display(), + obj_out.display()); + match link_or_copy(buf, &obj_out) { + Ok(()) => { } + Err(err) => { + cgcx.handler.err(&format!("unable to copy {} to {}: {}", + buf.display(), + obj_out.display(), + err)); + } + } + } + } } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ea8c248d0239f..a77ababaa6355 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -26,6 +26,8 @@ #![allow(non_camel_case_types)] use super::CrateTranslation; +use super::ModuleLlvm; +use super::ModuleSource; use super::ModuleTranslation; use back::link; @@ -43,6 +45,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::util::common::time; +use rustc_incremental::in_incr_comp_dir; use rustc::mir::mir_map::MirMap; use rustc_data_structures::graph::OUTGOING; use session::config::{self, NoDebugInfo, FullDebugInfo}; @@ -99,6 +102,7 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::ptr; use std::rc::Rc; +use std::path::PathBuf; use std::str; use std::{i8, i16, i32, i64}; use syntax_pos::{Span, DUMMY_SP}; @@ -2133,7 +2137,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { let instance = Instance::mono(ccx.shared(), main_def_id); - if !ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance)) { + if !ccx.codegen_unit().contains_item(&TransItem::Fn(instance)) { // We want to create the wrapper in the same codegen unit as Rust's main // function. return; @@ -2270,7 +2274,7 @@ fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>, // Collect all symbols that need to stay externally visible because they // are referenced via a declaration in some other codegen unit. - for ccx in ccxs.iter() { + for ccx in ccxs.iter_need_trans() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { let linkage = llvm::LLVMGetLinkage(val); // We only care about external declarations (not definitions) @@ -2315,7 +2319,7 @@ fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>, // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, // then give it internal linkage. - for ccx in ccxs.iter() { + for ccx in ccxs.iter_need_trans() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { let linkage = llvm::LLVMGetLinkage(val); @@ -2362,7 +2366,7 @@ fn create_imps(cx: &CrateContextList) { "\x01__imp_" }; unsafe { - for ccx in cx.iter() { + for ccx in cx.iter_need_trans() { let exported: Vec<_> = iter_globals(ccx.llmod()) .filter(|&val| { llvm::LLVMGetLinkage(val) == @@ -2514,8 +2518,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let metadata_module = ModuleTranslation { name: "metadata".to_string(), - llcx: shared_ccx.metadata_llcx(), - llmod: shared_ccx.metadata_llmod(), + symbol_name_hash: 0, // we always rebuild metadata, at least for now + source: ModuleSource::Translated(ModuleLlvm { + llcx: shared_ccx.metadata_llcx(), + llmod: shared_ccx.metadata_llmod(), + }), }; let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); @@ -2525,14 +2532,29 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let symbol_map = Rc::new(symbol_map); + let previous_work_products = trans_reuse_previous_work_products(tcx, + &codegen_units, + &symbol_map); + let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units, + previous_work_products, symbol_map.clone()); - let modules = crate_context_list.iter() - .map(|ccx| ModuleTranslation { - name: String::from(&ccx.codegen_unit().name[..]), - llcx: ccx.llcx(), - llmod: ccx.llmod() + let modules: Vec<_> = crate_context_list.iter_all() + .map(|ccx| { + let source = match ccx.previous_work_product() { + Some(buf) => ModuleSource::Preexisting(buf.clone()), + None => ModuleSource::Translated(ModuleLlvm { + llcx: ccx.llcx(), + llmod: ccx.llmod(), + }), + }; + + ModuleTranslation { + name: String::from(ccx.codegen_unit().name()), + symbol_name_hash: ccx.codegen_unit().compute_symbol_name_hash(tcx, &symbol_map), + source: source, + } }) .collect(); @@ -2551,41 +2573,44 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - for ccx in crate_context_list.iter() { - let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(tcx, &symbol_map); + for ccx in crate_context_list.iter_need_trans() { + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - for (trans_item, linkage) in trans_items { - trans_item.predefine(&ccx, linkage); - } + tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + for (trans_item, linkage) in trans_items { + trans_item.predefine(&ccx, linkage); + } + }); } // ... and now that we have everything pre-defined, fill out those definitions. - for ccx in crate_context_list.iter() { - let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(tcx, &symbol_map); - - for (trans_item, _) in trans_items { - trans_item.define(&ccx); - } + for ccx in crate_context_list.iter_need_trans() { + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); + tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + for (trans_item, _) in trans_items { + trans_item.define(&ccx); + } - // If this codegen unit contains the main function, also create the - // wrapper here - maybe_create_entry_wrapper(&ccx); + // If this codegen unit contains the main function, also create the + // wrapper here + maybe_create_entry_wrapper(&ccx); - // Run replace-all-uses-with for statics that need it - for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { - unsafe { - let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); - llvm::LLVMReplaceAllUsesWith(old_g, bitcast); - llvm::LLVMDeleteGlobal(old_g); + // Run replace-all-uses-with for statics that need it + for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { + unsafe { + let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); + llvm::LLVMReplaceAllUsesWith(old_g, bitcast); + llvm::LLVMDeleteGlobal(old_g); + } } - } - // Finalize debuginfo - if ccx.sess().opts.debuginfo != NoDebugInfo { - debuginfo::finalize(&ccx); - } + // Finalize debuginfo + if ccx.sess().opts.debuginfo != NoDebugInfo { + debuginfo::finalize(&ccx); + } + }); } symbol_names_test::report_symbol_names(&shared_ccx); @@ -2679,6 +2704,38 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +/// For each CGU, identify if we can reuse an existing object file (or +/// maybe other context). +fn trans_reuse_previous_work_products(tcx: TyCtxt, + codegen_units: &[CodegenUnit], + symbol_map: &SymbolMap) + -> Vec> { + debug!("trans_reuse_previous_work_products()"); + codegen_units + .iter() + .map(|cgu| { + let id = cgu.work_product_id(); + + let hash = cgu.compute_symbol_name_hash(tcx, symbol_map); + + debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash); + + if let Some(work_product) = tcx.dep_graph.previous_work_product(&id) { + if work_product.input_hash == hash { + debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); + return Some(in_incr_comp_dir(tcx.sess, &work_product.file_name).unwrap()); + } else { + debug!("trans_reuse_previous_work_products: \ + not reusing {:?} because hash changed to {:?}", + work_product, hash); + } + } + + None + }) + .collect() +} + fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> (Vec>, SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); @@ -2739,10 +2796,10 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a let mut item_to_cgus = HashMap::new(); for cgu in &codegen_units { - for (&trans_item, &linkage) in &cgu.items { + for (&trans_item, &linkage) in cgu.items() { item_to_cgus.entry(trans_item) .or_insert(Vec::new()) - .push((cgu.name.clone(), linkage)); + .push((cgu.name().clone(), linkage)); } } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index f662ba75cc6fe..571d2731fb216 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1029,7 +1029,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) assert!(!ccx.external_srcs().borrow().contains_key(&id)); let defined_in_current_codegen_unit = ccx.codegen_unit() - .items + .items() .contains_key(&TransItem::Static(id)); if defined_in_current_codegen_unit { if declare::get_declared_value(ccx, sym).is_none() { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 88903726d64f7..bf69629821285 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -40,6 +40,7 @@ use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; +use std::path::PathBuf; use std::marker::PhantomData; use std::ptr; use std::rc::Rc; @@ -95,6 +96,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, + previous_work_product: Option, tn: TypeNames, // FIXME: This seems to be largely unused. codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, @@ -198,24 +200,39 @@ pub struct CrateContextList<'a, 'tcx: 'a> { } impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { - pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, codegen_units: Vec>, + previous_work_products: Vec>, symbol_map: Rc>) -> CrateContextList<'a, 'tcx> { CrateContextList { shared: shared_ccx, - local_ccxs: codegen_units.into_iter().map(|codegen_unit| { - LocalCrateContext::new(shared_ccx, codegen_unit, symbol_map.clone()) + local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, path)| { + LocalCrateContext::new(shared_ccx, cgu, path, symbol_map.clone()) }).collect() } } - pub fn iter<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { + /// Iterate over all crate contexts, whether or not they need + /// translation. That is, whether or not a `.o` file is available + /// for re-use from a previous incr. comp.). + pub fn iter_all<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { CrateContextIterator { shared: self.shared, index: 0, - local_ccxs: &self.local_ccxs[..] + local_ccxs: &self.local_ccxs[..], + filter_to_previous_work_product_unavail: false, + } + } + + /// Iterator over all CCX that need translation (cannot reuse results from + /// previous incr. comp.). + pub fn iter_need_trans<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { + CrateContextIterator { + shared: self.shared, + index: 0, + local_ccxs: &self.local_ccxs[..], + filter_to_previous_work_product_unavail: true, } } @@ -239,24 +256,38 @@ pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], index: usize, + + /// if true, only return results where `previous_work_product` is none + filter_to_previous_work_product_unavail: bool, } impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { type Item = CrateContext<'a, 'tcx>; fn next(&mut self) -> Option> { - if self.index >= self.local_ccxs.len() { - return None; - } + loop { + if self.index >= self.local_ccxs.len() { + return None; + } - let index = self.index; - self.index += 1; + let index = self.index; + self.index += 1; - Some(CrateContext { - shared: self.shared, - index: index, - local_ccxs: self.local_ccxs, - }) + let ccx = CrateContext { + shared: self.shared, + index: index, + local_ccxs: self.local_ccxs, + }; + + if + self.filter_to_previous_work_product_unavail && + ccx.previous_work_product().is_some() + { + continue; + } + + return Some(ccx); + } } } @@ -510,6 +541,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'tcx> LocalCrateContext<'tcx> { fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, codegen_unit: CodegenUnit<'tcx>, + previous_work_product: Option, symbol_map: Rc>) -> LocalCrateContext<'tcx> { unsafe { @@ -521,7 +553,7 @@ impl<'tcx> LocalCrateContext<'tcx> { // crashes if the module identifier is same as other symbols // such as a function name in the module. // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}.rs", codegen_unit.name); + let llmod_id = format!("{}.rs", codegen_unit.name()); let (llcx, llmod) = create_context_and_module(&shared.tcx.sess, &llmod_id[..]); @@ -535,6 +567,7 @@ impl<'tcx> LocalCrateContext<'tcx> { let local_ccx = LocalCrateContext { llmod: llmod, llcx: llcx, + previous_work_product: previous_work_product, codegen_unit: codegen_unit, tn: TypeNames::new(), needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()), @@ -694,6 +727,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().llcx } + pub fn previous_work_product(&self) -> Option<&PathBuf> { + self.local().previous_work_product.as_ref() + } + pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> { &self.local().codegen_unit } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index ef7d0ea165d60..6bc48546dfa8c 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -239,7 +239,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Falling back to on-demand instantiation.", g, TransItem::DropGlue(g).to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); ccx.stats().n_fallback_instantiations.set(ccx.stats() .n_fallback_instantiations diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index fa0a1fdc37523..6ac64d3291084 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -37,6 +37,8 @@ #![feature(unicode)] #![feature(question_mark)] +use std::path::PathBuf; + extern crate arena; extern crate flate; extern crate getopts; @@ -133,6 +135,18 @@ mod value; #[derive(Clone)] pub struct ModuleTranslation { pub name: String, + pub symbol_name_hash: u64, + pub source: ModuleSource, +} + +#[derive(Clone)] +pub enum ModuleSource { + Preexisting(PathBuf), + Translated(ModuleLlvm), +} + +#[derive(Copy, Clone)] +pub struct ModuleLlvm { pub llcx: llvm::ContextRef, pub llmod: llvm::ModuleRef, } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 00c0e91103500..96a05f11bfd11 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -52,7 +52,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("leaving monomorphic fn {:?}", instance); return (val, mono_ty); } else { - assert!(!ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance))); + assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance))); } debug!("monomorphic_fn({:?})", instance); diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 8073359ede87e..12df8bd83708c 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -119,12 +119,15 @@ use collector::InliningMap; use llvm; use monomorphize; +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::item_path::characteristic_def_id_of_type; use std::cmp::Ordering; +use std::hash::{Hash, Hasher, SipHasher}; +use std::sync::Arc; use symbol_map::SymbolMap; use syntax::ast::NodeId; use syntax::parse::token::{self, InternedString}; @@ -140,11 +143,54 @@ pub enum PartitioningStrategy { } pub struct CodegenUnit<'tcx> { - pub name: InternedString, - pub items: FnvHashMap, llvm::Linkage>, + name: InternedString, + items: FnvHashMap, llvm::Linkage>, } impl<'tcx> CodegenUnit<'tcx> { + pub fn new(name: InternedString, + items: FnvHashMap, llvm::Linkage>) + -> Self { + CodegenUnit { + name: name, + items: items, + } + } + + pub fn empty(name: InternedString) -> Self { + Self::new(name, FnvHashMap()) + } + + pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool { + self.items.contains_key(item) + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn items(&self) -> &FnvHashMap, llvm::Linkage> { + &self.items + } + + pub fn work_product_id(&self) -> Arc { + Arc::new(WorkProductId::PartitionObjectFile(self.name().to_string())) + } + + pub fn work_product_dep_node(&self) -> DepNode { + DepNode::WorkProduct(self.work_product_id()) + } + + pub fn compute_symbol_name_hash(&self, tcx: TyCtxt, symbol_map: &SymbolMap) -> u64 { + let mut state = SipHasher::new(); + let all_items = self.items_in_deterministic_order(tcx, symbol_map); + for (item, _) in all_items { + let symbol_name = symbol_map.get(item).unwrap(); + symbol_name.hash(&mut state); + } + state.finish() + } + pub fn items_in_deterministic_order(&self, tcx: TyCtxt, symbol_map: &SymbolMap) @@ -277,10 +323,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let make_codegen_unit = || { - CodegenUnit { - name: codegen_unit_name.clone(), - items: FnvHashMap(), - } + CodegenUnit::empty(codegen_unit_name.clone()) }; let mut codegen_unit = codegen_units.entry(codegen_unit_name.clone()) @@ -319,10 +362,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if codegen_units.is_empty() { let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT); codegen_units.entry(codegen_unit_name.clone()) - .or_insert_with(|| CodegenUnit { - name: codegen_unit_name.clone(), - items: FnvHashMap(), - }); + .or_insert_with(|| CodegenUnit::new(codegen_unit_name.clone(), + FnvHashMap())); } PreInliningPartitioning { @@ -362,10 +403,8 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // we reach the target count while codegen_units.len() < target_cgu_count { let index = codegen_units.len(); - codegen_units.push(CodegenUnit { - name: numbered_codegen_unit_name(crate_name, index), - items: FnvHashMap() - }); + codegen_units.push( + CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index))); } } @@ -381,10 +420,8 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit follow_inlining(*root, inlining_map, &mut reachable); } - let mut new_codegen_unit = CodegenUnit { - name: codegen_unit.name.clone(), - items: FnvHashMap(), - }; + let mut new_codegen_unit = + CodegenUnit::empty(codegen_unit.name.clone()); // Add all translation items that are not already there for trans_item in reachable { @@ -560,10 +597,9 @@ fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, items.insert(trans_item, linkage); } - CodegenUnit { - name: numbered_codegen_unit_name(&tcx.crate_name[..], 0), - items: items - } + CodegenUnit::new( + numbered_codegen_unit_name(&tcx.crate_name[..], 0), + items) } fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index fc95d208f32cc..3afedb4909067 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -23,12 +23,12 @@ use glue::DropGlueKind; use llvm; use monomorphize::{self, Instance}; use inline; +use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst; -use rustc::dep_graph::DepNode; use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; @@ -68,16 +68,27 @@ impl<'tcx> Hash for TransItem<'tcx> { impl<'a, 'tcx> TransItem<'tcx> { pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) { - debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); + + // (*) This code executes in the context of a dep-node for the + // entire CGU. In some cases, we introduce dep-nodes for + // particular items that we are translating (these nodes will + // have read edges coming into the CGU node). These smaller + // nodes are not needed for correctness -- we always + // invalidate an entire CGU at a time -- but they enable + // finer-grained testing, since you can write tests that check + // that the incoming edges to a particular fn are from a + // particular set. self.register_reads(ccx); match *self { TransItem::Static(node_id) => { + let def_id = ccx.tcx().map.local_def_id(node_id); + let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*) let item = ccx.tcx().map.expect_item(node_id); if let hir::ItemStatic(_, m, ref expr) = item.node { match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) { @@ -93,6 +104,13 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Fn(instance) => { + let _task; + + if instance.def.is_local() { + _task = ccx.tcx().dep_graph.in_task( + DepNode::TransCrateItem(instance.def)); // (*) + } + base::trans_instance(&ccx, instance); } TransItem::DropGlue(dg) => { @@ -103,7 +121,7 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("END IMPLEMENTING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); } /// If necessary, creates a subtask for trans'ing a particular item and registers reads on @@ -152,7 +170,7 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); let symbol_name = ccx.symbol_map() .get_or_compute(ccx.shared(), *self); @@ -174,7 +192,7 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("END PREDEFINING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); } fn predefine_static(ccx: &CrateContext<'a, 'tcx>, diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 2e90b51843263..b58295d47f21d 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -20,6 +20,7 @@ extern crate rustc_metadata; extern crate rustc_resolve; extern crate rustc_errors; extern crate rustc_errors as errors; +extern crate rustc_trans; #[macro_use] extern crate syntax; use std::ffi::{CStr, CString}; @@ -37,6 +38,7 @@ use rustc::session::build_session; use rustc_driver::{driver, abort_on_err}; use rustc_resolve::MakeGlobMap; use rustc_metadata::cstore::CStore; +use rustc_trans::ModuleSource; use libc::c_void; use rustc_errors::registry::Registry; @@ -261,7 +263,10 @@ fn compile_program(input: &str, sysroot: PathBuf) .filter_map(|(_, p)| p).collect(); assert_eq!(trans.modules.len(), 1); - let llmod = trans.modules[0].llmod; + let llmod = match trans.modules[0].source { + ModuleSource::Preexisting(_) => unimplemented!(), + ModuleSource::Translated(llvm) => llvm.llmod, + }; // Workaround because raw pointers do not impl Send let modp = llmod as usize; diff --git a/src/test/run-make/llvm-phase/test.rs b/src/test/run-make/llvm-phase/test.rs index 402b5ed83556c..19e410fef5388 100644 --- a/src/test/run-make/llvm-phase/test.rs +++ b/src/test/run-make/llvm-phase/test.rs @@ -13,11 +13,13 @@ extern crate rustc; extern crate rustc_driver; extern crate rustc_llvm; +extern crate rustc_trans; #[macro_use] extern crate syntax; extern crate getopts; use rustc_driver::{CompilerCalls, Compilation}; use rustc_driver::driver::CompileController; +use rustc_trans::ModuleSource; use rustc::session::Session; use syntax::codemap::FileLoader; use std::io; @@ -51,7 +53,10 @@ impl<'a> CompilerCalls<'a> for JitCalls { state.session.abort_if_errors(); let trans = state.trans.unwrap(); assert_eq!(trans.modules.len(), 1); - let rs_llmod = trans.modules[0].llmod; + let rs_llmod = match trans.modules[0].source { + ModuleSource::Preexisting(_) => unimplemented!(), + ModuleSource::Translated(llvm) => llvm.llmod, + }; unsafe { rustc_llvm::LLVMDumpModule(rs_llmod) }; }); cc From 08a72d20c9c97ab7b1d3b023d6cc0caddcd12f77 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:50:15 -0400 Subject: [PATCH 145/150] Add a testing mechanism and a simple spike test --- src/librustc_trans/assert_module_sources.rs | 149 ++++++++++++++++++++ src/librustc_trans/base.rs | 3 + src/librustc_trans/lib.rs | 1 + src/libsyntax/feature_gate.rs | 10 ++ src/test/incremental/spike-neg1.rs | 67 +++++++++ src/test/incremental/spike-neg2.rs | 67 +++++++++ src/test/incremental/spike.rs | 63 +++++++++ 7 files changed, 360 insertions(+) create mode 100644 src/librustc_trans/assert_module_sources.rs create mode 100644 src/test/incremental/spike-neg1.rs create mode 100644 src/test/incremental/spike-neg2.rs create mode 100644 src/test/incremental/spike.rs diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs new file mode 100644 index 0000000000000..e0532e7476f51 --- /dev/null +++ b/src/librustc_trans/assert_module_sources.rs @@ -0,0 +1,149 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This pass is only used for UNIT TESTS related to incremental +//! compilation. It tests whether a particular `.o` file will be re-used +//! from a previous compilation or whether it must be regenerated. +//! +//! The user adds annotations to the crate of the following form: +//! +//! ``` +//! #![rustc_partition_reused(module="spike", cfg="rpass2")] +//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")] +//! ``` +//! +//! The first indicates (in the cfg `rpass2`) that `spike.o` will be +//! reused, the second that `spike-x.o` will be recreated. If these +//! annotations are inaccurate, errors are reported. +//! +//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that +//! the HIR doesn't change as a result of the annotations, which might +//! perturb the reuse results. + +use rustc::ty::TyCtxt; +use syntax::ast; +use syntax::attr::AttrMetaMethods; +use syntax::parse::token::InternedString; + +use {ModuleSource, ModuleTranslation}; + +const PARTITION_REUSED: &'static str = "rustc_partition_reused"; +const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; + +const MODULE: &'static str = "module"; +const CFG: &'static str = "cfg"; + +#[derive(Debug, PartialEq)] +enum Disposition { Reused, Translated } + +pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + modules: &[ModuleTranslation]) { + let _ignore = tcx.dep_graph.in_ignore(); + + if tcx.sess.opts.incremental.is_none() { + return; + } + + let ams = AssertModuleSource { tcx: tcx, modules: modules }; + for attr in &tcx.map.krate().attrs { + ams.check_attr(attr); + } +} + +struct AssertModuleSource<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + modules: &'a [ModuleTranslation], +} + +impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { + fn check_attr(&self, attr: &ast::Attribute) { + let disposition = if attr.check_name(PARTITION_REUSED) { + Disposition::Reused + } else if attr.check_name(PARTITION_TRANSLATED) { + Disposition::Translated + } else { + return; + }; + + if !self.check_config(attr) { + debug!("check_attr: config does not match, ignoring attr"); + return; + } + + let mname = self.field(attr, MODULE); + let mtrans = self.modules.iter().find(|mtrans| &mtrans.name[..] == &mname[..]); + let mtrans = match mtrans { + Some(m) => m, + None => { + debug!("module name `{}` not found amongst:", mname); + for mtrans in self.modules { + debug!("module named `{}` with disposition {:?}", + mtrans.name, + self.disposition(mtrans)); + } + + self.tcx.sess.span_err( + attr.span, + &format!("no module named `{}`", mname)); + return; + } + }; + + let mtrans_disposition = self.disposition(mtrans); + if disposition != mtrans_disposition { + self.tcx.sess.span_err( + attr.span, + &format!("expected module named `{}` to be {:?} but is {:?}", + mname, + disposition, + mtrans_disposition)); + } + } + + fn disposition(&self, mtrans: &ModuleTranslation) -> Disposition { + match mtrans.source { + ModuleSource::Preexisting(_) => Disposition::Reused, + ModuleSource::Translated(_) => Disposition::Translated, + } + } + + fn field(&self, attr: &ast::Attribute, name: &str) -> InternedString { + for item in attr.meta_item_list().unwrap_or(&[]) { + if item.check_name(name) { + if let Some(value) = item.value_str() { + return value; + } else { + self.tcx.sess.span_fatal( + item.span, + &format!("associated value expected for `{}`", name)); + } + } + } + + self.tcx.sess.span_fatal( + attr.span, + &format!("no field `{}`", name)); + } + + /// Scan for a `cfg="foo"` attribute and check whether we have a + /// cfg flag called `foo`. + fn check_config(&self, attr: &ast::Attribute) -> bool { + let config = &self.tcx.map.krate().config; + let value = self.field(attr, CFG); + debug!("check_config(config={:?}, value={:?})", config, value); + if config.iter().any(|c| c.check_name(&value[..])) { + debug!("check_config: matched"); + return true; + } + debug!("check_config: no match found"); + return false; + } + +} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a77ababaa6355..69a884431359d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -30,6 +30,7 @@ use super::ModuleLlvm; use super::ModuleSource; use super::ModuleTranslation; +use assert_module_sources; use back::link; use back::linker::LinkerInfo; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; @@ -2558,6 +2559,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .collect(); + assert_module_sources::assert_module_sources(tcx, &modules); + // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.no_trans { let linker_info = LinkerInfo::new(&shared_ccx, &[]); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6ac64d3291084..67475081caec7 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -88,6 +88,7 @@ mod macros; mod abi; mod adt; mod asm; +mod assert_module_sources; mod attributes; mod base; mod basic_block; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 27485ee65fcc0..f80f25a2e776d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -481,6 +481,16 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), diff --git a/src/test/incremental/spike-neg1.rs b/src/test/incremental/spike-neg1.rs new file mode 100644 index 0000000000000..e84906d12d0ce --- /dev/null +++ b/src/test/incremental/spike-neg1.rs @@ -0,0 +1,67 @@ +// 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. + +// A variant of the first "spike" test that serves to test the +// `rustc_partition_reused` and `rustc_partition_translated` tests. +// Here we change and say that the `x` module will be reused (when in +// fact it will not), and then indicate that the test itself +// should-fail (because an error will be reported, and hence the +// revision rpass2 will not compile, despite being named rpass). + +// revisions:rpass1 rpass2 +// should-fail + +#![feature(rustc_attrs)] + +#![rustc_partition_reused(module="spike_neg1", cfg="rpass2")] +#![rustc_partition_reused(module="spike_neg1-x", cfg="rpass2")] // this is wrong! +#![rustc_partition_reused(module="spike_neg1-y", cfg="rpass2")] + +mod x { + pub struct X { + x: u32, y: u32, + } + + #[cfg(rpass1)] + fn make() -> X { + X { x: 22, y: 0 } + } + + #[cfg(rpass2)] + fn make() -> X { + X { x: 11, y: 11 } + } + + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn new() -> X { + make() + } + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn sum(x: &X) -> u32 { + x.x + x.y + } +} + +mod y { + use x; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn assert_sum() -> bool { + let x = x::new(); + x::sum(&x) == 22 + } +} + +pub fn main() { + y::assert_sum(); +} diff --git a/src/test/incremental/spike-neg2.rs b/src/test/incremental/spike-neg2.rs new file mode 100644 index 0000000000000..40f4b4f0c44ce --- /dev/null +++ b/src/test/incremental/spike-neg2.rs @@ -0,0 +1,67 @@ +// 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. + +// A variant of the first "spike" test that serves to test the +// `rustc_partition_reused` and `rustc_partition_translated` tests. +// Here we change and say that the `y` module will be translated (when +// in fact it will not), and then indicate that the test itself +// should-fail (because an error will be reported, and hence the +// revision rpass2 will not compile, despite being named rpass). + +// revisions:rpass1 rpass2 +// should-fail + +#![feature(rustc_attrs)] + +#![rustc_partition_reused(module="spike_neg2", cfg="rpass2")] +#![rustc_partition_translated(module="spike_neg2-x", cfg="rpass2")] +#![rustc_partition_translated(module="spike_neg2-y", cfg="rpass2")] // this is wrong! + +mod x { + pub struct X { + x: u32, y: u32, + } + + #[cfg(rpass1)] + fn make() -> X { + X { x: 22, y: 0 } + } + + #[cfg(rpass2)] + fn make() -> X { + X { x: 11, y: 11 } + } + + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn new() -> X { + make() + } + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn sum(x: &X) -> u32 { + x.x + x.y + } +} + +mod y { + use x; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn assert_sum() -> bool { + let x = x::new(); + x::sum(&x) == 22 + } +} + +pub fn main() { + y::assert_sum(); +} diff --git a/src/test/incremental/spike.rs b/src/test/incremental/spike.rs new file mode 100644 index 0000000000000..68af20d419151 --- /dev/null +++ b/src/test/incremental/spike.rs @@ -0,0 +1,63 @@ +// 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. + +// A first "spike" for incremental compilation: here, we change the +// content of the `make` function, and we find that we can reuse the +// `y` module entirely (but not the `x` module). + +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + +#![rustc_partition_reused(module="spike", cfg="rpass2")] +#![rustc_partition_translated(module="spike-x", cfg="rpass2")] +#![rustc_partition_reused(module="spike-y", cfg="rpass2")] + +mod x { + pub struct X { + x: u32, y: u32, + } + + #[cfg(rpass1)] + fn make() -> X { + X { x: 22, y: 0 } + } + + #[cfg(rpass2)] + fn make() -> X { + X { x: 11, y: 11 } + } + + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn new() -> X { + make() + } + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn sum(x: &X) -> u32 { + x.x + x.y + } +} + +mod y { + use x; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn assert_sum() -> bool { + let x = x::new(); + x::sum(&x) == 22 + } +} + +pub fn main() { + y::assert_sum(); +} From ceeb158e0a04c3a73a4c5014609020ee628b4c06 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 Jul 2016 10:39:30 -0400 Subject: [PATCH 146/150] Address mw nits --- src/librustc/dep_graph/graph.rs | 10 ++++---- src/librustc/util/fs.rs | 14 +++++++++++ src/librustc_driver/driver.rs | 24 +++++++++---------- src/librustc_incremental/persist/load.rs | 11 +++++---- .../persist/work_product.rs | 6 ++--- src/librustc_trans/back/write.rs | 12 +--------- src/librustc_trans/base.rs | 13 ++++++++-- src/librustc_trans/partitioning.rs | 3 +-- src/librustc_trans/trans_item.rs | 8 ++----- src/test/incremental/spike-neg1.rs | 5 ---- src/test/incremental/spike-neg2.rs | 5 ---- 11 files changed, 54 insertions(+), 57 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index ab7013df33f14..8691894b32513 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -25,17 +25,17 @@ pub struct DepGraph { } struct DepGraphData { - /// we send messages to the thread to let it build up the dep-graph - /// from the current run + /// We send messages to the thread to let it build up the dep-graph + /// from the current run. thread: DepGraphThreadData, - /// when we load, there may be `.o` files, cached mir, or other such + /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. previous_work_products: RefCell, WorkProduct>>, - /// work-products that we generate in this run + /// Work-products that we generate in this run. work_products: RefCell, WorkProduct>>, } @@ -132,7 +132,7 @@ impl DepGraph { /// Each work product is associated with a dep-node, representing the /// process that produced the work-product. If that dep-node is found /// to be dirty when we load up, then we will delete the work-product -/// at load time. If the work-product is found to be clean, the we +/// at load time. If the work-product is found to be clean, then we /// will keep a record in the `previous_work_products` list. /// /// In addition, work products have an associated hash. This hash is diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index 4936e049ef2ee..f4e1c06090e59 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -10,6 +10,8 @@ use std::path::{self, Path, PathBuf}; use std::ffi::OsString; +use std::fs; +use std::io; // Unfortunately, on windows, it looks like msvcrt.dll is silently translating // verbatim paths under the hood to non-verbatim paths! This manifests itself as @@ -53,3 +55,15 @@ pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { _ => p.to_path_buf(), } } + +/// Copy `p` into `q`, preferring to use hard-linking if possible. If +/// `q` already exists, it is removed first. +pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result<()> { + let p = p.as_ref(); + let q = q.as_ref(); + if q.exists() { + try!(fs::remove_file(&q)); + } + fs::hard_link(p, q) + .or_else(|_| fs::copy(p, q).map(|_| ())) +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a48ff2533485c..f172f38b80968 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -88,7 +88,7 @@ pub fn compile_input(sess: &Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans, id) = { + let (outputs, trans, crate_name) = { let krate = match phase_1_parse_input(sess, cfg, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -113,13 +113,13 @@ pub fn compile_input(sess: &Session, }; let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); - let id = link::find_crate_name(Some(sess), &krate.attrs, input); + let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input); let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = { phase_2_configure_and_expand( - sess, &cstore, krate, &id, addl_plugins, control.make_glob_map, + sess, &cstore, krate, &crate_name, addl_plugins, control.make_glob_map, |expanded_crate| { let mut state = CompileState::state_after_expand( - input, sess, outdir, output, &cstore, expanded_crate, &id, + input, sess, outdir, output, &cstore, expanded_crate, &crate_name, ); controller_entry_point!(after_expand, sess, state, Ok(())); Ok(()) @@ -127,7 +127,7 @@ pub fn compile_input(sess: &Session, )? }; - write_out_deps(sess, &outputs, &id); + write_out_deps(sess, &outputs, &crate_name); let arenas = ty::CtxtArenas::new(); @@ -151,7 +151,7 @@ pub fn compile_input(sess: &Session, &resolutions, &expanded_crate, &hir_map.krate(), - &id), + &crate_name), Ok(())); } @@ -171,7 +171,7 @@ pub fn compile_input(sess: &Session, analysis, resolutions, &arenas, - &id, + &crate_name, |tcx, mir_map, analysis, result| { { // Eventually, we will want to track plugins. @@ -186,7 +186,7 @@ pub fn compile_input(sess: &Session, &analysis, mir_map.as_ref(), tcx, - &id); + &crate_name); (control.after_analysis.callback)(&mut state); if control.after_analysis.stop == Compilation::Stop { @@ -212,11 +212,11 @@ pub fn compile_input(sess: &Session, // Discard interned strings as they are no longer required. token::clear_ident_interner(); - Ok((outputs, trans, id.clone())) + Ok((outputs, trans, crate_name.clone())) })?? }; - let phase5_result = phase_5_run_llvm_passes(sess, &id, &trans, &outputs); + let phase5_result = phase_5_run_llvm_passes(sess, &crate_name, &trans, &outputs); controller_entry_point!(after_llvm, sess, @@ -1069,14 +1069,14 @@ fn escape_dep_filename(filename: &str) -> String { filename.replace(" ", "\\ ") } -fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) { +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) { let mut out_filenames = Vec::new(); for output_type in sess.opts.output_types.keys() { let file = outputs.path(*output_type); match *output_type { OutputType::Exe => { for output in sess.crate_types.borrow().iter() { - let p = link::filename_for_input(sess, *output, id, outputs); + let p = link::filename_for_input(sess, *output, crate_name, outputs); out_filenames.push(p); } } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 9fef2285aa7eb..6b856459aabfe 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -63,10 +63,13 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) { Ok(()) => return, - Err(err) => bug!("decoding error in dep-graph from `{}` and `{}`: {}", + Err(err) => { + tcx.sess.warn( + &format!("decoding error in dep-graph from `{}` and `{}`: {}", dep_graph_path.display(), work_products_path.display(), - err), + err)); + } } } @@ -94,9 +97,7 @@ fn load_data(sess: &Session, path: &Path) -> Option> { } /// Decode the dep graph and load the edges/nodes that are still clean -/// into `tcx.dep_graph`. On success, returns a hashset containing all -/// the paths of work-products from clean nodes (any work-products not -/// in this set can be deleted). +/// into `tcx.dep_graph`. pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, dep_graph_data: &[u8], work_products_data: &[u8]) diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index 01ac3f6c391d9..7695291bf620b 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -13,6 +13,7 @@ use persist::util::*; use rustc::dep_graph::{WorkProduct, WorkProductId}; use rustc::session::Session; +use rustc::util::fs::link_or_copy; use std::fs; use std::path::Path; use std::sync::Arc; @@ -39,10 +40,7 @@ pub fn save_trans_partition(sess: &Session, let _ = fs::remove_file(&path_in_incr_dir); } - match - fs::hard_link(path_to_obj_file, &path_in_incr_dir) - .or_else(|_| fs::copy(path_to_obj_file, &path_in_incr_dir).map(|_| ())) - { + match link_or_copy(path_to_obj_file, &path_in_incr_dir) { Ok(_) => { let work_product = WorkProduct { input_hash: partition_hash, diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 70925218781bd..08d7b531c2f1b 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -20,6 +20,7 @@ use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation}; use util::common::time; use util::common::path2cstr; +use util::fs::link_or_copy; use errors::{self, Handler, Level, DiagnosticBuilder}; use errors::emitter::Emitter; use syntax_pos::MultiSpan; @@ -27,7 +28,6 @@ use syntax_pos::MultiSpan; use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs; -use std::io; use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; @@ -929,16 +929,6 @@ fn build_work_item(sess: &Session, } } -fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result<()> { - let p = p.as_ref(); - let q = q.as_ref(); - if q.exists() { - try!(fs::remove_file(&q)); - } - fs::hard_link(p, q) - .or_else(|_| fs::copy(p, q).map(|_| ())) -} - fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) { unsafe { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 69a884431359d..e73c4f41c9412 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2262,12 +2262,20 @@ fn write_metadata(cx: &SharedCrateContext, /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. -fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>, +fn internalize_symbols<'a, 'tcx>(sess: &Session, + ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, reachable: &FnvHashSet<&str>) { let scx = ccxs.shared(); let tcx = scx.tcx(); + // In incr. comp. mode, we can't necessarily see all refs since we + // don't generate LLVM IR for reused modules, so skip this + // step. Later we should get smarter. + if sess.opts.debugging_opts.incremental.is_some() { + return; + } + // 'unsafe' because we are holding on to CStr's from the LLVM module within // this block. unsafe { @@ -2682,7 +2690,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } time(shared_ccx.sess().time_passes(), "internalize symbols", || { - internalize_symbols(&crate_context_list, + internalize_symbols(sess, + &crate_context_list, &symbol_map, &reachable_symbols.iter() .map(|s| &s[..]) diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 12df8bd83708c..32bcbf9f7562b 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -362,8 +362,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if codegen_units.is_empty() { let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT); codegen_units.entry(codegen_unit_name.clone()) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name.clone(), - FnvHashMap())); + .or_insert_with(|| CodegenUnit::empty(codegen_unit_name.clone())); } PreInliningPartitioning { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 3afedb4909067..fc2758e50f2ce 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -104,12 +104,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Fn(instance) => { - let _task; - - if instance.def.is_local() { - _task = ccx.tcx().dep_graph.in_task( - DepNode::TransCrateItem(instance.def)); // (*) - } + let _task = ccx.tcx().dep_graph.in_task( + DepNode::TransCrateItem(instance.def)); // (*) base::trans_instance(&ccx, instance); } diff --git a/src/test/incremental/spike-neg1.rs b/src/test/incremental/spike-neg1.rs index e84906d12d0ce..b00c68a184ed0 100644 --- a/src/test/incremental/spike-neg1.rs +++ b/src/test/incremental/spike-neg1.rs @@ -39,14 +39,10 @@ mod x { X { x: 11, y: 11 } } - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] - #[rustc_clean(label="ItemSignature", cfg="rpass2")] pub fn new() -> X { make() } - #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] - #[rustc_clean(label="ItemSignature", cfg="rpass2")] pub fn sum(x: &X) -> u32 { x.x + x.y } @@ -55,7 +51,6 @@ mod x { mod y { use x; - #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn assert_sum() -> bool { let x = x::new(); x::sum(&x) == 22 diff --git a/src/test/incremental/spike-neg2.rs b/src/test/incremental/spike-neg2.rs index 40f4b4f0c44ce..472d11d7f9028 100644 --- a/src/test/incremental/spike-neg2.rs +++ b/src/test/incremental/spike-neg2.rs @@ -39,14 +39,10 @@ mod x { X { x: 11, y: 11 } } - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] - #[rustc_clean(label="ItemSignature", cfg="rpass2")] pub fn new() -> X { make() } - #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] - #[rustc_clean(label="ItemSignature", cfg="rpass2")] pub fn sum(x: &X) -> u32 { x.x + x.y } @@ -55,7 +51,6 @@ mod x { mod y { use x; - #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn assert_sum() -> bool { let x = x::new(); x::sum(&x) == 22 From 2f9fff21911a3e419b21e56dba145bf0deab6f81 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 25 Jul 2016 10:51:14 -0400 Subject: [PATCH 147/150] Keep multiple files per work-product In the older version, a `.o` and ` .bc` file were separate work-products. This newer version keeps, for each codegen-unit, a set of files of different kinds. We assume that if any kinds are available then all the kinds we need are available, since the precise set of switches will depend on attributes and command-line switches. Should probably test this: the effect of changing attributes in particular might not be successfully tracked? --- src/librustc/dep_graph/dep_node.rs | 4 +- src/librustc/dep_graph/graph.rs | 7 +- src/librustc/session/config.rs | 23 ++++--- src/librustc_incremental/persist/load.rs | 31 ++++++--- .../persist/work_product.rs | 68 ++++++++++--------- src/librustc_trans/back/write.rs | 56 ++++++++++----- src/librustc_trans/base.rs | 8 +-- src/librustc_trans/context.rs | 15 ++-- src/librustc_trans/lib.rs | 12 +++- src/librustc_trans/partitioning.rs | 7 +- .../rlib_cross_crate/auxiliary/a.rs | 25 +++++++ src/test/incremental/rlib_cross_crate/b.rs | 38 +++++++++++ 12 files changed, 202 insertions(+), 92 deletions(-) create mode 100644 src/test/incremental/rlib_cross_crate/auxiliary/a.rs create mode 100644 src/test/incremental/rlib_cross_crate/b.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index dd7f0286574d0..c9247539990a9 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -246,7 +246,5 @@ impl DepNode { /// the need to be mapped or unmapped. (This ensures we can serialize /// them even in the absence of a tcx.) #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub enum WorkProductId { - PartitionObjectFile(String), // see (*TransPartition) below -} +pub struct WorkProductId(pub String); diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 8691894b32513..bb027b11b45af 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -10,6 +10,7 @@ use hir::def_id::DefId; use rustc_data_structures::fnv::FnvHashMap; +use session::config::OutputType; use std::cell::{Ref, RefCell}; use std::rc::Rc; use std::sync::Arc; @@ -157,11 +158,11 @@ impl DepGraph { /// previous hash. If it matches up, we can reuse the object file. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct WorkProduct { - /// extra hash used to decide if work-product is still suitable; + /// Extra hash used to decide if work-product is still suitable; /// note that this is *not* a hash of the work-product itself. /// See documentation on `WorkProduct` type for an example. pub input_hash: u64, - /// filename storing this work-product (found in the incr. comp. directory) - pub file_name: String, + /// Saved files associated with this CGU + pub saved_files: Vec<(OutputType, String)>, } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a0c2416d24cff..690395399efa1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -61,7 +61,7 @@ pub enum DebugInfoLevel { FullDebugInfo, } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum OutputType { Bitcode, Assembly, @@ -105,6 +105,17 @@ impl OutputType { OutputType::DepInfo => "dep-info", } } + + pub fn extension(&self) -> &'static str { + match *self { + OutputType::Bitcode => "bc", + OutputType::Assembly => "s", + OutputType::LlvmAssembly => "ll", + OutputType::Object => "o", + OutputType::DepInfo => "d", + OutputType::Exe => "", + } + } } #[derive(Clone)] @@ -215,15 +226,7 @@ impl OutputFilenames { flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf { - let extension = match flavor { - OutputType::Bitcode => "bc", - OutputType::Assembly => "s", - OutputType::LlvmAssembly => "ll", - OutputType::Object => "o", - OutputType::DepInfo => "d", - OutputType::Exe => "", - }; - + let extension = flavor.extension(); self.temp_path_ext(extension, codegen_unit_name) } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 6b856459aabfe..36b6c79c40f5d 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -260,11 +260,20 @@ fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("reconcile_work_products: dep-node for {:?} is dirty", swp); delete_dirty_work_product(tcx, swp); } else { - let path = in_incr_comp_dir(tcx.sess, &swp.work_product.file_name).unwrap(); - if path.exists() { + let all_files_exist = + swp.work_product + .saved_files + .iter() + .all(|&(_, ref file_name)| { + let path = in_incr_comp_dir(tcx.sess, &file_name).unwrap(); + path.exists() + }); + if all_files_exist { + debug!("reconcile_work_products: all files for {:?} exist", swp); tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product); } else { - debug!("reconcile_work_products: file for {:?} does not exist", swp); + debug!("reconcile_work_products: some file for {:?} does not exist", swp); + delete_dirty_work_product(tcx, swp); } } } @@ -273,13 +282,15 @@ fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn delete_dirty_work_product(tcx: TyCtxt, swp: SerializedWorkProduct) { debug!("delete_dirty_work_product({:?})", swp); - let path = in_incr_comp_dir(tcx.sess, &swp.work_product.file_name).unwrap(); - match fs::remove_file(&path) { - Ok(()) => { } - Err(err) => { - tcx.sess.warn( - &format!("file-system error deleting outdated file `{}`: {}", - path.display(), err)); + for &(_, ref file_name) in &swp.work_product.saved_files { + let path = in_incr_comp_dir(tcx.sess, file_name).unwrap(); + match fs::remove_file(&path) { + Ok(()) => { } + Err(err) => { + tcx.sess.warn( + &format!("file-system error deleting outdated file `{}`: {}", + path.display(), err)); + } } } } diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index 7695291bf620b..c106ea8f26269 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -13,47 +13,51 @@ use persist::util::*; use rustc::dep_graph::{WorkProduct, WorkProductId}; use rustc::session::Session; +use rustc::session::config::OutputType; use rustc::util::fs::link_or_copy; -use std::fs; -use std::path::Path; +use std::path::PathBuf; use std::sync::Arc; pub fn save_trans_partition(sess: &Session, - partition_name: &str, + cgu_name: &str, partition_hash: u64, - path_to_obj_file: &Path) { - debug!("save_trans_partition({:?},{},{})", - partition_name, + files: &[(OutputType, PathBuf)]) { + debug!("save_trans_partition({:?},{},{:?})", + cgu_name, partition_hash, - path_to_obj_file.display()); + files); if sess.opts.incremental.is_none() { return; } - let id = Arc::new(WorkProductId::PartitionObjectFile(partition_name.to_string())); - let file_name = format!("cgu-{}", partition_name); - let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap(); + let work_product_id = Arc::new(WorkProductId(cgu_name.to_string())); - // try to delete the file if it already exists - // - // FIXME(#34955) we can be smarter here -- if we are re-using, no need to do anything - if path_in_incr_dir.exists() { - let _ = fs::remove_file(&path_in_incr_dir); - } + let saved_files: Option> = + files.iter() + .map(|&(kind, ref path)| { + let file_name = format!("cgu-{}.{}", cgu_name, kind.extension()); + let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap(); + match link_or_copy(path, &path_in_incr_dir) { + Ok(_) => Some((kind, file_name)), + Err(err) => { + sess.warn(&format!("error copying object file `{}` \ + to incremental directory as `{}`: {}", + path.display(), + path_in_incr_dir.display(), + err)); + None + } + } + }) + .collect(); + let saved_files = match saved_files { + Some(v) => v, + None => return, + }; - match link_or_copy(path_to_obj_file, &path_in_incr_dir) { - Ok(_) => { - let work_product = WorkProduct { - input_hash: partition_hash, - file_name: file_name, - }; - sess.dep_graph.insert_work_product(&id, work_product); - } - Err(err) => { - sess.warn(&format!("error copying object file `{}` \ - to incremental directory as `{}`: {}", - path_to_obj_file.display(), - path_in_incr_dir.display(), - err)); - } - } + let work_product = WorkProduct { + input_hash: partition_hash, + saved_files: saved_files, + }; + + sess.dep_graph.insert_work_product(&work_product_id, work_product); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 08d7b531c2f1b..4b9d5dd9e8d67 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -337,6 +337,8 @@ struct CodegenContext<'a> { remark: Passes, // Worker thread number worker: usize, + // Directory where incremental data is stored (if any) + incremental: Option, } impl<'a> CodegenContext<'a> { @@ -347,6 +349,7 @@ impl<'a> CodegenContext<'a> { plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), worker: 0, + incremental: sess.opts.incremental.clone(), } } } @@ -612,7 +615,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if copy_bc_to_obj { debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); - if let Err(e) = fs::copy(&bc_out, &obj_out) { + if let Err(e) = link_or_copy(&bc_out, &obj_out) { cgcx.handler.err(&format!("failed to copy bitcode to object file: {}", e)); } } @@ -754,9 +757,19 @@ pub fn run_passes(sess: &Session, // If in incr. comp. mode, preserve the `.o` files for potential re-use for mtrans in trans.modules.iter() { - let path_to_obj = crate_output.temp_path(OutputType::Object, Some(&mtrans.name)); - debug!("wrote module {:?} to {:?}", mtrans.name, path_to_obj); - save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &path_to_obj); + let mut files = vec![]; + + if modules_config.emit_obj { + let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name)); + files.push((OutputType::Object, path)); + } + + if modules_config.emit_bc { + let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name)); + files.push((OutputType::Bitcode, path)); + } + + save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files); } // All codegen is finished. @@ -941,20 +954,24 @@ fn execute_work_item(cgcx: &CodegenContext, work_item.config, work_item.output_names); } - ModuleSource::Preexisting(ref buf) => { - let obj_out = work_item.output_names.temp_path(OutputType::Object, - Some(&work_item.mtrans.name)); - debug!("copying pre-existing module `{}` from {} to {}", - work_item.mtrans.name, - buf.display(), - obj_out.display()); - match link_or_copy(buf, &obj_out) { - Ok(()) => { } - Err(err) => { - cgcx.handler.err(&format!("unable to copy {} to {}: {}", - buf.display(), - obj_out.display(), - err)); + ModuleSource::Preexisting(wp) => { + let incremental = cgcx.incremental.as_ref().unwrap(); + let name = &work_item.mtrans.name; + for (kind, saved_file) in wp.saved_files { + let obj_out = work_item.output_names.temp_path(kind, Some(name)); + let source_file = incremental.join(&saved_file); + debug!("copying pre-existing module `{}` from {:?} to {}", + work_item.mtrans.name, + source_file, + obj_out.display()); + match link_or_copy(&source_file, &obj_out) { + Ok(()) => { } + Err(err) => { + cgcx.handler.err(&format!("unable to copy {} to {}: {}", + source_file.display(), + obj_out.display(), + err)); + } } } } @@ -994,6 +1011,8 @@ fn run_work_multithreaded(sess: &Session, let mut tx = Some(tx); futures.push(rx); + let incremental = sess.opts.incremental.clone(); + thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || { let diag_handler = Handler::with_emitter(true, false, box diag_emitter); @@ -1005,6 +1024,7 @@ fn run_work_multithreaded(sess: &Session, plugin_passes: plugin_passes, remark: remark, worker: i, + incremental: incremental, }; loop { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index e73c4f41c9412..5a19ddff7462a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -43,10 +43,9 @@ use rustc::ty::subst::{self, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; -use rustc_incremental::in_incr_comp_dir; use rustc::mir::mir_map::MirMap; use rustc_data_structures::graph::OUTGOING; use session::config::{self, NoDebugInfo, FullDebugInfo}; @@ -103,7 +102,6 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::ptr; use std::rc::Rc; -use std::path::PathBuf; use std::str; use std::{i8, i16, i32, i64}; use syntax_pos::{Span, DUMMY_SP}; @@ -2721,7 +2719,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn trans_reuse_previous_work_products(tcx: TyCtxt, codegen_units: &[CodegenUnit], symbol_map: &SymbolMap) - -> Vec> { + -> Vec> { debug!("trans_reuse_previous_work_products()"); codegen_units .iter() @@ -2735,7 +2733,7 @@ fn trans_reuse_previous_work_products(tcx: TyCtxt, if let Some(work_product) = tcx.dep_graph.previous_work_product(&id) { if work_product.input_hash == hash { debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); - return Some(in_incr_comp_dir(tcx.sess, &work_product.file_name).unwrap()); + return Some(work_product); } else { debug!("trans_reuse_previous_work_products: \ not reusing {:?} because hash changed to {:?}", diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index bf69629821285..a8f8474e94070 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef}; -use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig}; +use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; @@ -40,7 +40,6 @@ use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; -use std::path::PathBuf; use std::marker::PhantomData; use std::ptr; use std::rc::Rc; @@ -96,7 +95,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, - previous_work_product: Option, + previous_work_product: Option, tn: TypeNames, // FIXME: This seems to be largely unused. codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, @@ -202,13 +201,13 @@ pub struct CrateContextList<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, codegen_units: Vec>, - previous_work_products: Vec>, + previous_work_products: Vec>, symbol_map: Rc>) -> CrateContextList<'a, 'tcx> { CrateContextList { shared: shared_ccx, - local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, path)| { - LocalCrateContext::new(shared_ccx, cgu, path, symbol_map.clone()) + local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, wp)| { + LocalCrateContext::new(shared_ccx, cgu, wp, symbol_map.clone()) }).collect() } } @@ -541,7 +540,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'tcx> LocalCrateContext<'tcx> { fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, codegen_unit: CodegenUnit<'tcx>, - previous_work_product: Option, + previous_work_product: Option, symbol_map: Rc>) -> LocalCrateContext<'tcx> { unsafe { @@ -727,7 +726,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().llcx } - pub fn previous_work_product(&self) -> Option<&PathBuf> { + pub fn previous_work_product(&self) -> Option<&WorkProduct> { self.local().previous_work_product.as_ref() } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 67475081caec7..81a1dbeb7fe74 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -37,7 +37,7 @@ #![feature(unicode)] #![feature(question_mark)] -use std::path::PathBuf; +use rustc::dep_graph::WorkProduct; extern crate arena; extern crate flate; @@ -135,6 +135,11 @@ mod value; #[derive(Clone)] pub struct ModuleTranslation { + /// The name of the module. When the crate may be saved between + /// compilations, incremental compilation requires that name be + /// unique amongst **all** crates. Therefore, it should contain + /// something unique to this crate (e.g., a module path) as well + /// as the crate name and disambiguator. pub name: String, pub symbol_name_hash: u64, pub source: ModuleSource, @@ -142,7 +147,10 @@ pub struct ModuleTranslation { #[derive(Clone)] pub enum ModuleSource { - Preexisting(PathBuf), + /// Copy the `.o` files or whatever from the incr. comp. directory. + Preexisting(WorkProduct), + + /// Rebuild from this LLVM module. Translated(ModuleLlvm), } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 32bcbf9f7562b..ade6e8abeb32a 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -143,7 +143,12 @@ pub enum PartitioningStrategy { } pub struct CodegenUnit<'tcx> { + /// A name for this CGU. Incremental compilation requires that + /// name be unique amongst **all** crates. Therefore, it should + /// contain something unique to this crate (e.g., a module path) + /// as well as the crate name and disambiguator. name: InternedString, + items: FnvHashMap, llvm::Linkage>, } @@ -174,7 +179,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn work_product_id(&self) -> Arc { - Arc::new(WorkProductId::PartitionObjectFile(self.name().to_string())) + Arc::new(WorkProductId(self.name().to_string())) } pub fn work_product_dep_node(&self) -> DepNode { diff --git a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs new file mode 100644 index 0000000000000..ff5fd63471449 --- /dev/null +++ b/src/test/incremental/rlib_cross_crate/auxiliary/a.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. + +// no-prefer-dynamic + +#![crate_type="rlib"] + +#[cfg(rpass1)] +pub type X = u32; + +#[cfg(rpass2)] +pub type X = i32; + +// this version doesn't actually change anything: +#[cfg(rpass3)] +pub type X = i32; + +pub type Y = char; diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs new file mode 100644 index 0000000000000..55398370425a3 --- /dev/null +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -0,0 +1,38 @@ +// 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. + +// Same test as `type_alias_cross_crate`, but with +// `no-prefer-dynamic`, ensuring that we test what happens when we +// build rlibs (before we were only testing dylibs, which meant we +// didn't realize we had to preserve a `bc` file as well). + +// aux-build:a.rs +// revisions:rpass1 rpass2 rpass3 +// no-prefer-dynamic + + +#![feature(rustc_attrs)] + +extern crate a; + +#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] +#[rustc_clean(label="TypeckItemBody", cfg="rpass3")] +pub fn use_X() -> u32 { + let x: a::X = 22; + x as u32 +} + +#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +#[rustc_clean(label="TypeckItemBody", cfg="rpass3")] +pub fn use_Y() { + let x: a::Y = 'c'; +} + +pub fn main() { } From e359147d1214c6fe8e010118c5df05ca10f0a2b9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 28 Jul 2016 15:39:02 -0400 Subject: [PATCH 148/150] hash def-path's better actually we shouldn't even hash nested items at all, but that is addressed in a followup PR --- src/librustc_incremental/calculate_svh.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index 70704f5dec0d2..d433bdea6ecaa 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -119,6 +119,7 @@ mod svh_visitor { use rustc::ty::TyCtxt; use rustc::hir; use rustc::hir::*; + use rustc::hir::map::DefPath; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, FnKind}; @@ -135,6 +136,15 @@ mod svh_visitor { -> Self { StrictVersionHashVisitor { st: st, tcx: tcx } } + + fn hash_def_path(&mut self, path: &DefPath) { + self.tcx.crate_name(path.krate).hash(self.st); + self.tcx.crate_disambiguator(path.krate).hash(self.st); + for data in &path.data { + data.data.as_interned_str().hash(self.st); + data.disambiguator.hash(self.st); + } + } } // To off-load the bulk of the hash-computation on #[derive(Hash)], @@ -289,9 +299,9 @@ mod svh_visitor { impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { fn visit_nested_item(&mut self, item: ItemId) { - debug!("visit_nested_item: {:?} st={:?}", item, self.st); - let def_path = self.tcx.map.def_path_from_id(item.id); - def_path.hash(self.st); + let def_path = self.tcx.map.def_path_from_id(item.id).unwrap(); + debug!("visit_nested_item: def_path={:?} st={:?}", def_path, self.st); + self.hash_def_path(&def_path); } fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, From 42cd5d4ee28a1c1b3bf4f07e27b1ca5a03fd9b02 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 28 Jul 2016 15:39:34 -0400 Subject: [PATCH 149/150] make it possible to track where hash diverges --- src/librustc_incremental/calculate_svh.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index d433bdea6ecaa..7b1e0d2d0c8b6 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -306,12 +306,14 @@ mod svh_visitor { fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, g: &'a Generics, _: NodeId, _: Span) { + debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); visit::walk_generics(self, g); visit::walk_struct_def(self, s) } fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + debug!("visit_variant: st={:?}", self.st); SawVariant.hash(self.st); // walk_variant does not call walk_generics, so do it here. visit::walk_generics(self, g); @@ -333,14 +335,17 @@ mod svh_visitor { // pattern, please move that method up above this comment.) fn visit_name(&mut self, _: Span, name: Name) { + debug!("visit_name: st={:?}", self.st); SawIdent(name.as_str()).hash(self.st); } fn visit_lifetime(&mut self, l: &'a Lifetime) { + debug!("visit_lifetime: st={:?}", self.st); SawLifetime(l.name.as_str()).hash(self.st); } fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) { + debug!("visit_lifetime_def: st={:?}", self.st); SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); } @@ -350,14 +355,18 @@ mod svh_visitor { // that a change to a crate body will require downstream // crates to be recompiled. fn visit_expr(&mut self, ex: &'a Expr) { + debug!("visit_expr: st={:?}", self.st); SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) } fn visit_stmt(&mut self, s: &'a Stmt) { + debug!("visit_stmt: st={:?}", self.st); SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s) } fn visit_foreign_item(&mut self, i: &'a ForeignItem) { + debug!("visit_foreign_item: st={:?}", self.st); + // FIXME (#14132) ideally we would incorporate privacy (or // perhaps reachability) somewhere here, so foreign items // that do not leak into downstream crates would not be @@ -367,6 +376,7 @@ mod svh_visitor { fn visit_item(&mut self, i: &'a Item) { debug!("visit_item: {:?} st={:?}", i, self.st); + // FIXME (#14132) ideally would incorporate reachability // analysis somewhere here, so items that never leak into // downstream crates (e.g. via monomorphisation or @@ -375,55 +385,68 @@ mod svh_visitor { } fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) { + debug!("visit_mod: st={:?}", self.st); SawMod.hash(self.st); visit::walk_mod(self, m) } fn visit_decl(&mut self, d: &'a Decl) { + debug!("visit_decl: st={:?}", self.st); SawDecl.hash(self.st); visit::walk_decl(self, d) } fn visit_ty(&mut self, t: &'a Ty) { + debug!("visit_ty: st={:?}", self.st); SawTy.hash(self.st); visit::walk_ty(self, t) } fn visit_generics(&mut self, g: &'a Generics) { + debug!("visit_generics: st={:?}", self.st); SawGenerics.hash(self.st); visit::walk_generics(self, g) } fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, b: &'a Block, s: Span, _: NodeId) { + debug!("visit_fn: st={:?}", self.st); SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s) } fn visit_trait_item(&mut self, ti: &'a TraitItem) { + debug!("visit_trait_item: st={:?}", self.st); SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &'a ImplItem) { + debug!("visit_impl_item: st={:?}", self.st); SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) } fn visit_struct_field(&mut self, s: &'a StructField) { + debug!("visit_struct_field: st={:?}", self.st); SawStructField.hash(self.st); visit::walk_struct_field(self, s) } fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) { + debug!("visit_path: st={:?}", self.st); SawPath.hash(self.st); visit::walk_path(self, path) } fn visit_block(&mut self, b: &'a Block) { + debug!("visit_block: st={:?}", self.st); SawBlock.hash(self.st); visit::walk_block(self, b) } fn visit_pat(&mut self, p: &'a Pat) { + debug!("visit_pat: st={:?}", self.st); SawPat.hash(self.st); visit::walk_pat(self, p) } fn visit_local(&mut self, l: &'a Local) { + debug!("visit_local: st={:?}", self.st); SawLocal.hash(self.st); visit::walk_local(self, l) } fn visit_arm(&mut self, a: &'a Arm) { + debug!("visit_arm: st={:?}", self.st); SawArm.hash(self.st); visit::walk_arm(self, a) } } From 3563e400cc834bece5064e57ad698163865687d7 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 28 Jul 2016 19:02:25 -0700 Subject: [PATCH 150/150] Try to clear up some awkward wording --- src/doc/book/closures.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index 666d0946ecc80..24fcf886ef03d 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -291,9 +291,9 @@ isn’t interesting. The next part is: # some_closure(1) } ``` -Because `Fn` is a trait, we can bound our generic with it. In this case, our -closure takes a `i32` as an argument and returns an `i32`, and so the generic -bound we use is `Fn(i32) -> i32`. +Because `Fn` is a trait, we can use it as a bound for our generic type. In +this case, our closure takes a `i32` as an argument and returns an `i32`, and +so the generic bound we use is `Fn(i32) -> i32`. There’s one other key point here: because we’re bounding a generic with a trait, this will get monomorphized, and therefore, we’ll be doing static