From 59435072f58e1d622e1664f0a7e44830891c958f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 2 May 2016 18:51:24 -0500 Subject: [PATCH 001/331] 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 3f75201aad2c..a13a94e12e5d 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 000000000000..cd00ebc2d0a6 --- /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 000000000000..e06c0a5ec2a4 --- /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/331] 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 a13a94e12e5d..d7c68d9f2a98 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 8478d48dad949b3b1374569a5391089a49094eeb Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 9 May 2016 19:45:12 -0400 Subject: [PATCH 003/331] Add some warnings to std::env::current_exe /cc #21889 --- src/libstd/env.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 9dc6a26cdeed..369594e2b8f6 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -493,6 +493,21 @@ pub fn temp_dir() -> PathBuf { /// that can fail for a good number of reasons. Some errors can include, but not /// be limited to, filesystem operations failing or general syscall failures. /// +/// # Security +/// +/// This function should be used with care, as its incorrect usage can cause +/// security problems. Specifically, as with many operations invovling files and +/// paths, you can introduce a race condition. It goes like this: +/// +/// 1. You get the path to the current executable using `current_exe()`, and +/// store it in a variable binding. +/// 2. Time passes. A malicious actor removes the current executable, and +/// replaces it with a malicious one. +/// 3. You then use the binding to try to open that file. +/// +/// You expected to be opening the current executable, but you're now opening +/// something completely different. +/// /// # Examples /// /// ``` From e7d423a3bf599b8e235d25511e807e6bf981c020 Mon Sep 17 00:00:00 2001 From: Aaron Gallagher Date: Mon, 30 May 2016 19:10:16 -0700 Subject: [PATCH 004/331] Retry on EINTR in Bytes and Chars. Since Bytes and Chars called directly into Read::read, they didn't use any of the retrying wrappers. This allows both iterator types to retry. --- src/libstd/io/mod.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index a058337a50af..d5b255ee5737 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1522,6 +1522,18 @@ impl BufRead for Take { } } +fn read_one_byte(reader: &mut Read) -> Option> { + let mut buf = [0]; + loop { + return match reader.read(&mut buf) { + Ok(0) => None, + Ok(..) => Some(Ok(buf[0])), + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => Some(Err(e)), + }; + } +} + /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes()`][bytes] on a reader. @@ -1538,12 +1550,7 @@ impl Iterator for Bytes { type Item = Result; fn next(&mut self) -> Option> { - let mut buf = [0]; - match self.inner.read(&mut buf) { - Ok(0) => None, - Ok(..) => Some(Ok(buf[0])), - Err(e) => Some(Err(e)), - } + read_one_byte(&mut self.inner) } } @@ -1579,11 +1586,10 @@ impl Iterator for Chars { type Item = result::Result; fn next(&mut self) -> Option> { - let mut buf = [0]; - let first_byte = match self.inner.read(&mut buf) { - Ok(0) => return None, - Ok(..) => buf[0], - Err(e) => return Some(Err(CharsError::Other(e))), + let first_byte = match read_one_byte(&mut self.inner) { + None => return None, + Some(Ok(b)) => b, + Some(Err(e)) => return Some(Err(CharsError::Other(e))), }; let width = core_str::utf8_char_width(first_byte); if width == 1 { return Some(Ok(first_byte as char)) } @@ -1595,6 +1601,7 @@ impl Iterator for Chars { match self.inner.read(&mut buf[start..width]) { Ok(0) => return Some(Err(CharsError::NotUtf8)), Ok(n) => start += n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Some(Err(CharsError::Other(e))), } } From dbe6a09a8b8ab8c2c2b422df1e10db8306b1a481 Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 24 Jun 2016 15:27:22 -0700 Subject: [PATCH 005/331] 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 fb8ea0f5661d..d564b19e1001 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 006/331] 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 d564b19e1001..fa6014a3d6ce 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 007/331] 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 edb965c1962e..1b52ea33d375 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 008/331] Fix up some things which scott mentioned --- src/libcore/intrinsics.rs | 85 ++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1b52ea33d375..c7ea5e9da640 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") }; + /// // 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; + /// + /// + /// // 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; + /// + /// + /// // 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 + /// 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 + /// // Or, just use a byte string, if you have control over the string + /// // literal /// 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]) { @@ -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 009/331] 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 c7ea5e9da640..3cc113f5e0a7 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 010/331] 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 3cc113f5e0a7..d2bf9d94399e 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 011/331] 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 d2bf9d94399e..5bd35ae1ac25 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 012/331] 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 5bd35ae1ac25..ce87bd3ba326 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 013/331] Fix tests --- src/libcore/intrinsics.rs | 246 ++++++++++++++++++++++---------------- 1 file changed, 142 insertions(+), 104 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ce87bd3ba326..fd23598a8471 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 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 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 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 `&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); + /// ``` /// - /// // 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); - /// } - /// - /// - /// // 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 = 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) + /// 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); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// let len = slice.len(); + /// assert!(index < 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]) + /// } + /// } + /// // 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: /// ``` - /// // getting the bitpattern of a floating point type - /// { - /// let x = mem::transmute::(0.0/0.0) + /// let bitpattern = std::mem::transmute::(1.0); + /// assert_eq!(bitpattern, 0x3F800000); + /// ``` + /// + /// 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; + /// + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// mem::transmute::, R<'static>>(ptr); /// } /// - /// - /// // 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()); - /// } - /// - /// - /// // 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 014/331] 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 6f77d79ab0bf..356bb96741e4 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 4ac134c2b59c..a36f7e42c9c4 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 27cafeacc203..1cc52c930344 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 015/331] 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 fd23598a8471..1ccdbb3411c8 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 016/331] 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 1ccdbb3411c8..fd2d9cdb0d4b 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 017/331] 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 fd2d9cdb0d4b..875fa08f7898 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 018/331] 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 875fa08f7898..953173f8aace 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 b8141049da7507bdbf2b037847945e5bb299ccad Mon Sep 17 00:00:00 2001 From: Matt Horn Date: Wed, 6 Jul 2016 16:59:32 -0600 Subject: [PATCH 019/331] Add IpAddr common methods --- src/libstd/net/ip.rs | 103 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 57d75441bff3..b9a57579b5cb 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -59,6 +59,48 @@ pub enum Ipv6MulticastScope { Global } +impl IpAddr { + /// Returns true for the special 'unspecified' address (0.0.0.0 in IPv4, :: in IPv6). + pub fn is_unspecified(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_unspecified(), + IpAddr::V6(ref a) => a.is_unspecified(), + } + } + + /// Returns true if this is a loopback address (127.0.0.0/8 in IPv4, ::1 in IPv6). + pub fn is_loopback(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_loopback(), + IpAddr::V6(ref a) => a.is_loopback(), + } + } + + /// Returns true if the address appears to be globally routable. + pub fn is_global(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_global(), + IpAddr::V6(ref a) => a.is_global(), + } + } + + /// Returns true if this is a multicast address (224.0.0.0/4 in IPv4, ff00::/8 in IPv6) + pub fn is_multicast(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_multicast(), + IpAddr::V6(ref a) => a.is_multicast(), + } + } + + /// Returns true if this address is in a range designated for documentation. + pub fn is_documentation(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_documentation(), + IpAddr::V6(ref a) => a.is_documentation(), + } + } +} + impl Ipv4Addr { /// Creates a new IPv4 address from four eight-bit octets. /// @@ -756,6 +798,67 @@ mod tests { None); } + #[test] + fn ip_properties() { + fn check4(octets: &[u8; 4], unspec: bool, loopback: bool, + global: bool, multicast: bool, documentation: bool) { + let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])); + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_documentation(), documentation); + } + + fn check6(str_addr: &str, unspec: bool, loopback: bool, + global: bool, u_doc: bool, mcast: bool) { + let ip = IpAddr::V6(str_addr.parse().unwrap()); + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_documentation(), u_doc); + assert_eq!(ip.is_multicast(), mcast); + } + + // address unspec loopbk global multicast doc + check4(&[0, 0, 0, 0], true, false, false, false, false); + check4(&[0, 0, 0, 1], false, false, true, false, false); + check4(&[0, 1, 0, 0], false, false, true, false, false); + check4(&[10, 9, 8, 7], false, false, false, false, false); + check4(&[127, 1, 2, 3], false, true, false, false, false); + check4(&[172, 31, 254, 253], false, false, false, false, false); + check4(&[169, 254, 253, 242], false, false, false, false, false); + check4(&[192, 0, 2, 183], false, false, false, false, true); + check4(&[192, 1, 2, 183], false, false, true, false, false); + check4(&[192, 168, 254, 253], false, false, false, false, false); + check4(&[198, 51, 100, 0], false, false, false, false, true); + check4(&[203, 0, 113, 0], false, false, false, false, true); + check4(&[203, 2, 113, 0], false, false, true, false, false); + check4(&[224, 0, 0, 0], false, false, true, true, false); + check4(&[239, 255, 255, 255], false, false, true, true, false); + check4(&[255, 255, 255, 255], false, false, false, false, false); + + // address unspec loopbk global doc mcast + check6("::", true, false, false, false, false); + check6("::1", false, true, false, false, false); + check6("::0.0.0.2", false, false, true, false, false); + check6("1::", false, false, true, false, false); + check6("fc00::", false, false, false, false, false); + check6("fdff:ffff::", false, false, false, false, false); + check6("fe80:ffff::", false, false, false, false, false); + check6("febf:ffff::", false, false, false, false, false); + check6("fec0::", false, false, false, false, false); + check6("ff01::", false, false, false, false, true); + check6("ff02::", false, false, false, false, true); + check6("ff03::", false, false, false, false, true); + check6("ff04::", false, false, false, false, true); + check6("ff05::", false, false, false, false, true); + check6("ff08::", false, false, false, false, true); + check6("ff0e::", false, false, true, false, true); + check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false); + check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false); + } + #[test] fn ipv4_properties() { fn check(octets: &[u8; 4], unspec: bool, loopback: bool, From 211c655c97d35a511e27b30480e196ea04e4e13f Mon Sep 17 00:00:00 2001 From: Matt Horn Date: Wed, 6 Jul 2016 20:47:47 -0600 Subject: [PATCH 020/331] Mark new methods as unstable --- src/libstd/net/ip.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index b9a57579b5cb..6bbba7ffb20a 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -61,6 +61,7 @@ pub enum Ipv6MulticastScope { impl IpAddr { /// Returns true for the special 'unspecified' address (0.0.0.0 in IPv4, :: in IPv6). + #[unstable(feature="ipaddr_common", reason="recently added and depends on unstable Ipv4Addr.is_unspecified()", issue="27709")] pub fn is_unspecified(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_unspecified(), @@ -69,6 +70,7 @@ impl IpAddr { } /// Returns true if this is a loopback address (127.0.0.0/8 in IPv4, ::1 in IPv6). + #[unstable(feature="ipaddr_common", reason="recently added", issue="27709")] pub fn is_loopback(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_loopback(), @@ -77,6 +79,7 @@ impl IpAddr { } /// Returns true if the address appears to be globally routable. + #[unstable(feature="ipaddr_common", reason="recently added and depends on unstable Ipv4Addr.is_global() and Ipv6Addr.is_global()", issue="27709")] pub fn is_global(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_global(), @@ -85,6 +88,7 @@ impl IpAddr { } /// Returns true if this is a multicast address (224.0.0.0/4 in IPv4, ff00::/8 in IPv6) + #[unstable(feature="ipaddr_common", reason="recently added", issue="27709")] pub fn is_multicast(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_multicast(), @@ -93,6 +97,7 @@ impl IpAddr { } /// Returns true if this address is in a range designated for documentation. + #[unstable(feature="ipaddr_common", reason="recently added and depends on unstable Ipv6Addr.is_documentation()", issue="27709")] pub fn is_documentation(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_documentation(), From fee5b492fecd321b5ce507d732948943a74fbf4c Mon Sep 17 00:00:00 2001 From: Matt Horn Date: Wed, 6 Jul 2016 22:10:12 -0600 Subject: [PATCH 021/331] Properly mark new methods as unstable --- src/libstd/net/ip.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 6bbba7ffb20a..2bf063099e40 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -61,7 +61,8 @@ pub enum Ipv6MulticastScope { impl IpAddr { /// Returns true for the special 'unspecified' address (0.0.0.0 in IPv4, :: in IPv6). - #[unstable(feature="ipaddr_common", reason="recently added and depends on unstable Ipv4Addr.is_unspecified()", issue="27709")] + #[unstable(feature="ip", issue="27709", + reason="recently added and depends on unstable Ipv4Addr.is_unspecified()")] pub fn is_unspecified(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_unspecified(), @@ -70,7 +71,7 @@ impl IpAddr { } /// Returns true if this is a loopback address (127.0.0.0/8 in IPv4, ::1 in IPv6). - #[unstable(feature="ipaddr_common", reason="recently added", issue="27709")] + #[unstable(feature="ip", reason="recently added", issue="27709")] pub fn is_loopback(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_loopback(), @@ -79,7 +80,8 @@ impl IpAddr { } /// Returns true if the address appears to be globally routable. - #[unstable(feature="ipaddr_common", reason="recently added and depends on unstable Ipv4Addr.is_global() and Ipv6Addr.is_global()", issue="27709")] + #[unstable(feature="ip", issue="27709", + reason="recently added and depends on unstable Ip{v4,v6}Addr.is_global()")] pub fn is_global(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_global(), @@ -88,7 +90,7 @@ impl IpAddr { } /// Returns true if this is a multicast address (224.0.0.0/4 in IPv4, ff00::/8 in IPv6) - #[unstable(feature="ipaddr_common", reason="recently added", issue="27709")] + #[unstable(feature="ip", reason="recently added", issue="27709")] pub fn is_multicast(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_multicast(), @@ -97,7 +99,8 @@ impl IpAddr { } /// Returns true if this address is in a range designated for documentation. - #[unstable(feature="ipaddr_common", reason="recently added and depends on unstable Ipv6Addr.is_documentation()", issue="27709")] + #[unstable(feature="ip", issue="27709", + reason="recently added and depends on unstable Ipv6Addr.is_documentation()")] pub fn is_documentation(&self) -> bool { match *self { IpAddr::V4(ref a) => a.is_documentation(), From 58da5dd51eebe700a2ac8cf4f0b10dec6d1b6ca9 Mon Sep 17 00:00:00 2001 From: Matt Horn Date: Thu, 7 Jul 2016 11:15:25 -0600 Subject: [PATCH 022/331] Add links to Ipv*Addr methods in docs per https://github.com/rust-lang/rust/pull/34694#issuecomment-231126489 --- src/libstd/net/ip.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 2bf063099e40..fddb237dd5f5 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -60,7 +60,9 @@ pub enum Ipv6MulticastScope { } impl IpAddr { - /// Returns true for the special 'unspecified' address (0.0.0.0 in IPv4, :: in IPv6). + /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified #[unstable(feature="ip", issue="27709", reason="recently added and depends on unstable Ipv4Addr.is_unspecified()")] pub fn is_unspecified(&self) -> bool { @@ -70,7 +72,9 @@ impl IpAddr { } } - /// Returns true if this is a loopback address (127.0.0.0/8 in IPv4, ::1 in IPv6). + /// Returns true if this is a loopback address ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback #[unstable(feature="ip", reason="recently added", issue="27709")] pub fn is_loopback(&self) -> bool { match *self { @@ -79,7 +83,9 @@ impl IpAddr { } } - /// Returns true if the address appears to be globally routable. + /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global #[unstable(feature="ip", issue="27709", reason="recently added and depends on unstable Ip{v4,v6}Addr.is_global()")] pub fn is_global(&self) -> bool { @@ -89,7 +95,9 @@ impl IpAddr { } } - /// Returns true if this is a multicast address (224.0.0.0/4 in IPv4, ff00::/8 in IPv6) + /// Returns true if this is a multicast address ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast #[unstable(feature="ip", reason="recently added", issue="27709")] pub fn is_multicast(&self) -> bool { match *self { @@ -98,7 +106,9 @@ impl IpAddr { } } - /// Returns true if this address is in a range designated for documentation. + /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation #[unstable(feature="ip", issue="27709", reason="recently added and depends on unstable Ipv6Addr.is_documentation()")] pub fn is_documentation(&self) -> bool { From 8aeb9303e954502f67f4af7c5c7e79f6d4f706eb Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 8 Jul 2016 22:12:36 +1000 Subject: [PATCH 023/331] 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 34bc210b3c82..30ce9c3f382b 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 024/331] 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 30ce9c3f382b..51a820b2e91c 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 025/331] 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 51a820b2e91c..2d2bded9f606 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 026/331] 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 9b5c2128f1ea..43360b91fdaa 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 027/331] 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 953173f8aace..ab7545d37dc9 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 028/331] 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 ab7545d37dc9..d6fb1816b5fa 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 029/331] Add method `String::insert_str` --- src/libcollections/string.rs | 64 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index eedf4c2c11f3..ce3f96893242 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(); - self.vec.reserve(amt); 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, 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 { + self.insert_bytes(idx, string.as_bytes()); } } From b91acc9f2a9e80dfa04af62d20bf69d302a1a5e2 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 14 Jul 2016 05:29:50 +0900 Subject: [PATCH 030/331] Remove extra newlines in MIR dump --- src/librustc_mir/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 515620d42538..c9ca1a963a42 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -195,7 +195,7 @@ fn write_basic_block(tcx: TyCtxt, ALIGN, comment(tcx, data.terminator().source_info))?; - writeln!(w, "{}}}\n", INDENT) + writeln!(w, "{}}}", INDENT) } fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { From e2f5961f35a012f64bbb054d9eadeed608b82983 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 16 Jul 2016 11:20:17 -0400 Subject: [PATCH 031/331] Partial rewrite/expansion of `Vec::truncate` documentation. --- src/libcollections/vec.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index da56b21cf0c0..966144233894 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -479,18 +479,45 @@ impl Vec { } } - /// Shorten a vector to be `len` elements long, dropping excess elements. + /// Shortens the vector, keeping the first `len` elements and dropping + /// the rest. /// /// If `len` is greater than the vector's current length, this has no /// effect. /// + /// The [`drain`] method can emulate `truncate`, but causes the excess + /// elements to be returned instead of dropped. + /// /// # Examples /// + /// Truncating a five element vector to two elements: + /// /// ``` /// let mut vec = vec![1, 2, 3, 4, 5]; /// vec.truncate(2); /// assert_eq!(vec, [1, 2]); /// ``` + /// + /// No truncation occurs when `len` is greater than the vector's current + /// length: + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.truncate(8); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// Truncating when `len == 0` is equivalent to calling the [`clear`] + /// method. + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.truncate(0); + /// assert_eq!(vec, []); + /// ``` + /// + /// [`clear`]: #method.clear + /// [`drain`]: #method.drain #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, len: usize) { unsafe { From 42326ec2a48a6a70d737b27cb7930810360a1df6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 16 Jul 2016 18:00:05 +0200 Subject: [PATCH 032/331] 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 84a0bbbd2498..9e4428ec57d5 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 033/331] 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 dbede94f0bf1..3d5c3125fae2 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 034/331] 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 e681d1bee061..e4cb861d3b0f 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 b2f5b5a812b0b9a8d4e5e0dec16ba44ef16d3e55 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 16 Jul 2016 21:42:11 -0400 Subject: [PATCH 035/331] Indicate where `std::slice` structs originate from. --- src/libcore/slice.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 4f11cac4eb2b..d8a11581c3b6 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -902,6 +902,8 @@ macro_rules! make_mut_slice { /// Immutable slice iterator /// +/// This struct is created by the [`iter`] method on [slices]. +/// /// # Examples /// /// Basic usage: @@ -915,6 +917,9 @@ macro_rules! make_mut_slice { /// println!("{}", element); /// } /// ``` +/// +/// [`iter`]: ../../std/primitive.slice.html#method.iter +/// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ptr: *const T, @@ -993,6 +998,8 @@ impl<'a, T> Clone for Iter<'a, T> { /// Mutable slice iterator. /// +/// This struct is created by the [`iter_mut`] method on [slices]. +/// /// # Examples /// /// Basic usage: @@ -1010,6 +1017,9 @@ impl<'a, T> Clone for Iter<'a, T> { /// // We now have "[2, 3, 4]": /// println!("{:?}", slice); /// ``` +/// +/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut +/// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ptr: *mut T, From 4e5e36fb79e1cffc6f7c3a9670df222060bb0e4b Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Sun, 17 Jul 2016 20:57:54 +0200 Subject: [PATCH 036/331] test: disable more stdcall tests for ARM arches. temp workaround for #24958 --- src/test/debuginfo/type-names.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index a74369ed3c3a..2419625cbd37 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -11,6 +11,8 @@ // ignore-tidy-linelength // ignore-lldb // ignore-android: FIXME(#24958) +// ignore-arm: FIXME(#24958) +// ignore-aarch64: FIXME(#24958) // compile-flags:-g From 8aaf0f894bfbbc8e1135e42ce7cb9258d55f41cc Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Sun, 17 Jul 2016 21:00:24 +0200 Subject: [PATCH 037/331] doc/book: fix tests for non-x86 architectures, such as aarch64 `rustdoc --test` gets confused when "main" exists for some architectures but not others. --- src/doc/book/inline-assembly.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/book/inline-assembly.md b/src/doc/book/inline-assembly.md index a8340d9d31e7..62e196a7ccdf 100644 --- a/src/doc/book/inline-assembly.md +++ b/src/doc/book/inline-assembly.md @@ -60,6 +60,8 @@ asm!("xor %eax, %eax" : "eax" ); # } } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` Whitespace also doesn't matter: @@ -70,6 +72,8 @@ Whitespace also doesn't matter: # fn main() { unsafe { asm!("xor %eax, %eax" ::: "eax"); # } } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` ## Operands @@ -129,6 +133,8 @@ stay valid. // Put the value 0x200 in eax asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); # } } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` Input and output registers need not be listed since that information @@ -164,6 +170,8 @@ unsafe { } println!("eax is currently {}", result); # } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` ## More Information From 6a09df9079279297c5f68c0a1214a17e8193cd6a Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Sun, 17 Jul 2016 11:31:44 -0400 Subject: [PATCH 038/331] 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 eedf4c2c11f3..688f05760425 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 f6be6aa92acd34d3a8815e29bb09b7ec2a72fedc Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sun, 17 Jul 2016 10:52:59 -0400 Subject: [PATCH 039/331] Document from_raw_parts involves ownership transfer --- src/libcollections/string.rs | 6 ++++++ src/libcollections/vec.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index eedf4c2c11f3..8ba5c6ffbf2e 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -701,6 +701,12 @@ impl String { /// Violating these may cause problems like corrupting the allocator's /// internal datastructures. /// + /// The ownership of `ptr` is effectively transferred to the + /// `String` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// /// # Examples /// /// Basic usage: diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index da56b21cf0c0..98b5c4663cd0 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -348,6 +348,12 @@ impl Vec { /// Violating these may cause problems like corrupting the allocator's /// internal datastructures. /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// /// # Examples /// /// ``` From 661187a95eb9b00a4a120de7d22ee28706574656 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sun, 17 Jul 2016 10:55:00 -0400 Subject: [PATCH 040/331] Remove extraneous words --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 98b5c4663cd0..3c221f0fea0d 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -342,7 +342,7 @@ impl Vec { /// /// * `ptr` needs to have been previously allocated via `String`/`Vec` /// (at least, it's highly likely to be incorrect if it wasn't). - /// * `length` needs to be the length that less than or equal to `capacity`. + /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated with. /// /// Violating these may cause problems like corrupting the allocator's From ce442b4f5195ff6af27ae3335c7bb372015c1407 Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 20 Jul 2016 15:02:33 +0200 Subject: [PATCH 041/331] 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 60d7e01d9881..a03249e00635 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 042/331] 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 83439b3f1321..c28f70b8692a 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 043/331] 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 ab3b20e08c80..9a94cc16bfe8 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 044/331] 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 688f05760425..3920b57962c8 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 045/331] 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 3920b57962c8..71c6a6c892ea 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 9292c0bc91a9165a2dc7baa4d154079ad0a5f5c9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Jul 2016 00:15:15 +0300 Subject: [PATCH 046/331] Properly feature gate all unstable ABIs --- src/doc/book/closures.md | 1 + src/libsyntax/feature_gate.rs | 73 +++++++++++-------- src/test/compile-fail/E0045.rs | 2 +- .../feature-gate-abi-vectorcall.rs | 19 ----- src/test/compile-fail/feature-gate-abi.rs | 60 +++++++++++++++ .../compile-fail/feature-gate-rust-call.rs | 21 ------ 6 files changed, 103 insertions(+), 73 deletions(-) delete mode 100644 src/test/compile-fail/feature-gate-abi-vectorcall.rs create mode 100644 src/test/compile-fail/feature-gate-abi.rs delete mode 100644 src/test/compile-fail/feature-gate-rust-call.rs diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index 666d0946ecc8..defa63b91692 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -223,6 +223,7 @@ trait system to overload operators. Calling functions is no different. We have three separate traits to overload with: ```rust +# #![feature(unboxed_closures)] # mod foo { pub trait Fn : FnMut { extern "rust-call" fn call(&self, args: Args) -> Self::Output; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 27485ee65fcc..2b79a7012e31 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -800,6 +800,29 @@ macro_rules! gate_feature_post { }} } +impl<'a> PostExpansionVisitor<'a> { + fn check_abi(&self, abi: Abi, span: Span) { + match abi { + Abi::RustIntrinsic => + gate_feature_post!(&self, intrinsics, span, + "intrinsics are subject to change"), + Abi::PlatformIntrinsic => { + gate_feature_post!(&self, platform_intrinsics, span, + "platform intrinsics are experimental and possibly buggy") + }, + Abi::Vectorcall => { + gate_feature_post!(&self, abi_vectorcall, span, + "vectorcall is experimental and subject to change") + } + Abi::RustCall => { + gate_feature_post!(&self, unboxed_closures, span, + "rust-call ABI is subject to change"); + } + _ => {} + } + } +} + impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { @@ -831,21 +854,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { across platforms, it is recommended to \ use `#[link(name = \"foo\")]` instead") } - match foreign_module.abi { - Abi::RustIntrinsic => - gate_feature_post!(&self, intrinsics, i.span, - "intrinsics are subject to change"), - Abi::PlatformIntrinsic => { - gate_feature_post!(&self, platform_intrinsics, i.span, - "platform intrinsics are experimental \ - and possibly buggy") - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, i.span, - "vectorcall is experimental and subject to change") - } - _ => () - } + self.check_abi(foreign_module.abi, i.span); } ast::ItemKind::Fn(..) => { @@ -928,6 +937,16 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_foreign_item(self, i) } + fn visit_ty(&mut self, ty: &ast::Ty) { + match ty.node { + ast::TyKind::BareFn(ref bare_fn_ty) => { + self.check_abi(bare_fn_ty.abi, ty.span); + } + _ => {} + } + visit::walk_ty(self, ty) + } + fn visit_expr(&mut self, e: &ast::Expr) { match e.node { ast::ExprKind::Box(_) => { @@ -1015,23 +1034,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } match fn_kind { - FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => { - gate_feature_post!(&self, intrinsics, - span, - "intrinsics are subject to change") - } FnKind::ItemFn(_, _, _, _, abi, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi { - Abi::RustCall => { - gate_feature_post!(&self, unboxed_closures, span, - "rust-call ABI is subject to change"); - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change"); - }, - _ => {} - }, + FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => { + self.check_abi(abi, span); + } _ => {} } visit::walk_fn(self, fn_kind, fn_decl, block, span); @@ -1044,7 +1050,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { ti.span, "associated constants are experimental") } - ast::TraitItemKind::Method(ref sig, _) => { + ast::TraitItemKind::Method(ref sig, ref block) => { + if block.is_none() { + self.check_abi(sig.abi, ti.span); + } if sig.constness == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } diff --git a/src/test/compile-fail/E0045.rs b/src/test/compile-fail/E0045.rs index edec911d3c07..2a731596b4be 100644 --- a/src/test/compile-fail/E0045.rs +++ b/src/test/compile-fail/E0045.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern "rust-call" { fn foo(x: u8, ...); } //~ ERROR E0045 +extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045 fn main() { } diff --git a/src/test/compile-fail/feature-gate-abi-vectorcall.rs b/src/test/compile-fail/feature-gate-abi-vectorcall.rs deleted file mode 100644 index 79f3c8dc7762..000000000000 --- a/src/test/compile-fail/feature-gate-abi-vectorcall.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern "vectorcall" { //~ ERROR vectorcall is experimental and subject to change - fn bar(); -} - -extern "vectorcall" fn baz() { //~ ERROR vectorcall is experimental and subject to change -} - -fn main() { -} diff --git a/src/test/compile-fail/feature-gate-abi.rs b/src/test/compile-fail/feature-gate-abi.rs new file mode 100644 index 000000000000..0c01f955c063 --- /dev/null +++ b/src/test/compile-fail/feature-gate-abi.rs @@ -0,0 +1,60 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Functions +extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change +extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental +extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change +extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change + +// Methods in trait definition +trait Tr { + extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change + + extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change +} + +struct S; + +// Methods in trait impl +impl Tr for S { + extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change +} + +// Methods in inherent impl +impl S { + extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change +} + +// Function pointer types +type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change +type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental +type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change +type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change + +// Foreign modules +extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change +extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental +extern "vectorcall" {} //~ ERROR vectorcall is experimental and subject to change +extern "rust-call" {} //~ ERROR rust-call ABI is subject to change + +fn main() {} diff --git a/src/test/compile-fail/feature-gate-rust-call.rs b/src/test/compile-fail/feature-gate-rust-call.rs deleted file mode 100644 index 029a9cad65fc..000000000000 --- a/src/test/compile-fail/feature-gate-rust-call.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change - -trait Foo { - extern "rust-call" fn foo(); -} - -impl Foo for i32 { - extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change -} - -fn main() { } From f77bcc86b1624644c4e897b9fb1f094d8ea81f15 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 18 Jul 2016 16:25:11 -0700 Subject: [PATCH 047/331] 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 794e4d4996c9..ceb17e53a555 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 048/331] 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 8cd09fa9043c..5d822f1b1aba 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 d4696976574e..34ca4de6563e 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 efad43d25627..6da7905a7003 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 9c98c0a6b4c9..a98a51b06b5d 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 373e2e3b65d1..bfb7fa281f24 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 2b28550320d8..14b9ebfdba66 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 7ebb492bb21f..e4b3431e8b67 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 3426b30aeeb8..50c2b8c98acd 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 bbc0c2d6f396..a9d4446d5d49 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 129af8ac6960..9e2312008a10 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 c1cd20a843ce..80918728316a 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 dda957673eba..9c5720de4b31 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 f6e6436f6157..389bb6f0cab4 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 a2049331ab2e..6884fa11e741 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 4c68d3dcf37b..8af47b671a85 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 dd6080fdb0ba..764cdc15996d 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 f0732d08c71e..82e7b23279fb 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 1b5aa12274d4..53d58b9fceaa 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 0a09a5cf72d9..7fc323b234ae 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 76b39b450254..8ac31c176188 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 4015293826e1..579a9a809e20 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 1bd43168b4f6..c700601eac7a 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 044c687c9fc4..817ce22e4f59 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 dfe9de18f578..3a03b2accd54 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 a77c5fa542eb..93bb2d672653 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 f1e45d764099..7cca1f7b18b3 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 049/331] 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 c8b9fea15ba8..f9e1a4f16087 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 dae311ea3b6e37e5ad2b7b3d42cfe953c2221855 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 17 Jul 2016 17:28:00 +0200 Subject: [PATCH 050/331] Add debug for btree_map::{Entry, VacantEntry, OccupiedEntry} --- src/libcollections/btree/map.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index aea7a1c13a28..ef94aae78f41 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -326,6 +326,20 @@ pub enum Entry<'a, K: 'a, V: 'a> { OccupiedEntry<'a, K, V>), } +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, 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 vacant Entry. #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { @@ -337,6 +351,15 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { _marker: PhantomData<&'a mut (K, V)>, } +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, 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() + } +} + /// An occupied Entry. #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { @@ -348,6 +371,16 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { _marker: PhantomData<&'a mut (K, V)>, } +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, 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() + } +} + // An iterator for merging two sorted sequences into one struct MergeIter> { left: Peekable, From f7820888daeb961339643dd142ba032847181555 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 19 Jul 2016 06:22:35 -0400 Subject: [PATCH 051/331] 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 000000000000..90aafd6a3bb3 --- /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 052/331] [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 303cc671f4a2..de0457592fc8 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 053/331] 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 da56b21cf0c0..9badf8cf1830 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 { - /// v.set_len(1); + /// 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 { + /// vec.set_len(4); /// } /// ``` #[inline] From c4730daf450bafe51e76d430f94d2c59c814e53c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 19 Jul 2016 12:32:56 -0400 Subject: [PATCH 054/331] re-work example --- src/libstd/env.rs | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 369594e2b8f6..5a3899eca3f0 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -495,18 +495,41 @@ pub fn temp_dir() -> PathBuf { /// /// # Security /// -/// This function should be used with care, as its incorrect usage can cause -/// security problems. Specifically, as with many operations invovling files and -/// paths, you can introduce a race condition. It goes like this: +/// The output of this function should not be used in anything that might have +/// security implications. For example: /// -/// 1. You get the path to the current executable using `current_exe()`, and -/// store it in a variable binding. -/// 2. Time passes. A malicious actor removes the current executable, and -/// replaces it with a malicious one. -/// 3. You then use the binding to try to open that file. +/// ``` +/// fn main() { +/// println!("{:?}", std::env::current_exe()); +/// } +/// ``` /// -/// You expected to be opening the current executable, but you're now opening -/// something completely different. +/// On Linux systems, if this is compiled as `foo`: +/// +/// ```bash +/// $ rustc foo.rs +/// $ ./foo +/// Ok("/home/alex/foo") +/// ``` +/// +/// And you make a symbolic link of the program: +/// +/// ```bash +/// $ ln foo bar +/// ``` +/// +/// When you run it, you won't get the original executable, you'll get the +/// symlink: +/// +/// ```bash +/// $ ./bar +/// Ok("/home/alex/bar") +/// ``` +/// +/// This sort of behavior has been known to [lead to privledge escalation] when +/// used incorrectly, for example. +/// +/// [lead to privledge escalation]: http://securityvulns.com/Wdocument183.html /// /// # Examples /// From 9652fcbb6e59845904ef246b41231f5df198dd0d Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 19 Jul 2016 23:02:06 +0530 Subject: [PATCH 055/331] Run rustfmt on libsyntax_ext/deriving folder --- src/libsyntax_ext/deriving/bounds.rs | 8 +- src/libsyntax_ext/deriving/clone.rs | 98 +-- src/libsyntax_ext/deriving/cmp/eq.rs | 67 +- src/libsyntax_ext/deriving/cmp/ord.rs | 144 ++-- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 61 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 235 +++--- src/libsyntax_ext/deriving/debug.rs | 89 +-- src/libsyntax_ext/deriving/decodable.rs | 175 +++-- src/libsyntax_ext/deriving/default.rs | 48 +- src/libsyntax_ext/deriving/encodable.rs | 92 ++- src/libsyntax_ext/deriving/generic/mod.rs | 723 +++++++++--------- src/libsyntax_ext/deriving/hash.rs | 55 +- src/libsyntax_ext/deriving/mod.rs | 42 +- 13 files changed, 921 insertions(+), 916 deletions(-) diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index 36818e000b55..cfc98bf36871 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -12,15 +12,14 @@ use deriving::generic::*; use deriving::generic::ty::*; use syntax::ast::MetaItem; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax_pos::Span; pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, span: Span, _: &MetaItem, _: &Annotatable, - _: &mut FnMut(Annotatable)) -{ + _: &mut FnMut(Annotatable)) { cx.span_err(span, "this unsafe trait should be implemented explicitly"); } @@ -28,8 +27,7 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new()); v.push("marker"); v.push("Copy"); diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 1e47ebb85837..ce8ce2209d8c 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -11,23 +11,25 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{Expr, ItemKind, Generics, MetaItem, VariantData}; +use syntax::ast::{Expr, Generics, ItemKind, MetaItem, VariantData}; use syntax::attr; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax_pos::Span; #[derive(PartialEq)] -enum Mode { Deep, Shallow } +enum Mode { + Deep, + Shallow, +} pub fn expand_deriving_clone(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { // check if we can use a short form // // the short form is `fn clone(&self) -> Self { *self }` @@ -46,8 +48,8 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, match annitem.node { ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) - if ty_params.is_empty() - && attr::contains_name(&annitem.attrs, "derive_Copy") => { + if ty_params.is_empty() && + attr::contains_name(&annitem.attrs, "derive_Copy") => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; unify_fieldless_variants = true; @@ -66,11 +68,11 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, } } - _ => cx.span_bug(span, "#[derive(Clone)] on trait item or impl item") + _ => cx.span_bug(span, "#[derive(Clone)] on trait item or impl item"), } let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -78,42 +80,41 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "clone", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: unify_fieldless_variants, - combine_substructure: substructure, - } - ), + methods: vec![MethodDef { + name: "clone", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: Vec::new(), + ret_ty: Self_, + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: unify_fieldless_variants, + combine_substructure: substructure, + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) } -fn cs_clone( - name: &str, - cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, - mode: Mode) -> P { +fn cs_clone(name: &str, + cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + mode: Mode) + -> P { let ctor_path; let all_fields; let fn_path = match mode { Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), - Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), + Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), }; let subcall = |field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; let span = if mode == Mode::Shallow { // set the expn ID so we can call the unstable method - Span { expn_id: cx.backtrace(), .. trait_span } + Span { expn_id: cx.backtrace(), ..trait_span } } else { field.span }; @@ -131,15 +132,15 @@ fn cs_clone( ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]); all_fields = af; vdata = &variant.node.data; - }, - EnumNonMatchingCollapsed (..) => { + } + EnumNonMatchingCollapsed(..) => { cx.span_bug(trait_span, &format!("non-matching enum variants in \ - `derive({})`", name)) + `derive({})`", + name)) } StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, - &format!("static method in `derive({})`", name)) + cx.span_bug(trait_span, &format!("static method in `derive({})`", name)) } } @@ -153,17 +154,20 @@ fn cs_clone( Mode::Deep => { match *vdata { VariantData::Struct(..) => { - let fields = all_fields.iter().map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", name)) - } - }; - cx.field_imm(field.span, ident, subcall(field)) - }).collect::>(); + let fields = all_fields.iter() + .map(|field| { + let ident = match field.name { + Some(i) => i, + None => { + cx.span_bug(trait_span, + &format!("unnamed field in normal struct in \ + `derive({})`", + name)) + } + }; + cx.field_imm(field.span, ident, subcall(field)) + }) + .collect::>(); cx.expr_struct(trait_span, ctor_path, fields) } @@ -172,9 +176,7 @@ fn cs_clone( let path = cx.expr_path(ctor_path); cx.expr_call(trait_span, path, subcalls) } - VariantData::Unit(..) => { - cx.expr_path(ctor_path) - } + VariantData::Unit(..) => cx.expr_path(ctor_path), } } } diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 9c5072eeb3e0..2ab0f0ff5466 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,30 +22,27 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method( - |cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") }), - cx, - span, - substr - ) + cs_same_method(|cx, span, exprs| { + // create `a.(); b.(); c.(); ...` + // (where method is `assert_receiver_is_total_eq`) + let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); + let block = cx.block(span, stmts); + cx.expr_block(block) + }, + Box::new(|cx, sp, _, _| { + cx.span_bug(sp, "non matching enums in derive(Eq)?") + }), + cx, + span, + substr) } let inline = cx.meta_word(span, InternedString::new("inline")); let hidden = cx.meta_word(span, InternedString::new("hidden")); - let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden)); - let attrs = vec!(cx.attribute(span, inline), - cx.attribute(span, doc)); + let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]); + let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -53,21 +50,19 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "assert_receiver_is_total_eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(), - ret_ty: nil_ty(), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })) - } - ), + methods: vec![MethodDef { + name: "assert_receiver_is_total_eq", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![], + ret_ty: nil_ty(), + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + cs_total_eq_assert(a, b, c) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index cbd7ac0eadad..8ae77e79310b 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, self}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{self, Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,10 +22,9 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -33,21 +32,19 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_cmp(a, b, c) - })), - } - ), + methods: vec![MethodDef { + name: "cmp", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![borrowed_self()], + ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + cs_cmp(a, b, c) + })), + }], associated_types: Vec::new(), }; @@ -57,76 +54,73 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, pub fn ordering_collapsed(cx: &mut ExtCtxt, span: Span, - self_arg_tags: &[ast::Ident]) -> P { + self_arg_tags: &[ast::Ident]) + -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) } -pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { +pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__cmp"); - let equals_path = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); + let equals_path = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]); - /* - Builds: + // Builds: + // + // match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { + // ::std::cmp::Ordering::Equal => + // match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { + // ::std::cmp::Ordering::Equal => { + // ... + // } + // __cmp => __cmp + // }, + // __cmp => __cmp + // } + // + cs_fold(// foldr nests the if-elses correctly, leaving the first field + // as the outermost one, and the last as the innermost. + false, + |cx, span, old, self_f, other_fs| { + // match new { + // ::std::cmp::Ordering::Equal => old, + // __cmp => __cmp + // } - match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { - ::std::cmp::Ordering::Equal => - match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { - ::std::cmp::Ordering::Equal => { - ... - } - __cmp => __cmp - }, - __cmp => __cmp - } - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // match new { - // ::std::cmp::Ordering::Equal => old, - // __cmp => __cmp - // } + let new = { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), + }; - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), - }; - - let args = vec![ + let args = vec![ cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone()), ]; - cx.expr_call_global(span, cmp_path.clone(), args) - }; + cx.expr_call_global(span, cmp_path.clone(), args) + }; - let eq_arm = cx.arm(span, - vec![cx.pat_enum(span, - equals_path.clone(), - vec![])], - old); - let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], - cx.expr_ident(span, test_id)); + let eq_arm = cx.arm(span, + vec![cx.pat_enum(span, equals_path.clone(), vec![])], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - cx.expr_path(equals_path.clone()), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`") - } else { - ordering_collapsed(cx, span, tag_tuple) - } - }), - cx, span, substr) + cx.expr_match(span, new, vec![eq_arm, neq_arm]) + }, + cx.expr_path(equals_path.clone()), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`") + } else { + ordering_collapsed(cx, span, tag_tuple) + } + }), + cx, + span, + substr) } diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index b5a8167fb555..f70e0cf4ac45 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, BinOpKind}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{BinOpKind, Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,43 +22,44 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; + cs_fold(true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; - let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); + let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::And, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, span, substr) + cx.expr_binary(span, BinOpKind::And, subexpr, eq) + }, + cx.expr_bool(span, true), + Box::new(|cx, span, _, _| cx.expr_bool(span, false)), + cx, + span, + substr) } fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; + cs_fold(true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; - let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); + let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::Or, subexpr, eq) - }, - cx.expr_bool(span, false), - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), - cx, span, substr) + cx.expr_binary(span, BinOpKind::Or, subexpr, eq) + }, + cx.expr_bool(span, false), + Box::new(|cx, span, _, _| cx.expr_bool(span, true)), + cx, + span, + substr) } macro_rules! md { diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 26c14ae934f7..10a9738742e4 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -13,8 +13,8 @@ pub use self::OrderingOp::*; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, BinOpKind, self}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{self, BinOpKind, Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -24,8 +24,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { macro_rules! md { ($name:expr, $op:expr, $equal:expr) => { { let inline = cx.meta_word(span, InternedString::new("inline")); @@ -53,7 +52,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, true)); let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let partial_cmp_def = MethodDef { name: "partial_cmp", @@ -66,7 +65,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr) - })) + })), }; // avoid defining extra methods if we can @@ -75,13 +74,11 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, let methods = if is_type_without_fields(item) { vec![partial_cmp_def] } else { - vec![ - partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true) - ] + vec![partial_cmp_def, + md!("lt", true, false), + md!("le", true, true), + md!("gt", false, false), + md!("ge", false, true)] }; let trait_def = TraitDef { @@ -99,142 +96,146 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, #[derive(Copy, Clone)] pub enum OrderingOp { - PartialCmpOp, LtOp, LeOp, GtOp, GeOp, + PartialCmpOp, + LtOp, + LeOp, + GtOp, + GeOp, } pub fn some_ordering_collapsed(cx: &mut ExtCtxt, span: Span, op: OrderingOp, - self_arg_tags: &[ast::Ident]) -> P { + self_arg_tags: &[ast::Ident]) + -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); let op_str = match op { PartialCmpOp => "partial_cmp", - LtOp => "lt", LeOp => "le", - GtOp => "gt", GeOp => "ge", + LtOp => "lt", + LeOp => "le", + GtOp => "gt", + GeOp => "ge", }; cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { +pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__cmp"); - let ordering = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); + let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let ordering_expr = cx.expr_path(ordering.clone()); let equals_expr = cx.expr_some(span, ordering_expr); let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]); - /* - Builds: + // Builds: + // + // match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { + // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => + // match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { + // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { + // ... + // } + // __cmp => __cmp + // }, + // __cmp => __cmp + // } + // + cs_fold(// foldr nests the if-elses correctly, leaving the first field + // as the outermost one, and the last as the innermost. + false, + |cx, span, old, self_f, other_fs| { + // match new { + // Some(::std::cmp::Ordering::Equal) => old, + // __cmp => __cmp + // } - match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { - ::std::option::Option::Some(::std::cmp::Ordering::Equal) => - match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { - ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { - ... - } - __cmp => __cmp - }, - __cmp => __cmp - } - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // match new { - // Some(::std::cmp::Ordering::Equal) => old, - // __cmp => __cmp - // } + let new = { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ + let args = vec![ cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone()), ]; - cx.expr_call_global(span, partial_cmp_path.clone(), args) - }; + cx.expr_call_global(span, partial_cmp_path.clone(), args) + }; - let eq_arm = cx.arm(span, - vec![cx.pat_some(span, - cx.pat_enum(span, - ordering.clone(), - vec![]))], - old); - let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], - cx.expr_ident(span, test_id)); + let eq_arm = cx.arm(span, + vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - equals_expr.clone(), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) - } - }), - cx, span, substr) + cx.expr_match(span, new, vec![eq_arm, neq_arm]) + }, + equals_expr.clone(), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) + } + }), + cx, + span, + substr) } /// Strict inequality. -fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, - span: Span, substr: &Substructure) -> P { +fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let op = if less { BinOpKind::Lt } else { BinOpKind::Gt }; - cs_fold( - false, // need foldr, - |cx, span, subexpr, self_f, other_fs| { - /* - build up a series of chain ||'s and &&'s from the inside - out (hence foldr) to get lexical ordering, i.e. for op == - `ast::lt` + cs_fold(false, // need foldr, + |cx, span, subexpr, self_f, other_fs| { + // build up a series of chain ||'s and &&'s from the inside + // out (hence foldr) to get lexical ordering, i.e. for op == + // `ast::lt` + // + // ``` + // self.f1 < other.f1 || (!(other.f1 < self.f1) && + // (self.f2 < other.f2 || (!(other.f2 < self.f2) && + // (false) + // )) + // ) + // ``` + // + // The optimiser should remove the redundancy. We explicitly + // get use the binops to avoid auto-deref dereferencing too many + // layers of pointers, if the type includes pointers. + // + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; - ``` - self.f1 < other.f1 || (!(other.f1 < self.f1) && - (self.f2 < other.f2 || (!(other.f2 < self.f2) && - (false) - )) - ) - ``` + let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - The optimiser should remove the redundancy. We explicitly - get use the binops to avoid auto-deref dereferencing too many - layers of pointers, if the type includes pointers. - */ - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + let not_cmp = cx.expr_unary(span, + ast::UnOp::Not, + cx.expr_binary(span, op, other_f.clone(), self_f)); + + let and = cx.expr_binary(span, BinOpKind::And, not_cmp, subexpr); + cx.expr_binary(span, BinOpKind::Or, cmp, and) + }, + cx.expr_bool(span, equal), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + let op = match (less, equal) { + (true, true) => LeOp, + (true, false) => LtOp, + (false, true) => GeOp, + (false, false) => GtOp, }; - - let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - - let not_cmp = cx.expr_unary(span, ast::UnOp::Not, - cx.expr_binary(span, op, other_f.clone(), self_f)); - - let and = cx.expr_binary(span, BinOpKind::And, not_cmp, subexpr); - cx.expr_binary(span, BinOpKind::Or, cmp, and) - }, - cx.expr_bool(span, equal), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let op = match (less, equal) { - (true, true) => LeOp, (true, false) => LtOp, - (false, true) => GeOp, (false, false) => GtOp, - }; - some_ordering_collapsed(cx, span, op, tag_tuple) - } - }), - cx, span, substr) + some_ordering_collapsed(cx, span, op, tag_tuple) + } + }), + cx, + span, + substr) } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 34c872bef11d..a31c695e3604 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -12,19 +12,18 @@ use deriving::generic::*; use deriving::generic::ty::*; use syntax::ast; -use syntax::ast::{MetaItem, Expr}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{DUMMY_SP, Span}; pub fn expand_deriving_debug(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut FnMut(Annotatable)) { // &mut ::std::fmt::Formatter let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))), Borrowed(None, ast::Mutability::Mutable)); @@ -36,57 +35,54 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec![ - MethodDef { - name: "fmt", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(fmtr), - ret_ty: Literal(path_std!(cx, core::fmt::Result)), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - show_substructure(a, b, c) - })) - } - ], + methods: vec![MethodDef { + name: "fmt", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![fmtr], + ret_ty: Literal(path_std!(cx, core::fmt::Result)), + attributes: Vec::new(), + is_unsafe: false, + unify_fieldless_variants: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + show_substructure(a, b, c) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) } /// We use the debug builders to do the heavy lifting here -fn show_substructure(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { +fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { // build fmt.debug_struct().field(, &)....build() // or fmt.debug_tuple().field(&)....build() // based on the "shape". let (ident, is_struct) = match *substr.fields { Struct(vdata, _) => (substr.type_ident, vdata.is_struct()), EnumMatching(_, v, _) => (v.node.name, v.node.data.is_struct()), - EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { - cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") - } + EnumNonMatchingCollapsed(..) | + StaticStruct(..) | + StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), .. span }; - let name = cx.expr_lit(span, ast::LitKind::Str(ident.name.as_str(), ast::StrStyle::Cooked)); + let span = Span { expn_id: cx.backtrace(), ..span }; + let name = cx.expr_lit(span, + ast::LitKind::Str(ident.name.as_str(), ast::StrStyle::Cooked)); let builder = token::str_to_ident("builder"); let builder_expr = cx.expr_ident(span, builder.clone()); let fmt = substr.nonself_args[0].clone(); let mut stmts = match *substr.fields { - Struct(_, ref fields) | EnumMatching(_, _, ref fields) => { + Struct(_, ref fields) | + EnumMatching(_, _, ref fields) => { let mut stmts = vec![]; if !is_struct { // tuple struct/"normal" variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_tuple"), - vec![name]); + let expr = + cx.expr_method_call(span, fmt, token::str_to_ident("debug_tuple"), vec![name]); stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { @@ -105,16 +101,14 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, } } else { // normal struct/struct variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_struct"), - vec![name]); + let expr = + cx.expr_method_call(span, fmt, token::str_to_ident("debug_struct"), vec![name]); stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { - let name = cx.expr_lit(field.span, ast::LitKind::Str( - field.name.unwrap().name.as_str(), - ast::StrStyle::Cooked)); + let name = cx.expr_lit(field.span, + ast::LitKind::Str(field.name.unwrap().name.as_str(), + ast::StrStyle::Cooked)); // Use double indirection to make sure this works for unsized types let field = cx.expr_addr_of(field.span, field.self_.clone()); @@ -128,22 +122,17 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, } stmts } - _ => unreachable!() + _ => unreachable!(), }; - let expr = cx.expr_method_call(span, - builder_expr, - token::str_to_ident("finish"), - vec![]); + let expr = cx.expr_method_call(span, builder_expr, token::str_to_ident("finish"), vec![]); stmts.push(cx.stmt_expr(expr)); let block = cx.block(span, stmts); cx.expr_block(block) } -fn stmt_let_undescore(cx: &mut ExtCtxt, - sp: Span, - expr: P) -> ast::Stmt { +fn stmt_let_undescore(cx: &mut ExtCtxt, sp: Span, expr: P) -> ast::Stmt { let local = P(ast::Local { pat: cx.pat_wild(sp), ty: None, diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 488402c48f70..9a332227053c 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -15,8 +15,8 @@ use deriving::generic::*; use deriving::generic::ty::*; use syntax::ast; -use syntax::ast::{MetaItem, Expr, Mutability}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem, Mutability}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::parse::token; @@ -27,8 +27,7 @@ pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") } @@ -36,8 +35,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") } @@ -46,13 +44,13 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable), - krate: &'static str) -{ + krate: &'static str) { if cx.crate_root != Some("std") { // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ + cx.span_err(span, + "this trait cannot be derived with #![no_std] \ or #![no_core]"); - return + return; } let typaram = &*deriving::hygienic_type_parameter(item, "__D"); @@ -60,50 +58,50 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), + path: Path::new_(vec![krate, "Decodable"], None, vec![], true), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "decode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![(typaram, - vec![Path::new_(vec!(krate, "Decoder"), None, vec!(), true)])] - }, - explicit_self: None, - args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))), - Borrowed(None, Mutability::Mutable))), - ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), - None, - vec!(Box::new(Self_), Box::new(Literal(Path::new_( + methods: vec![MethodDef { + name: "decode", + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec![(typaram, + vec![Path::new_(vec![krate, "Decoder"], + None, + vec![], + true)])], + }, + explicit_self: None, + args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), + Borrowed(None, Mutability::Mutable))], + ret_ty: + Literal(Path::new_(pathvec_std!(cx, core::result::Result), + None, + vec!(Box::new(Self_), Box::new(Literal(Path::new_( vec![typaram, "Error"], None, vec![], false )))), - true - )), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - } - ), + true)), + attributes: Vec::new(), + is_unsafe: false, + unify_fieldless_variants: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + decodable_substructure(a, b, c, krate) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) } -fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, +fn decodable_substructure(cx: &mut ExtCtxt, + trait_span: Span, substr: &Substructure, - krate: &str) -> P { + krate: &str) + -> P { let decoder = substr.nonself_args[0].clone(); - let recurse = vec!(cx.ident_of(krate), - cx.ident_of("Decodable"), - cx.ident_of("decode")); + let recurse = vec![cx.ident_of(krate), cx.ident_of("Decodable"), cx.ident_of("decode")]; let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); // throw an underscore in front to suppress unused variable warnings let blkarg = cx.ident_of("_d"); @@ -113,31 +111,28 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, StaticStruct(_, ref summary) => { let nfields = match *summary { Unnamed(ref fields) => fields.len(), - Named(ref fields) => fields.len() + Named(ref fields) => fields.len(), }; let read_struct_field = cx.ident_of("read_struct_field"); let path = cx.path_ident(trait_span, substr.type_ident); - let result = decode_static_fields(cx, - trait_span, - path, - summary, - |cx, span, name, field| { - cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), read_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone()))) - }); + let result = + decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| { + cx.expr_try(span, + cx.expr_method_call(span, + blkdecoder.clone(), + read_struct_field, + vec![cx.expr_str(span, name), + cx.expr_usize(span, field), + exprdecode.clone()])) + }); let result = cx.expr_ok(trait_span, result); cx.expr_method_call(trait_span, decoder, cx.ident_of("read_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg) - )) + vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), + cx.expr_usize(trait_span, nfields), + cx.lambda_expr_1(trait_span, result, blkarg)]) } StaticEnum(_, ref fields) => { let variant = cx.ident_of("i"); @@ -150,42 +145,39 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, variants.push(cx.expr_str(v_span, ident.name.as_str())); let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = decode_static_fields(cx, - v_span, - path, - parts, - |cx, span, _, field| { + let decoded = decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| { let idx = cx.expr_usize(span, field); cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg, - vec!(idx, exprdecode.clone()))) + cx.expr_method_call(span, + blkdecoder.clone(), + rvariant_arg, + vec![idx, exprdecode.clone()])) }); arms.push(cx.arm(v_span, - vec!(cx.pat_lit(v_span, cx.expr_usize(v_span, i))), + vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))], decoded)); } arms.push(cx.arm_unreachable(trait_span)); - let result = cx.expr_ok(trait_span, - cx.expr_match(trait_span, - cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec!(blkarg, variant), result); + let result = + cx.expr_ok(trait_span, + cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms)); + let lambda = cx.lambda_expr(trait_span, vec![blkarg, variant], result); let variant_vec = cx.expr_vec(trait_span, variants); let variant_vec = cx.expr_addr_of(trait_span, variant_vec); - let result = cx.expr_method_call(trait_span, blkdecoder, + let result = cx.expr_method_call(trait_span, + blkdecoder, cx.ident_of("read_enum_variant"), - vec!(variant_vec, lambda)); + vec![variant_vec, lambda]); cx.expr_method_call(trait_span, decoder, cx.ident_of("read_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg) - )) + vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), + cx.lambda_expr_1(trait_span, result, blkarg)]) } - _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)") + _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), }; } @@ -197,8 +189,8 @@ fn decode_static_fields(cx: &mut ExtCtxt, outer_pat_path: ast::Path, fields: &StaticFields, mut getarg: F) - -> P where - F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P, + -> P + where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P { match *fields { Unnamed(ref fields) => { @@ -206,21 +198,28 @@ fn decode_static_fields(cx: &mut ExtCtxt, if fields.is_empty() { path_expr } else { - let fields = fields.iter().enumerate().map(|(i, &span)| { - getarg(cx, span, - token::intern_and_get_ident(&format!("_field{}", i)), - i) - }).collect(); + let fields = fields.iter() + .enumerate() + .map(|(i, &span)| { + getarg(cx, + span, + token::intern_and_get_ident(&format!("_field{}", i)), + i) + }) + .collect(); cx.expr_call(trait_span, path_expr, fields) } } Named(ref fields) => { // use the field's span to get nicer error messages. - let fields = fields.iter().enumerate().map(|(i, &(ident, span))| { - let arg = getarg(cx, span, ident.name.as_str(), i); - cx.field_imm(span, ident, arg) - }).collect(); + let fields = fields.iter() + .enumerate() + .map(|(i, &(ident, span))| { + let arg = getarg(cx, span, ident.name.as_str(), i); + cx.field_imm(span, ident, arg) + }) + .collect(); cx.expr_struct(trait_span, outer_pat_path, fields) } } diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 2711ccba8191..9df3db938b1f 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,10 +22,9 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -33,21 +32,19 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "default", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - default_substructure(a, b, c) - })) - } - ), + methods: vec![MethodDef { + name: "default", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: Vec::new(), + ret_ty: Self_, + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + default_substructure(a, b, c) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) @@ -69,18 +66,19 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur } } Named(ref fields) => { - let default_fields = fields.iter().map(|&(ident, span)| { - cx.field_imm(span, ident, default_call(span)) - }).collect(); + let default_fields = fields.iter() + .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) + .collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) } } } StaticEnum(..) => { - cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs"); + cx.span_err(trait_span, + "`Default` cannot be derived for enums, only structs"); // let compilation continue cx.expr_usize(trait_span, 0) } - _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`") + _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`"), }; } diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index ad3786212475..940fdf037711 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -92,8 +92,8 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, ExprKind, Mutability}; -use syntax::ext::base::{ExtCtxt,Annotatable}; +use syntax::ast::{Expr, ExprKind, MetaItem, Mutability}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; @@ -103,8 +103,7 @@ pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") } @@ -112,8 +111,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") } @@ -122,11 +120,11 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable), - krate: &'static str) -{ + krate: &'static str) { if cx.crate_root != Some("std") { // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ + cx.span_err(span, + "this trait cannot be derived with #![no_std] \ or #![no_core]"); return; } @@ -136,7 +134,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), + path: Path::new_(vec![krate, "Encodable"], None, vec![], true), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, @@ -173,40 +171,38 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push) } -fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, krate: &'static str) -> P { +fn encodable_substructure(cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + krate: &'static str) + -> P { let encoder = substr.nonself_args[0].clone(); // throw an underscore in front to suppress unused variable warnings let blkarg = cx.ident_of("_e"); let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global(trait_span, vec![cx.ident_of(krate), - cx.ident_of("Encodable"), - cx.ident_of("encode")])); + let fn_path = cx.expr_path(cx.path_global(trait_span, + vec![cx.ident_of(krate), + cx.ident_of("Encodable"), + cx.ident_of("encode")])); return match *substr.fields { Struct(_, ref fields) => { let emit_struct_field = cx.ident_of("emit_struct_field"); let mut stmts = Vec::new(); - for (i, &FieldInfo { - name, - ref self_, - span, - .. - }) in fields.iter().enumerate() { + for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() { let name = match name { Some(id) => id.name.as_str(), - None => { - token::intern_and_get_ident(&format!("_field{}", i)) - } + None => token::intern_and_get_ident(&format!("_field{}", i)), }; let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), + let call = cx.expr_method_call(span, + blkencoder.clone(), emit_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda)); + vec![cx.expr_str(span, name), + cx.expr_usize(span, i), + lambda]); // last call doesn't need a try! let last = fields.len() - 1; @@ -229,11 +225,9 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, fields.len()), - blk - )) + vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), + cx.expr_usize(trait_span, fields.len()), + blk]) } EnumMatching(idx, variant, ref fields) => { @@ -248,14 +242,14 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, if !fields.is_empty() { let last = fields.len() - 1; for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { - let self_ref = cx.expr_addr_of(span, self_.clone()); - let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, - blkencoder.clone()]); + let self_ref = cx.expr_addr_of(span, self_.clone()); + let enc = + cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), + let call = cx.expr_method_call(span, + blkencoder.clone(), emit_variant_arg, - vec!(cx.expr_usize(span, i), - lambda)); + vec![cx.expr_usize(span, i), lambda]); let call = if i != last { cx.expr_try(span, call) } else { @@ -271,23 +265,23 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); let name = cx.expr_str(trait_span, variant.node.name.name.as_str()); - let call = cx.expr_method_call(trait_span, blkencoder, + let call = cx.expr_method_call(trait_span, + blkencoder, cx.ident_of("emit_enum_variant"), - vec!(name, - cx.expr_usize(trait_span, idx), - cx.expr_usize(trait_span, fields.len()), - blk)); + vec![name, + cx.expr_usize(trait_span, idx), + cx.expr_usize(trait_span, fields.len()), + blk]); let blk = cx.lambda_expr_1(trait_span, call, blkarg); let ret = cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - blk - )); + vec![cx.expr_str(trait_span, + substr.type_ident.name.as_str()), + blk]); cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)])) } - _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)") + _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"), }; } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index f33898109cc5..cd49e7ec9d2c 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -192,16 +192,16 @@ use std::collections::HashSet; use std::vec; use syntax::abi::Abi; -use syntax::ast::{self, EnumDef, Expr, Ident, Generics, VariantData, BinOpKind, PatKind}; +use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData}; use syntax::attr; use syntax::attr::AttrMetaMethods; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::codemap::{self, respan}; use syntax::util::move_map::MoveMap; -use syntax::parse::token::{keywords, InternedString}; +use syntax::parse::token::{InternedString, keywords}; use syntax::ptr::P; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{DUMMY_SP, Span}; use errors::Handler; use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; @@ -273,7 +273,7 @@ pub struct Substructure<'a> { pub self_args: &'a [P], /// verbatim access to any other arguments pub nonself_args: &'a [P], - pub fields: &'a SubstructureFields<'a> + pub fields: &'a SubstructureFields<'a>, } /// Summary of the relevant parts of a struct/enum field. @@ -338,14 +338,17 @@ pub type EnumNonMatchCollapsedFunc<'a> = Box]) -> P + 'a>; pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) - -> RefCell> { + -> RefCell> { RefCell::new(f) } /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter ``, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. -fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name], span: Span, cx: &ExtCtxt) +fn find_type_parameters(ty: &ast::Ty, + ty_param_names: &[ast::Name], + span: Span, + cx: &ExtCtxt) -> Vec> { use syntax::visit; @@ -395,23 +398,15 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt, mitem: &ast::MetaItem, item: &'a Annotatable, - push: &mut FnMut(Annotatable)) - { + push: &mut FnMut(Annotatable)) { match *item { Annotatable::Item(ref item) => { let newitem = match item.node { ast::ItemKind::Struct(ref struct_def, ref generics) => { - self.expand_struct_def(cx, - &struct_def, - item.ident, - generics) + self.expand_struct_def(cx, &struct_def, item.ident, generics) } ast::ItemKind::Enum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, - enum_def, - &item.attrs, - item.ident, - generics) + self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics) } _ => { cx.span_err(mitem.span, @@ -422,19 +417,20 @@ impl<'a> TraitDef<'a> { // Keep the lint attributes of the previous item to control how the // generated implementations are linted let mut attrs = newitem.attrs.clone(); - attrs.extend(item.attrs.iter().filter(|a| { - match &a.name()[..] { - "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, - _ => false, - } - }).cloned()); - push(Annotatable::Item(P(ast::Item { - attrs: attrs, - ..(*newitem).clone() - }))) + attrs.extend(item.attrs + .iter() + .filter(|a| { + match &a.name()[..] { + "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, + _ => false, + } + }) + .cloned()); + push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) } _ => { - cx.span_err(mitem.span, "`derive` may only be applied to structs and enums"); + cx.span_err(mitem.span, + "`derive` may only be applied to structs and enums"); } } } @@ -475,7 +471,8 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, field_tys: Vec>, - methods: Vec) -> P { + methods: Vec) + -> P { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem` @@ -487,16 +484,12 @@ impl<'a> TraitDef<'a> { vis: ast::Visibility::Inherited, defaultness: ast::Defaultness::Final, attrs: Vec::new(), - node: ast::ImplItemKind::Type(type_def.to_ty(cx, - self.span, - type_ident, - generics - )), + node: ast::ImplItemKind::Type(type_def.to_ty(cx, self.span, type_ident, generics)), } }); - let Generics { mut lifetimes, ty_params, mut where_clause } = - self.generics.to_generics(cx, self.span, type_ident, generics); + let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics + .to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); // Copy the lifetimes @@ -521,10 +514,7 @@ impl<'a> TraitDef<'a> { bounds.push((*declared_bound).clone()); } - cx.typaram(self.span, - ty_param.ident, - P::from_vec(bounds), - None) + cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None) })); // and similarly for where clauses @@ -542,7 +532,7 @@ impl<'a> TraitDef<'a> { ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { span: self.span, lifetime: rb.lifetime, - bounds: rb.bounds.iter().cloned().collect() + bounds: rb.bounds.iter().cloned().collect(), }) } ast::WherePredicate::EqPredicate(ref we) => { @@ -550,7 +540,7 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, path: we.path.clone(), - ty: we.ty.clone() + ty: we.ty.clone(), }) } } @@ -568,16 +558,17 @@ impl<'a> TraitDef<'a> { for ty in tys { // if we have already handled this type, skip it if let ast::TyKind::Path(_, ref p) = ty.node { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].identifier.name) - || processed_field_types.contains(&p.segments) { + if p.segments.len() == 1 && + ty_param_names.contains(&p.segments[0].identifier.name) || + processed_field_types.contains(&p.segments) { continue; }; processed_field_types.insert(p.segments.clone()); } - let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) - }).collect(); + let mut bounds: Vec<_> = self.additional_bounds + .iter() + .map(|p| cx.typarambound(p.to_path(cx, self.span, type_ident, generics))) + .collect(); // require the current trait bounds.push(cx.typarambound(trait_path.clone())); @@ -598,40 +589,41 @@ impl<'a> TraitDef<'a> { let trait_generics = Generics { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), - where_clause: where_clause + where_clause: where_clause, }; // Create the reference to the trait. let trait_ref = cx.trait_ref(trait_path); // Create the type parameters on the `self` path. - let self_ty_params = generics.ty_params.iter().map(|ty_param| { - cx.ty_ident(self.span, ty_param.ident) - }).collect(); + let self_ty_params = generics.ty_params + .iter() + .map(|ty_param| cx.ty_ident(self.span, ty_param.ident)) + .collect(); - let self_lifetimes: Vec = - generics.lifetimes + let self_lifetimes: Vec = generics.lifetimes .iter() .map(|ld| ld.lifetime) .collect(); // Create the type of `self`. - let self_type = cx.ty_path( - cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes, - self_ty_params, Vec::new())); + let self_type = cx.ty_path(cx.path_all(self.span, + false, + vec![type_ident], + self_lifetimes, + self_ty_params, + Vec::new())); - let attr = cx.attribute( - self.span, - cx.meta_word(self.span, - InternedString::new("automatically_derived"))); + let attr = cx.attribute(self.span, + cx.meta_word(self.span, + InternedString::new("automatically_derived"))); // Just mark it now since we know that it'll end up used downstream attr::mark_used(&attr); let opt_trait_ref = Some(trait_ref); - let unused_qual = cx.attribute( - self.span, - cx.meta_list(self.span, - InternedString::new("allow"), - vec![cx.meta_word(self.span, + let unused_qual = cx.attribute(self.span, + cx.meta_list(self.span, + InternedString::new("allow"), + vec![cx.meta_word(self.span, InternedString::new("unused_qualifications"))])); let mut a = vec![attr, unused_qual]; a.extend(self.attributes.iter().cloned()); @@ -642,58 +634,60 @@ impl<'a> TraitDef<'a> { ast::Unsafety::Normal }; - cx.item( - self.span, - keywords::Invalid.ident(), - a, - ast::ItemKind::Impl(unsafety, - ast::ImplPolarity::Positive, - trait_generics, - opt_trait_ref, - self_type, - methods.into_iter().chain(associated_types).collect())) + cx.item(self.span, + keywords::Invalid.ident(), + a, + ast::ItemKind::Impl(unsafety, + ast::ImplPolarity::Positive, + trait_generics, + opt_trait_ref, + self_type, + methods.into_iter().chain(associated_types).collect())) } fn expand_struct_def(&self, cx: &mut ExtCtxt, struct_def: &'a VariantData, type_ident: Ident, - generics: &Generics) -> P { - let field_tys: Vec> = struct_def.fields().iter() + generics: &Generics) + -> P { + let field_tys: Vec> = struct_def.fields() + .iter() .map(|field| field.ty.clone()) .collect(); - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args( - cx, self, type_ident, generics); + let methods = self.methods + .iter() + .map(|method_def| { + let (explicit_self, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { - method_def.expand_static_struct_method_body( - cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_struct_method_body(cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - }; + let body = if method_def.is_static() { + method_def.expand_static_struct_method_body(cx, + self, + struct_def, + type_ident, + &self_args[..], + &nonself_args[..]) + } else { + method_def.expand_struct_method_body(cx, + self, + struct_def, + type_ident, + &self_args[..], + &nonself_args[..]) + }; - method_def.create_method(cx, - self, - type_ident, - generics, - Abi::Rust, - explicit_self, - tys, - body) - }).collect(); + method_def.create_method(cx, + self, + type_ident, + generics, + Abi::Rust, + explicit_self, + tys, + body) + }) + .collect(); self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } @@ -703,53 +697,57 @@ impl<'a> TraitDef<'a> { enum_def: &'a EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, - generics: &Generics) -> P { + generics: &Generics) + -> P { let mut field_tys = Vec::new(); for variant in &enum_def.variants { - field_tys.extend(variant.node.data.fields().iter() + field_tys.extend(variant.node + .data + .fields() + .iter() .map(|field| field.ty.clone())); } - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, - type_ident, generics); + let methods = self.methods + .iter() + .map(|method_def| { + let (explicit_self, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { - method_def.expand_static_enum_method_body( - cx, - self, - enum_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_enum_method_body(cx, - self, - enum_def, - type_attrs, - type_ident, - self_args, - &nonself_args[..]) - }; + let body = if method_def.is_static() { + method_def.expand_static_enum_method_body(cx, + self, + enum_def, + type_ident, + &self_args[..], + &nonself_args[..]) + } else { + method_def.expand_enum_method_body(cx, + self, + enum_def, + type_attrs, + type_ident, + self_args, + &nonself_args[..]) + }; - method_def.create_method(cx, - self, - type_ident, - generics, - Abi::Rust, - explicit_self, - tys, - body) - }).collect(); + method_def.create_method(cx, + self, + type_ident, + generics, + Abi::Rust, + explicit_self, + tys, + body) + }) + .collect(); self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } } -fn find_repr_type_name(diagnostic: &Handler, - type_attrs: &[ast::Attribute]) -> &'static str { +fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &'static str { let mut repr_type_name = "isize"; for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { @@ -782,13 +780,13 @@ impl<'a> MethodDef<'a> { self_args: &[P], nonself_args: &[P], fields: &SubstructureFields) - -> P { + -> P { let substructure = Substructure { type_ident: type_ident, method_ident: cx.ident_of(self.name), self_args: self_args, nonself_args: nonself_args, - fields: fields + fields: fields, }; let mut f = self.combine_substructure.borrow_mut(); let f: &mut CombineSubstructureFunc = &mut *f; @@ -808,12 +806,13 @@ impl<'a> MethodDef<'a> { self.explicit_self.is_none() } - fn split_self_nonself_args(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics) - -> (Option, Vec>, Vec>, Vec<(Ident, P)>) { + fn split_self_nonself_args + (&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + type_ident: Ident, + generics: &Generics) + -> (Option, Vec>, Vec>, Vec<(Ident, P)>) { let mut self_args = Vec::new(); let mut nonself_args = Vec::new(); @@ -839,7 +838,7 @@ impl<'a> MethodDef<'a> { match *ty { // for static methods, just treat any Self // arguments as a normal arg - Self_ if nonstatic => { + Self_ if nonstatic => { self_args.push(arg_expr); } Ptr(ref ty, _) if **ty == Self_ && nonstatic => { @@ -861,18 +860,20 @@ impl<'a> MethodDef<'a> { generics: &Generics, abi: Abi, explicit_self: Option, - arg_types: Vec<(Ident, P)> , - body: P) -> ast::ImplItem { + arg_types: Vec<(Ident, P)>, + body: P) + -> ast::ImplItem { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); let args = { let self_args = explicit_self.map(|explicit_self| { - ast::Arg::from_self(explicit_self, respan(trait_.span, keywords::SelfValue.ident())) + ast::Arg::from_self(explicit_self, + respan(trait_.span, keywords::SelfValue.ident())) }); let nonself_args = arg_types.into_iter() - .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + .map(|(name, ty)| cx.arg(trait_.span, name, ty)); self_args.into_iter().chain(nonself_args).collect() }; @@ -897,12 +898,13 @@ impl<'a> MethodDef<'a> { defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { - generics: fn_generics, - abi: abi, - unsafety: unsafety, - constness: ast::Constness::NotConst, - decl: fn_decl - }, body_block) + generics: fn_generics, + abi: abi, + unsafety: unsafety, + constness: ast::Constness::NotConst, + decl: fn_decl, + }, + body_block), } } @@ -926,26 +928,24 @@ impl<'a> MethodDef<'a> { /// } /// ``` fn expand_struct_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - struct_def: &'b VariantData, - type_ident: Ident, - self_args: &[P], - nonself_args: &[P]) - -> P { + cx: &mut ExtCtxt, + trait_: &TraitDef<'b>, + struct_def: &'b VariantData, + type_ident: Ident, + self_args: &[P], + nonself_args: &[P]) + -> P { let mut raw_fields = Vec::new(); // Vec<[fields of self], // [fields of next Self arg], [etc]> let mut patterns = Vec::new(); for i in 0..self_args.len() { - let struct_path= cx.path(DUMMY_SP, vec!( type_ident )); - let (pat, ident_expr) = - trait_.create_struct_pattern(cx, - struct_path, - struct_def, - &format!("__self_{}", - i), - ast::Mutability::Immutable); + let struct_path = cx.path(DUMMY_SP, vec![type_ident]); + let (pat, ident_expr) = trait_.create_struct_pattern(cx, + struct_path, + struct_def, + &format!("__self_{}", i), + ast::Mutability::Immutable); patterns.push(pat); raw_fields.push(ident_expr); } @@ -954,21 +954,23 @@ impl<'a> MethodDef<'a> { let fields = if !raw_fields.is_empty() { let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec> - = raw_fields.collect(); + let mut other_fields: Vec> = raw_fields.collect(); first_field.map(|(span, opt_id, field, attrs)| { - FieldInfo { - span: span, - name: opt_id, - self_: field, - other: other_fields.iter_mut().map(|l| { - match l.next().unwrap() { - (_, _, ex, _) => ex - } - }).collect(), - attrs: attrs, - } - }).collect() + FieldInfo { + span: span, + name: opt_id, + self_: field, + other: other_fields.iter_mut() + .map(|l| { + match l.next().unwrap() { + (_, _, ex, _) => ex, + } + }) + .collect(), + attrs: attrs, + } + }) + .collect() } else { cx.span_bug(trait_.span, "no self arguments to non-static method in generic \ @@ -976,20 +978,20 @@ impl<'a> MethodDef<'a> { }; // body of the inner most destructuring match - let mut body = self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &Struct(struct_def, fields)); + let mut body = self.call_substructure_method(cx, + trait_, + type_ident, + self_args, + nonself_args, + &Struct(struct_def, fields)); // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't // matter. for (arg_expr, pat) in self_args.iter().zip(patterns) { - body = cx.expr_match(trait_.span, arg_expr.clone(), - vec!( cx.arm(trait_.span, vec!(pat.clone()), body) )) + body = cx.expr_match(trait_.span, + arg_expr.clone(), + vec![cx.arm(trait_.span, vec![pat.clone()], body)]) } body @@ -1002,13 +1004,14 @@ impl<'a> MethodDef<'a> { type_ident: Ident, self_args: &[P], nonself_args: &[P]) - -> P { + -> P { let summary = trait_.summarise_struct(cx, struct_def); self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, + self_args, + nonself_args, &StaticStruct(struct_def, summary)) } @@ -1042,16 +1045,21 @@ impl<'a> MethodDef<'a> { /// as their results are unused. The point of `__self_vi` and /// `__arg_1_vi` is for `PartialOrd`; see #15503.) fn expand_enum_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec>, - nonself_args: &[P]) - -> P { - self.build_enum_match_tuple( - cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args) + cx: &mut ExtCtxt, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, + type_attrs: &[ast::Attribute], + type_ident: Ident, + self_args: Vec>, + nonself_args: &[P]) + -> P { + self.build_enum_match_tuple(cx, + trait_, + enum_def, + type_attrs, + type_ident, + self_args, + nonself_args) } @@ -1090,20 +1098,21 @@ impl<'a> MethodDef<'a> { /// ... // catch-all remainder can inspect above variant index values. /// } /// ``` - fn build_enum_match_tuple<'b>( - &self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec>, - nonself_args: &[P]) -> P { + fn build_enum_match_tuple<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, + type_attrs: &[ast::Attribute], + type_ident: Ident, + self_args: Vec>, + nonself_args: &[P]) + -> P { let sp = trait_.span; let variants = &enum_def.variants; - let self_arg_names = self_args.iter().enumerate() + let self_arg_names = self_args.iter() + .enumerate() .map(|(arg_count, _self_arg)| { if arg_count == 0 { "__self".to_string() @@ -1114,22 +1123,24 @@ impl<'a> MethodDef<'a> { .collect::>(); let self_arg_idents = self_arg_names.iter() - .map(|name|cx.ident_of(&name[..])) + .map(|name| cx.ident_of(&name[..])) .collect::>(); // The `vi_idents` will be bound, solely in the catch-all, to // a series of let statements mapping each self_arg to an int // value corresponding to its discriminant. let vi_idents: Vec = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..]) }) + .map(|name| { + let vi_suffix = format!("{}_vi", &name[..]); + cx.ident_of(&vi_suffix[..]) + }) .collect::>(); // Builds, via callback to call_substructure_method, the // delegated expression that handles the catch-all case, // using `__variants_tuple` to drive logic if necessary. - let catch_all_substructure = EnumNonMatchingCollapsed( - self_arg_idents, &variants[..], &vi_idents[..]); + let catch_all_substructure = + EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]); let first_fieldless = variants.iter().find(|v| v.node.data.fields().is_empty()); @@ -1138,15 +1149,16 @@ impl<'a> MethodDef<'a> { // (Variant2, Variant2, ...) => Body2 // ... // where each tuple has length = self_args.len() - let mut match_arms: Vec = variants.iter().enumerate() + let mut match_arms: Vec = variants.iter() + .enumerate() .filter(|&(_, v)| !(self.unify_fieldless_variants && v.node.data.fields().is_empty())) .map(|(index, variant)| { let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| { - let (p, idents) = trait_.create_enum_variant_pattern( - cx, type_ident, - variant, - self_arg_name, - ast::Mutability::Immutable); + let (p, idents) = trait_.create_enum_variant_pattern(cx, + type_ident, + variant, + self_arg_name, + ast::Mutability::Immutable); (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Immutable)), idents) }; @@ -1213,24 +1225,29 @@ impl<'a> MethodDef<'a> { // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, - variant, - field_tuples); - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &substructure); + let substructure = EnumMatching(index, variant, field_tuples); + let arm_expr = self.call_substructure_method(cx, + trait_, + type_ident, + &self_args[..], + nonself_args, + &substructure); cx.arm(sp, vec![single_pat], arm_expr) - }).collect(); + }) + .collect(); let default = match first_fieldless { Some(v) if self.unify_fieldless_variants => { // We need a default case that handles the fieldless variants. // The index and actual variant aren't meaningful in this case, // so just use whatever - Some(self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &EnumMatching(0, v, Vec::new()))) + Some(self.call_substructure_method(cx, + trait_, + type_ident, + &self_args[..], + nonself_args, + &EnumMatching(0, v, Vec::new()))) } _ if variants.len() > 1 && self_args.len() > 1 => { // Since we know that all the arguments will match if we reach @@ -1238,7 +1255,7 @@ impl<'a> MethodDef<'a> { // result of the catch all which should help llvm in optimizing it Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![])) } - _ => None + _ => None, }; if let Some(arm) = default { match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm)); @@ -1279,20 +1296,17 @@ impl<'a> MethodDef<'a> { // ``` let mut index_let_stmts: Vec = Vec::new(); - //We also build an expression which checks whether all discriminants are equal + // We also build an expression which checks whether all discriminants are equal // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... let mut discriminant_test = cx.expr_bool(sp, true); - let target_type_name = - find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); + let target_type_name = find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); let mut first_ident = None; for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { let self_addr = cx.expr_addr_of(sp, self_arg.clone()); - let variant_value = deriving::call_intrinsic(cx, - sp, - "discriminant_value", - vec![self_addr]); + let variant_value = + deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]); let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); let variant_disr = cx.expr_cast(sp, variant_value, target_ty); @@ -1304,8 +1318,8 @@ impl<'a> MethodDef<'a> { let first_expr = cx.expr_ident(sp, first); let id = cx.expr_ident(sp, ident); let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id); - discriminant_test = cx.expr_binary(sp, BinOpKind::And, - discriminant_test, test) + discriminant_test = + cx.expr_binary(sp, BinOpKind::And, discriminant_test, test) } None => { first_ident = Some(ident); @@ -1313,9 +1327,12 @@ impl<'a> MethodDef<'a> { } } - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &catch_all_substructure); + let arm_expr = self.call_substructure_method(cx, + trait_, + type_ident, + &self_args[..], + nonself_args, + &catch_all_substructure); // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref @@ -1325,7 +1342,7 @@ impl<'a> MethodDef<'a> { let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args)); - //Lastly we create an expression which branches on all discriminants being equal + // Lastly we create an expression which branches on all discriminants being equal // if discriminant_test { // match (...) { // (Variant1, Variant1, ...) => Body1 @@ -1392,8 +1409,7 @@ impl<'a> MethodDef<'a> { // that needs the feature gate enabled.) deriving::call_intrinsic(cx, sp, "unreachable", vec![]) - } - else { + } else { // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref @@ -1413,26 +1429,30 @@ impl<'a> MethodDef<'a> { type_ident: Ident, self_args: &[P], nonself_args: &[P]) - -> P { - let summary = enum_def.variants.iter().map(|v| { - let ident = v.node.name; - let summary = trait_.summarise_struct(cx, &v.node.data); - (ident, v.span, summary) - }).collect(); - self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, + -> P { + let summary = enum_def.variants + .iter() + .map(|v| { + let ident = v.node.name; + let summary = trait_.summarise_struct(cx, &v.node.data); + (ident, v.span, summary) + }) + .collect(); + self.call_substructure_method(cx, + trait_, + type_ident, + self_args, + nonself_args, &StaticEnum(enum_def, summary)) } } // general helper methods. impl<'a> TraitDef<'a> { - fn summarise_struct(&self, - cx: &mut ExtCtxt, - struct_def: &VariantData) -> StaticFields { + fn summarise_struct(&self, cx: &mut ExtCtxt, struct_def: &VariantData) -> StaticFields { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); - for field in struct_def.fields(){ + for field in struct_def.fields() { let sp = Span { expn_id: self.span.expn_id, ..field.span }; match field.ident { Some(ident) => named_idents.push((ident, sp)), @@ -1441,9 +1461,11 @@ impl<'a> TraitDef<'a> { } match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx.span_bug(self.span, - "a struct with named and unnamed \ - fields in generic `derive`"), + (false, false) => { + cx.span_bug(self.span, + "a struct with named and unnamed \ + fields in generic `derive`") + } // named fields (_, false) => Named(named_idents), // empty structs @@ -1454,46 +1476,57 @@ impl<'a> TraitDef<'a> { fn create_subpatterns(&self, cx: &mut ExtCtxt, - field_paths: Vec , + field_paths: Vec, mutbl: ast::Mutability) -> Vec> { - field_paths.iter().map(|path| { - cx.pat(path.span, - PatKind::Ident(ast::BindingMode::ByRef(mutbl), (*path).clone(), None)) - }).collect() + field_paths.iter() + .map(|path| { + cx.pat(path.span, + PatKind::Ident(ast::BindingMode::ByRef(mutbl), (*path).clone(), None)) + }) + .collect() } - fn create_struct_pattern(&self, - cx: &mut ExtCtxt, - struct_path: ast::Path, - struct_def: &'a VariantData, - prefix: &str, - mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, - P, - &'a [ast::Attribute])>) { + fn create_struct_pattern + (&self, + cx: &mut ExtCtxt, + struct_path: ast::Path, + struct_def: &'a VariantData, + prefix: &str, + mutbl: ast::Mutability) + -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let mut paths = Vec::new(); let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { let sp = Span { expn_id: self.span.expn_id, ..struct_field.span }; let ident = cx.ident_of(&format!("{}_{}", prefix, i)); - paths.push(codemap::Spanned{span: sp, node: ident}); - let val = cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))); + paths.push(codemap::Spanned { + span: sp, + node: ident, + }); + let val = cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp, ident))); let val = cx.expr(sp, ast::ExprKind::Paren(val)); ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..])); } let subpats = self.create_subpatterns(cx, paths, mutbl); let pattern = if struct_def.is_struct() { - let field_pats = subpats.into_iter().zip(&ident_exprs).map(|(pat, &(sp, ident, _, _))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } - codemap::Spanned { - span: pat.span, - node: ast::FieldPat { ident: ident.unwrap(), pat: pat, is_shorthand: false }, - } - }).collect(); + let field_pats = subpats.into_iter() + .zip(&ident_exprs) + .map(|(pat, &(sp, ident, _, _))| { + if ident.is_none() { + cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); + } + codemap::Spanned { + span: pat.span, + node: ast::FieldPat { + ident: ident.unwrap(), + pat: pat, + is_shorthand: false, + }, + } + }) + .collect(); cx.pat_struct(self.span, struct_path, field_pats) } else { cx.pat_enum(self.span, struct_path, subpats) @@ -1502,20 +1535,21 @@ impl<'a> TraitDef<'a> { (pattern, ident_exprs) } - fn create_enum_variant_pattern(&self, - cx: &mut ExtCtxt, - enum_ident: ast::Ident, - variant: &'a ast::Variant, - prefix: &str, - mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { + fn create_enum_variant_pattern + (&self, + cx: &mut ExtCtxt, + enum_ident: ast::Ident, + variant: &'a ast::Variant, + prefix: &str, + mutbl: ast::Mutability) + -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } } -/* helpful premade recipes */ +// helpful premade recipes /// Fold the fields. `use_foldl` controls whether this is done /// left-to-right (`true`) or right-to-left (`false`). @@ -1526,35 +1560,29 @@ pub fn cs_fold(use_foldl: bool, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) - -> P where - F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P, + -> P + where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P { match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => { + EnumMatching(_, _, ref all_fields) | + Struct(_, ref all_fields) => { if use_foldl { all_fields.iter().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) + f(cx, field.span, old, field.self_.clone(), &field.other) }) } else { all_fields.iter().rev().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) + f(cx, field.span, old, field.self_.clone(), &field.other) }) } - }, - EnumNonMatchingCollapsed(ref all_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") } + EnumNonMatchingCollapsed(ref all_args, _, tuple) => { + enum_nonmatch_f(cx, + trait_span, + (&all_args[..], tuple), + substructure.nonself_args) + } + StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } @@ -1572,29 +1600,34 @@ pub fn cs_same_method(f: F, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) - -> P where - F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P, + -> P + where F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P { match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => { + EnumMatching(_, _, ref all_fields) | + Struct(_, ref all_fields) => { // call self_n.method(other_1_n, other_2_n, ...) - let called = all_fields.iter().map(|field| { - cx.expr_method_call(field.span, - field.self_.clone(), - substructure.method_ident, - field.other.iter() - .map(|e| cx.expr_addr_of(field.span, e.clone())) - .collect()) - }).collect(); + let called = all_fields.iter() + .map(|field| { + cx.expr_method_call(field.span, + field.self_.clone(), + substructure.method_ident, + field.other + .iter() + .map(|e| cx.expr_addr_of(field.span, e.clone())) + .collect()) + }) + .collect(); f(cx, trait_span, called) - }, - EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") } + EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => { + enum_nonmatch_f(cx, + trait_span, + (&all_self_args[..], tuple), + substructure.nonself_args) + } + StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } @@ -1606,10 +1639,8 @@ pub fn is_type_without_fields(item: &Annotatable) -> bool { ast::ItemKind::Enum(ref enum_def, _) => { enum_def.variants.iter().all(|v| v.node.data.fields().is_empty()) } - ast::ItemKind::Struct(ref variant_data, _) => { - variant_data.fields().is_empty() - } - _ => false + ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(), + _ => false, } } else { false diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 0fad96c84ef3..81c8e7112dbd 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -12,8 +12,8 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, Mutability}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem, Mutability}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; use syntax_pos::Span; @@ -22,11 +22,9 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { - let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, - vec!(), true); + let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, vec![], true); let typaram = &*deriving::hygienic_type_parameter(item, "__H"); @@ -38,25 +36,23 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "hash", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![(typaram, - vec![path_std!(cx, core::hash::Hasher)])], - }, - explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mutable))), - ret_ty: nil_ty(), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) - })) - } - ), + methods: vec![MethodDef { + name: "hash", + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec![(typaram, vec![path_std!(cx, core::hash::Hasher)])], + }, + explicit_self: borrowed_explicit_self(), + args: vec![Ptr(Box::new(Literal(arg)), + Borrowed(None, Mutability::Mutable))], + ret_ty: nil_ty(), + attributes: vec![], + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + hash_substructure(a, b, c) + })), + }], associated_types: Vec::new(), }; @@ -66,7 +62,10 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { (1, Some(o_f)) => o_f, - _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`") + _ => { + cx.span_bug(trait_span, + "incorrect number of arguments in `derive(Hash)`") + } }; let call_hash = |span, thing_expr| { let hash_path = { @@ -75,7 +74,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) cx.expr_path(cx.path_global(span, strs)) }; let ref_thing = cx.expr_addr_of(span, thing_expr); - let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone())); + let expr = cx.expr_call(span, hash_path, vec![ref_thing, state_expr.clone()]); cx.stmt_expr(expr) }; let mut stmts = Vec::new(); @@ -92,7 +91,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) fs } - _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`") + _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"), }; for &FieldInfo { ref self_, span, .. } in fields { diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 169e80736619..80e2a923e556 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -10,9 +10,9 @@ //! The compiler code necessary to implement the `#[derive]` extensions. -use syntax::ast::{MetaItem, MetaItemKind, self}; +use syntax::ast::{self, MetaItem, MetaItemKind}; use syntax::attr::AttrMetaMethods; -use syntax::ext::base::{ExtCtxt, SyntaxEnv, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; @@ -123,7 +123,8 @@ fn expand_derive(cx: &mut ExtCtxt, span: Some(titem.span), allow_internal_unstable: true, }, - }), ..titem.span + }), + ..titem.span }; if &tname[..] == "Eq" { @@ -133,8 +134,9 @@ fn expand_derive(cx: &mut ExtCtxt, } // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(span, cx.meta_word(titem.span, - intern_and_get_ident(&format!("derive_{}", tname))))); + item.attrs.push(cx.attribute(span, + cx.meta_word(titem.span, + intern_and_get_ident(&format!("derive_{}", tname))))); } // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) @@ -142,18 +144,18 @@ fn expand_derive(cx: &mut ExtCtxt, if let Some(eq_span) = eq_span { if found_partial_eq { let structural_match = intern_and_get_ident("structural_match"); - item.attrs.push(cx.attribute(eq_span, - cx.meta_word(eq_span, - structural_match))); + item.attrs.push(cx.attribute(eq_span, cx.meta_word(eq_span, structural_match))); } } item }) - }, |a| { - cx.span_err(span, "`derive` can only be applied to items"); - a - }); + }, + |a| { + cx.span_err(span, + "`derive` can only be applied to items"); + a + }); debug!("expand_derive: annotatable output = {:?}", annot); annot } @@ -261,8 +263,10 @@ fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { "Decodable" => Some("RustcDecodable"), _ => None, } { - ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})", - name, replacement)); + ecx.span_warn(sp, + &format!("derive({}) is deprecated in favor of derive({})", + name, + replacement)); } } @@ -275,8 +279,7 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { if let Annotatable::Item(ref item) = *item { match item.node { ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) | - ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => { - + ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => { for ty in ty_params.iter() { typaram.push_str(&ty.ident.name.as_str()); } @@ -293,7 +296,8 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { fn call_intrinsic(cx: &ExtCtxt, span: Span, intrinsic: &str, - args: Vec>) -> P { + args: Vec>) + -> P { let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); @@ -301,6 +305,6 @@ fn call_intrinsic(cx: &ExtCtxt, stmts: vec![cx.stmt_expr(call)], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span: span })) + span: span, + })) } - From b40b7ef0c429b62d0907c0de930a93b262229b92 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 19 Jul 2016 20:01:54 +0000 Subject: [PATCH 056/331] 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 4656ba03e21c..32107026eedf 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 057/331] 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 52e19b37d793..c982e8ac6f83 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 058/331] 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 096e1ecc9ffb..6cb79d6e8630 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 ffc950d76dd2..b70e270df54d 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 f0a6f8edeec7..6fdc9b714d34 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 8866ffc2575c..a619da84b2d5 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 059/331] 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 518b94b5031b..4cc5b11dc343 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 060/331] 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 2d2bded9f606..b862a594ed21 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 061/331] 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 ef94aae78f41..c3a7d4023754 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 062/331] trans: Make base::internalize_symbols() respect explicit linkage directives. --- src/librustc_trans/base.rs | 74 +++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f9e1a4f16087..ea8c248d0239 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>) { - unsafe { - let mut declared = HashSet::new(); +fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>, + reachable: &FnvHashSet<&str>) { + let scx = ccxs.shared(); + let tcx = scx.tcx(); - // Collect all external declarations in all compilation units. - for ccx in cx.iter() { + // 'unsafe' because we are holding on to CStr's from the LLVM module within + // this block. + unsafe { + let mut referenced_somewhere = FnvHashSet(); + + // 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 063/331] 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 | 476 +++++++++++++++++++++++++++++---------- src/bootstrap/Cargo.lock | 11 +- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/native.rs | 459 +++++++++++++++++++++++++++++++------ src/bootstrap/step.rs | 4 +- src/bootstrap/util.rs | 5 +- 6 files changed, 749 insertions(+), 208 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index 8113b6838074..067721fab4fa 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))) - -# 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))) -endif - -ifeq ($$(findstring windows-gnu,$(1)),windows-gnu) -COMPRT_DIR_$(1) := windows -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1)) -endif - -ifeq ($$(findstring darwin,$(1)),darwin) -COMPRT_DIR_$(1) := builtins -COMPRT_LIB_NAME_$(1) := clang_rt.builtins_$$(patsubst i686,i386,$$(COMPRT_ARCH_$(1)))_osx -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 -endif -COMPRT_DEFINES_$(1) := -DCOMPILER_RT_ENABLE_IOS=ON -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))) - -ifeq ($$(findstring android,$(1)),android) -ifeq ($$(findstring arm,$$(COMPRT_ARCH_$(1))),arm) -COMPRT_ARCH_$(1) := armhf -endif -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)) -endif -endif - - -ifeq ($$(findstring windows-gnu,$(1)),windows-gnu) -COMPRT_LIB_FILE_$(1) := lib$$(COMPRT_LIB_NAME_$(1)).a -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 -endif - -ifndef COMPRT_LIB_FILE_$(1) -COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1))) -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) := -else -COMPRT_BUILD_ARGS_$(1) := -ifndef COMPRT_BUILD_TARGET_$(1) -COMPRT_BUILD_TARGET_$(1) := $$(COMPRT_LIB_NAME_$(1)) -endif -COMPRT_BUILD_CC_$(1) := -DCMAKE_C_COMPILER=$$(call FIND_COMPILER,$$(CC_$(1))) \ - -DCMAKE_CXX_COMPILER=$$(call FIND_COMPILER,$$(CXX_$(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 ifeq ($$(findstring ios,$(1)),) -COMPRT_BUILD_CC_$(1) := $$(COMPRT_BUILD_CC_$(1)) \ - -DCMAKE_C_FLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error" +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 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 windows,$(1)),) +COMPRT_OBJS_$(1) += emutls.o +endif + +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 + +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 + +else + +ifeq ($$(findstring x86_64,$(1)),x86_64) +COMPRT_OBJS_$(1) += \ + x86_64/floatdidf.o \ + x86_64/floatdisf.o \ + x86_64/floatdixf.o +endif + +endif + +# 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 + +# 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 + +# 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 + +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 + +ifeq ($$(findstring msvc,$(1)),msvc) +$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -Zl -D__func__=__FUNCTION__ +else +$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -fno-builtin -fvisibility=hidden \ + -fomit-frame-pointer -ffreestanding +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 39c7a3750112..1290f2a404b2 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 cde4a825be1f..02746034cca6 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 83e9393fbaef..05ecbc0cadaa 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_llvm_config = build.llvm_config(&build.config.build); - let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt")); - cfg.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)) - } else { - panic!("can't get os from target: {}", target) - }; - let output = dst.join("build/lib").join(dir) - .join(staticlib(&libname, target)); + 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()); - if fs::metadata(&output).is_ok() { + t!(fs::create_dir_all(&build_dir)); + + let mut cfg = gcc::Config::new(); + cfg.cargo_metadata(false) + .out_dir(&build_dir) + .target(target) + .host(&build.config.build) + .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 { + // 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 82ae70d22ca0..1ce8c7312324 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 3ef7f8cab2d1..b5230132bcb6 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 064/331] 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 045c1f9feafc..fe508adb7138 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 065/331] 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 a784741c88cc..6f1b70acb60b 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 066/331] 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 ed443147d466..201e4cae51d6 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 943271fc8a64..53a062574465 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 4b3be04b57c5..bd262cc7721e 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 5ccc96210be7..2d0b243558ff 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 515620d42538..577e0fd08601 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 000000000000..9144e9757f6a --- /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 000000000000..4409f16b3f5f --- /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 000000000000..dd6a85796043 --- /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 5ec62e06e37a..2a35fab9676a 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 6830f32bb2ce..cefcc11486fe 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 577da5c5af11..f2acfa517ced 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 067/331] 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 b9f5c6fcab90..f6ca90234c5b 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 518b94b5031b..f4855cce3b4a 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 be933abe41fe..39efc9fc22c3 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 cb99659cc0ea..01656b44a849 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 068/331] 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 b862a594ed21..6fe1b2a3b47d 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 069/331] 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 aa8c706ea1e2..88cd29a3ccfa 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 000000000000..8173f69191da --- /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 070/331] 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 d565532017a6..189695716deb 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 071/331] 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 7dfe19452a2a..c96be8fec2b0 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 072/331] 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 d6fb1816b5fa..6a1d94a2e44d 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 073/331] 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 a9ea52c42786..6195ac5eadfc 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 074/331] 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 ff75149f518a..a825cf866a87 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 075/331] 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 f6ca90234c5b..b9f5c6fcab90 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 f4855cce3b4a..f3d31ceea134 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 39efc9fc22c3..e2a57bd8d386 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 01656b44a849..7a6bd958a5f8 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 076/331] 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 a3c707e82a0f..4643686786be 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 2f265b9112b9..7297c71a6d66 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 077/331] 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 2ea2978b2940..fc5625036ae4 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 078/331] 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 96ecad629f54..a0fa188c4f80 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 fc5625036ae4..dc262e61dd01 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 1e2920ca87ea..16a54c20925d 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 e90b32cd5dfc..aae6e3ad36df 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 eeebd6a7f626..c1f415b3c028 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 5a3268e9e447..8a53c59b4c7f 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 d101381e2565..2d44a85f9af4 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 8769bc1a32b5..683328f4eb4a 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 84452589dfda..3b2d02dc861c 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 ef91188c5d16..1bc0a4f96521 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 526aa83dec7f..2c4c25630218 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 f14a3505cdeb..e997cf47c733 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 079/331] refactor type error reporting --- src/librustc/infer/error_reporting.rs | 233 +++++++------------- 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, 140 insertions(+), 202 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index a0fa188c4f80..be73818c8a4e 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" - } - }; + 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*. - 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)); - } + 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 dc262e61dd01..fd65e06ea972 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 76dca1bb5b64..52420475db10 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 2c7e7d284fa1..9c6727ebbfcf 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 22ac8bc56907..7a4cc09a7d50 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 f20dcdc35aea..346449d0a513 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 fc1d2236f3fe..7076b6a2a900 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 8604dadf46df..d02f87d0b9cd 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 080/331] 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 35a5bc9c6096..847dcc90ad39 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 4658d0f057d7..95508a31044b 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 43cf70e5bc3c..3d9d81471cb1 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 42e3456b309b..da48bbb3ecd7 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 b36918149fa9..db3334834d44 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 27d46be40fbe..ede81bea32ae 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 f86d9b7648bb..a05e007d6b73 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 51f876661f65..fb4652affd0d 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 081/331] 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 | 49 +++++++++++-------- 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, 76 insertions(+), 34 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 be73818c8a4e..0726d8560bab 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 span = trace.origin.span(); - - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false + 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 = origin.span(); let mut err = self.tcx.sess.struct_span_err_with_code( - trace.origin.span(), - message, - code); + span, message, code); - if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); + let mut is_simple_error = false; + + 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); + } } - 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 52420475db10..190c9b665e0d 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 3b9ecb882585..afbe34f89bbf 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 847dcc90ad39..2c4c6279076d 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 8c66160e8a36..cb952f6534f0 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 000000000000..62d23a99cbad --- /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 082/331] 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 | 44 +-- src/librustc_const_eval/eval.rs | 256 +++++++++++++----- 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 01872bbe3c04..8967672548b1 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 0de00d9d7f63..915a0cf0bdc7 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 f2abdf831a3b..45414c33c075 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -551,6 +551,26 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, +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 +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 +"##, + + 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: @@ -566,29 +586,11 @@ Working example: let x = [0i32; 2]; ``` "##, - -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: - -```compile_fail - let len = 10; - let x = [0i32; len]; // error: expected constant integer for repeat count, - // found variable -``` - -Working example: - -``` -let x = [0i32; 10]; -``` -"##, - } 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 a3c707e82a0f..03d2f596e216 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(), + 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 => "nonexistent struct field".into_cow(), - NonConstPath => "non-constant path in constant expression".into_cow(), + 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 726ba4fc1924..a6714c178e7c 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 27ce03b2d939..b0ba38f1db67 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 918e17d21ea9..a616b95ef720 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 08e894ffbcfd..f7fd970f37f2 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 00feb2cd1de0..f662ba75cc6f 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 a721361fce0e..bc5f3a0f22e2 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 da72793abf6d..1f3b13203163 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 8b8e658533ed..fc95d208f32c 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 f5b9bef5313f..92a2d3787bfd 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 9ff30f9ede26..b642a7122194 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 7076b6a2a900..c01edc568afd 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 41e7a467fa33..57602b55cc96 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 683328f4eb4a..38bf869119c6 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 4def60e485f7..0b2287cf233d 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 e65230389f9c..501c66e75cde 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 69d84e24c498..d3b43e83bfe5 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 5d8007defc90..0239986f5ad3 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 2f687350f34e..c3fa39659b96 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 faabed4fd5e4..b980bc02c85a 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 1143d3bd5cd9..7e2eabf412d6 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 a1d3888e78ea..f2079800cad3 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 07e27a7dc9a9..4749457da881 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 c90ae045f96b..c78c74e9e231 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 31e1a72967f4..e7639a4ff70a 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 3dfcb5bb29a2..c1c693544fa9 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 9fdd24c42fdb..73351429b506 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 45a00de48e71..dd0f058f2c95 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 09822e46cc1a..4f92770df289 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 0d6cf3bab453..5dadd892f835 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 9c6b774b9903..43375ee3d189 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 d51f31087d0d..e338f206553b 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 4567cd4a74bb..d68d63683a79 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 d63b0097e5a0..b1b4bfe2d1c3 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 9d3c432d1487..6f095b3041ff 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 23106c99594a..5af889cb2399 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 d6ba09bb4c5b..bbdb3891d998 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 7ca274b81e57..57db583aefe2 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 05b194345d40..89ae1a09bd3e 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 3c4ad5a56ec3..9a9358b787f5 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 7d619c270d32..54a240893546 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 32cdd6b5ed9f..c2bcbb9d54a9 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 e8a9c8d2ea34..93f75e9bfed0 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 bdcbaf09177f..ee6ec5276126 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 3b3abc94a490..ca8d5a1f7047 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 c8a1e424da2e..1dfd146985ff 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 52375ef281ac..1b6e4b1d289e 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 1c98abce0304..6352f4f6a044 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 9564a080b8ee..cadfec5a38d3 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 3ce206ff7fb2..a6f88a57b912 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 ee88168515d3..737f80372deb 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 ab5af64d95c1..d68df9736416 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 083/331] 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 fa9bc7c83680..5901c42b5258 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 084/331] 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 | 83 ++++++++++++++----- .../higher-ranked-projection.rs | 38 +++++++++ src/test/compile-fail/issue-31173.rs | 3 +- 3 files changed, 101 insertions(+), 23 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 afbe34f89bbf..33ca1d05cad7 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, - 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(); - } + 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, + 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 000000000000..12341fa8db38 --- /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 62d23a99cbad..fb1e3cc87e88 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 085/331] 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 9e4428ec57d5..9c3792afa2f1 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 086/331] 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 60d7e01d9881..a4aa434d6c47 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 087/331] 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 60d7e01d9881..d4b09807e749 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 088/331] 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 9e3f7a4a84a8..27fdbd383017 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 089/331] 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 7445ff94eb50..1ea0f8d70a8e 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 090/331] 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 6a48f65714cc..610e5647d6d1 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 091/331] 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 0726d8560bab..511cc32d2e1e 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 190c9b665e0d..76dca1bb5b64 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 33ca1d05cad7..67ad887530eb 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 2c4c6279076d..9844377d0bd3 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 092/331] 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 fd65e06ea972..1df06e8a0073 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 c01edc568afd..6062bd048b3d 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 38bf869119c6..6000ea71bff8 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 093/331] 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 6000ea71bff8..e7efed905ad7 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 094/331] 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 e7efed905ad7..500f624ea3f7 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 095/331] 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 000000000000..e83939e7aec6 --- /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 8ffc04b0325b0efc749121d03f92538daef37a11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 Jul 2016 16:52:11 -0400 Subject: [PATCH 096/331] Avoid writing a temporary closure kind We used to write a temporary closure kind into the inference table, but this could lead to obligations being incorrectled resolved before inference had completed. This result could then be cached, leading to further trouble. This patch avoids writing any closure kind until the computation is complete. Fixes #34349. --- src/librustc/infer/mod.rs | 16 +++++ src/librustc/middle/mem_categorization.rs | 22 ++++-- src/librustc_typeck/check/upvar.rs | 85 +++++++++++------------ src/test/compile-fail/issue-34349.rs | 32 +++++++++ 4 files changed, 105 insertions(+), 50 deletions(-) create mode 100644 src/test/compile-fail/issue-34349.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2ea2978b2940..dfca7b924b12 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -175,6 +175,12 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // any obligations set during the current snapshot. In that case, the // snapshot can't be rolled back. pub obligations_in_snapshot: Cell, + + // This is false except during closure kind inference. It is used + // by the mem-categorization code to be able to have stricter + // assertions (which are always true except during upvar + // inference). + during_closure_kind_inference: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -491,6 +497,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), obligations_in_snapshot: Cell::new(false), + during_closure_kind_inference: Cell::new(false), } } } @@ -532,6 +539,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), obligations_in_snapshot: Cell::new(false), + during_closure_kind_inference: Cell::new(false), })) } } @@ -1294,6 +1302,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|method| resolve_ty(method.ty))) } + pub fn set_during_closure_kind_inference(&self, value: bool) { + self.during_closure_kind_inference.set(value); + } + + pub fn during_closure_kind_inference(&self) -> bool { + self.during_closure_kind_inference.get() + } + /// True if errors have been reported since this infcx was /// created. This is sometimes used as a heuristic to skip /// reporting errors that often occur as a result of earlier diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 28bfb460a14f..e4308aabf5f7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -362,7 +362,9 @@ impl MutabilityCategory { impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> MemCategorizationContext<'a, 'gcx, 'tcx> { - MemCategorizationContext { infcx: infcx } + MemCategorizationContext { + infcx: infcx, + } } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { @@ -584,10 +586,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_upvar(id, span, var_id, fn_node_id, kind) } None => { - span_bug!( - span, - "No closure kind for {:?}", - closure_id); + if !self.infcx.during_closure_kind_inference() { + span_bug!( + span, + "No closure kind for {:?}", + closure_id); + } + + // during closure kind inference, we + // don't know the closure kind yet, but + // it's ok because we detect that we are + // accessing an upvar and handle that + // case specially anyhow. Use Fn + // arbitrarily. + self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn) } } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 702dd5f8de58..c1ffc668bc26 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -47,11 +47,11 @@ use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use rustc::ty::{self, Ty}; use rustc::infer::UpvarRegion; -use std::collections::HashSet; use syntax::ast; use syntax_pos::Span; use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; +use rustc::util::nodemap::NodeMap; /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS @@ -60,9 +60,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze_fn(&self, body: &hir::Block) { let mut seed = SeedBorrowKind::new(self); seed.visit_block(body); - let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); + let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); adjust.visit_block(body); // it's our job to process these. @@ -72,9 +71,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze_const(&self, body: &hir::Expr) { let mut seed = SeedBorrowKind::new(self); seed.visit_expr(body); - let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); + let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); adjust.visit_expr(body); // it's our job to process these. @@ -87,7 +85,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - closures_with_inferred_kinds: HashSet, + temp_closure_kinds: NodeMap, } impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> { @@ -106,7 +104,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> { - SeedBorrowKind { fcx: fcx, closures_with_inferred_kinds: HashSet::new() } + SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() } } fn check_closure(&mut self, @@ -116,11 +114,8 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { { let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id); if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) { - self.closures_with_inferred_kinds.insert(expr.id); - self.fcx.tables.borrow_mut().closure_kinds - .insert(closure_def_id, ty::ClosureKind::Fn); - debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds", - closure_def_id); + self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn); + debug!("check_closure: adding closure {:?} as Fn", expr.id); } self.fcx.tcx.with_freevars(expr.id, |freevars| { @@ -154,14 +149,14 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - closures_with_inferred_kinds: &'a HashSet, + temp_closure_kinds: NodeMap, } impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - closures_with_inferred_kinds: &'a HashSet) + temp_closure_kinds: NodeMap) -> AdjustBorrowKind<'a, 'gcx, 'tcx> { - AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds } + AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } } fn analyze_closure(&mut self, @@ -176,8 +171,10 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id); { + self.fcx.set_during_closure_kind_inference(true); let mut euv = euv::ExprUseVisitor::new(self, self.fcx); euv.walk_fn(decl, body); + self.fcx.set_during_closure_kind_inference(false); } // Now that we've analyzed the closure, we know how each @@ -211,10 +208,14 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); } - // Now we must process and remove any deferred resolutions, - // since we have a concrete closure kind. + // If we are also inferred the closure kind here, update the + // main table and process any deferred resolutions. let closure_def_id = self.fcx.tcx.map.local_def_id(id); - if self.closures_with_inferred_kinds.contains(&id) { + if let Some(&kind) = self.temp_closure_kinds.get(&id) { + self.fcx.tables.borrow_mut().closure_kinds + .insert(closure_def_id, kind); + debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); + let mut deferred_call_resolutions = self.fcx.remove_deferred_call_resolutions(closure_def_id); for deferred_call_resolution in &mut deferred_call_resolutions { @@ -259,7 +260,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { }) } - fn adjust_upvar_borrow_kind_for_consume(&self, + fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { @@ -350,7 +351,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); @@ -381,7 +382,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - fn try_adjust_upvar_deref(&self, + fn try_adjust_upvar_deref(&mut self, note: &mc::Note, borrow_kind: ty::BorrowKind) -> bool @@ -430,7 +431,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. - fn adjust_upvar_borrow_kind(&self, + fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, upvar_capture: &mut ty::UpvarCapture, kind: ty::BorrowKind) { @@ -460,36 +461,30 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - fn adjust_closure_kind(&self, + fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, new_kind: ty::ClosureKind) { debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", closure_id, new_kind); - if !self.closures_with_inferred_kinds.contains(&closure_id) { - return; - } + if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) { + debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", + closure_id, existing_kind, new_kind); - let closure_def_id = self.fcx.tcx.map.local_def_id(closure_id); - let closure_kinds = &mut self.fcx.tables.borrow_mut().closure_kinds; - let existing_kind = *closure_kinds.get(&closure_def_id).unwrap(); + match (existing_kind, new_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, _) => { + // no change needed + } - debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", - closure_id, existing_kind, new_kind); - - match (existing_kind, new_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, _) => { - // no change needed - } - - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // new kind is stronger than the old kind - closure_kinds.insert(closure_def_id, new_kind); + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // new kind is stronger than the old kind + self.temp_closure_kinds.insert(closure_id, new_kind); + } } } } diff --git a/src/test/compile-fail/issue-34349.rs b/src/test/compile-fail/issue-34349.rs new file mode 100644 index 000000000000..591753181db1 --- /dev/null +++ b/src/test/compile-fail/issue-34349.rs @@ -0,0 +1,32 @@ +// 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. + +// This is a regression test for a problem encountered around upvar +// inference and trait caching: in particular, we were entering a +// temporary closure kind during inference, and then caching results +// based on that temporary kind, which led to no error being reported +// in this particular test. + +fn main() { + let inc = || {}; + inc(); + + fn apply(f: F) where F: Fn() { + f() + } + + let mut farewell = "goodbye".to_owned(); + let diary = || { //~ ERROR E0525 + farewell.push_str("!!!"); + println!("Then I screamed {}.", farewell); + }; + + apply(diary); +} From 717e39294f635d90f8ba9e0968494f741878f37b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Jul 2016 23:52:53 +0300 Subject: [PATCH 097/331] 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 1df06e8a0073..87882c5528ec 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 03d2f596e216..2eb08cab1aa9 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 c1f415b3c028..1f3a83ebc1d5 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 2d44a85f9af4..907cb734c2ff 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 e7639a4ff70a..9e7a5ecae105 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 5af889cb2399..c73b7e831b32 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 b5432fafb1b8..f8aa1ea95f0f 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 6b9294b2038f..664d62e87ae6 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 1bc0a4f96521..ef91188c5d16 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 6352f4f6a044..91a07dd9ba6d 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 d68df9736416..3a7e9cc4191e 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 e997cf47c733..a98b7cd43090 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 098/331] 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 | 105 ++++++++++++------- src/libpanic_unwind/gcc.rs | 169 ++++++++++++++----------------- 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, 177 insertions(+), 139 deletions(-) diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 0ad6a74d1013..32fdf5c20480 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; + let ip = context.ip; - 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 !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 3c46072e17e1..cdf772ad3b82 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. + #[cfg(target_arch = "x86")] + const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX + + #[cfg(target_arch = "x86_64")] + const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX + + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 + + #[cfg(any(target_arch = "mips", target_arch = "mipsel"))] + const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 + + #[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] - 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) } - } + #[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); - #[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! + 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 { - // cleanup phase - unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) } + 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, + } } } -} - -// iOS on armv7 is using SjLj exceptions and therefore requires to use -// a specialized personality routine: __gcc_personality_sj0 - -#[cfg(all(target_os = "ios", target_arch = "arm"))] -pub mod eabi { - use unwind as uw; - use libc::c_int; - - 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; - } - - #[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) } - } + #[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 b765ee6f81cf..11dd9befe0a8 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 56801e8cb6bc..7dc428871b38 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 a721361fce0e..f033b278fe7f 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 aadfe202afe7..d9b6c9ed74dd 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 099/331] 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 000000000000..3566d143529b --- /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 07428f3f8b2d..4d85c9d545e5 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 0e7f04c77582..0d39217bd726 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 000000000000..1d8f95cd4b81 --- /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 0ad1f671f155..bf0c3ae987a2 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 c8906fed3d2f..e01f83ed70ab 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 100/331] 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 bf0c3ae987a2..fabb3900ec64 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 101/331] 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 ed56519d2362..8b5536de12e4 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 102/331] 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 e762e4d8ce9a..64b780413f88 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 103/331] 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 c28f70b8692a..c74e508a69b3 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 bb90a977433e..d1f26fec249a 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 104/331] 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 3e889f51f542..0259db221b6b 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 105/331] 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 2d77b38879b8..967baccd2740 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 106/331] 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 2c54dc13c8d0..1f8eea56fc69 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 107/331] 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 7c0d10669f30..29a300b172e7 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 0ad09fd0f7df..d38edf816880 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 108/331] 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 a03249e00635..97af99030c8f 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 1afb17ed5f9206e1e04c5d72ea724c5fadadd46c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 24 Jul 2016 04:48:26 +0000 Subject: [PATCH 109/331] Fix build of compiler-rt on FreeBSD Broken since ee6011fc71e02485f2dffcc25be64631c2008775 removed cmake from the process. There are likely other platforms still broken, but I didn't test on them. --- mk/rt.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mk/rt.mk b/mk/rt.mk index 067721fab4fa..e86aec60893e 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -384,7 +384,11 @@ COMPRT_OBJS_$(1) += emutls.o endif ifeq ($$(findstring msvc,$(1)),) + +ifeq ($$(findstring freebsd,$(1)),) COMPRT_OBJS_$(1) += gcc_personality_v0.o +endif + COMPRT_OBJS_$(1) += emutls.o ifeq ($$(findstring x86_64,$(1)),x86_64) From 6cef93d400b183d70c6c37856b46bb36d7bd8e16 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sat, 23 Jul 2016 17:25:25 -0700 Subject: [PATCH 110/331] Implement ARM personality routine in Rust. Remove the `eh_personality_catch` lang item. Use a simplified version of `cfg_if!` in libunwind. --- src/libpanic_unwind/gcc.rs | 291 ++++++++++++++++----------- src/libpanic_unwind/seh64_gnu.rs | 1 + src/librustc/middle/lang_items.rs | 1 - src/librustc_trans/intrinsic.rs | 19 +- src/libunwind/libunwind.rs | 322 ++++++++++++++++-------------- 5 files changed, 339 insertions(+), 295 deletions(-) diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index cdf772ad3b82..fdae8f69a9c0 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -61,6 +61,8 @@ use core::ptr; use alloc::boxed::Box; use unwind as uw; +use libc::{c_int, uintptr_t}; +use dwarf::eh::{self, EHContext, EHAction}; #[repr(C)] struct Exception { @@ -106,139 +108,184 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { 0x4d4f5a_00_52555354 } -// 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 + +// 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. + +#[cfg(target_arch = "x86")] +const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX + +#[cfg(target_arch = "x86_64")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 + +#[cfg(any(target_arch = "mips", target_arch = "mipsel"))] +const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 + +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 + +// The following code is 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 + +// The personality routine for most of our targets, except ARM, which has a slightly different ABI +// (however, iOS goes here as it uses SjLj unwinding). Also, the 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, uintptr_t}; - use dwarf::eh::{EHContext, EHAction, find_eh_action}; - - // 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. - - #[cfg(target_arch = "x86")] - const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX - - #[cfg(target_arch = "x86_64")] - const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX - - #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] - const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 - - #[cfg(any(target_arch = "mips", target_arch = "mipsel"))] - const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 - - #[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] - #[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, - } - } +#[lang = "eh_personality"] +#[no_mangle] +#[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; } - - #[cfg(stage0)] - #[lang = "eh_personality_catch"] - #[no_mangle] - 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) + let eh_action = find_eh_action(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, + } } } -// ARM EHABI uses a slightly different personality routine signature, -// but otherwise works the same. +// ARM EHABI personality routine. +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf #[cfg(all(target_arch = "arm", not(target_os = "ios")))] -pub mod eabi { - use unwind as uw; - use libc::c_int; - - extern "C" { - fn __gcc_personality_v0(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; - } - - #[lang = "eh_personality"] - #[no_mangle] - extern "C" fn rust_eh_personality(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { __gcc_personality_v0(state, ue_header, context) } - } - - #[lang = "eh_personality_catch"] - #[no_mangle] - pub extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { +#[lang = "eh_personality"] +#[no_mangle] +unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + let state = state as c_int; + let action = state & uw::_US_ACTION_MASK as c_int; + let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // Backtraces on ARM will call the personality routine with // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases // we want to continue unwinding the stack, otherwise all our backtraces - // would end at __rust_try. - if (state as c_int & uw::_US_ACTION_MASK as c_int) == - uw::_US_VIRTUAL_UNWIND_FRAME as c_int && - (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { - // search phase - uw::_URC_HANDLER_FOUND // catch! - } else { - // cleanup phase - unsafe { __gcc_personality_v0(state, ue_header, context) } + // would end at __rust_try + if state & uw::_US_FORCE_UNWIND as c_int != 0 { + return continue_unwind(exception_object, context) + } + true + } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int { + false + } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int { + return continue_unwind(exception_object, context); + } else { + return uw::_URC_FAILURE; + }; + + // The DWARF unwinder assumes that _Unwind_Context holds things like the function + // and LSDA pointers, however ARM EHABI places them into the exception object. + // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which + // take only the context pointer, GCC personality routines stash a pointer to exception_object + // in the context, using location reserved for ARM's "scratch register" (r12). + uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr); + // ...A more principled approach would be to provide the full definition of ARM's + // _Unwind_Context in our libunwind bindings and fetch the required data from there directly, + // bypassing DWARF compatibility functions. + + let eh_action = find_eh_action(context); + if search_phase { + match eh_action { + EHAction::None | + EHAction::Cleanup(_) => return continue_unwind(exception_object, context), + EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, + EHAction::Terminate => return uw::_URC_FAILURE, + } + } else { + match eh_action { + EHAction::None => return continue_unwind(exception_object, context), + 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_FAILURE, } } + + // On ARM EHABI the personality routine is responsible for actually + // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). + unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON { + uw::_URC_CONTINUE_UNWIND + } else { + uw::_URC_FAILURE + } + } + // defined in libgcc + extern "C" { + fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; + } +} + +unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction { + 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), + }; + eh::find_eh_action(lsda, &eh_context) +} + +// *** Delete after a new snapshot *** +#[cfg(all(stage0, any(target_os = "ios", not(target_arch = "arm"))))] +#[lang = "eh_personality_catch"] +#[no_mangle] +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) +} + +// *** Delete after a new snapshot *** +#[cfg(all(stage0, target_arch = "arm", not(target_os = "ios")))] +#[lang = "eh_personality_catch"] +#[no_mangle] +pub unsafe extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State, + ue_header: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + rust_eh_personality(state, ue_header, context) } // See docs in the `unwind` module. diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 7dc428871b38..3642e2488958 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -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. +// *** Delete after a new snapshot *** #[cfg(stage0)] #[lang = "eh_personality_catch"] #[cfg(not(test))] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 960305e10488..a209b1d1abd7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -359,7 +359,6 @@ language_item_table! { StartFnLangItem, "start", start_fn; EhPersonalityLangItem, "eh_personality", eh_personality; - EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch; EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume; MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter; diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index f033b278fe7f..3ec79cf107a3 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -19,7 +19,6 @@ use rustc::ty::subst; use rustc::ty::subst::FnSpace; use abi::{Abi, FnType}; use adt; -use attributes; use base::*; use build::*; use callee::{self, Callee}; @@ -37,7 +36,6 @@ use machine; use type_::Type; use rustc::ty::{self, Ty}; use Disr; -use rustc::ty::subst::Substs; use rustc::hir; use syntax::ast; use syntax::ptr::P; @@ -1172,7 +1170,6 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dloc: DebugLoc) -> Block<'blk, 'tcx> { let llfn = get_rust_try_fn(bcx.fcx, &mut |bcx| { let ccx = bcx.ccx(); - let tcx = ccx.tcx(); let dloc = DebugLoc::None; // Translates the shims described above: @@ -1192,20 +1189,6 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // expected to be `*mut *mut u8` for this to actually work, but that's // managed by the standard library. - attributes::emit_uwtable(bcx.fcx.llfn, true); - 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"), - } - } else { - bcx.fcx.eh_personality() - }; - let then = bcx.fcx.new_temp_block("then"); let catch = bcx.fcx.new_temp_block("catch"); @@ -1223,7 +1206,7 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // rust_try ignores the selector. let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); - let vals = LandingPad(catch, lpad_ty, catch_pers, 1); + let vals = LandingPad(catch, lpad_ty, bcx.fcx.eh_personality(), 1); AddClause(catch, vals, C_null(Type::i8p(ccx))); let ptr = ExtractValue(catch, vals, 0); Store(catch, ptr, BitCast(catch, local_ptr, Type::i8p(ccx).ptr_to())); diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index d9b6c9ed74dd..5e242db0a888 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -10,38 +10,15 @@ #![allow(bad_style)] -use libc; - -#[cfg(any(not(target_arch = "arm"), target_os = "ios"))] -pub use self::_Unwind_Action::*; -#[cfg(target_arch = "arm")] -pub use self::_Unwind_State::*; -pub use self::_Unwind_Reason_Code::*; - -#[cfg(any(not(target_arch = "arm"), target_os = "ios"))] -#[repr(C)] -#[derive(Clone, Copy)] -pub enum _Unwind_Action { - _UA_SEARCH_PHASE = 1, - _UA_CLEANUP_PHASE = 2, - _UA_HANDLER_FRAME = 4, - _UA_FORCE_UNWIND = 8, - _UA_END_OF_STACK = 16, +macro_rules! cfg_if { + ( $( if #[cfg( $meta:meta )] { $($it1:item)* } else { $($it2:item)* } )* ) => + ( $( $( #[cfg($meta)] $it1)* $( #[cfg(not($meta))] $it2)* )* ) } -#[cfg(target_arch = "arm")] -#[repr(C)] -#[derive(Clone, Copy)] -pub enum _Unwind_State { - _US_VIRTUAL_UNWIND_FRAME = 0, - _US_UNWIND_FRAME_STARTING = 1, - _US_UNWIND_FRAME_RESUME = 2, - _US_ACTION_MASK = 3, - _US_FORCE_UNWIND = 8, - _US_END_OF_STACK = 16, -} +use libc::{c_int, c_void, uintptr_t}; #[repr(C)] +#[derive(Copy, Clone, PartialEq)] pub enum _Unwind_Reason_Code { _URC_NO_REASON = 0, _URC_FOREIGN_EXCEPTION_CAUGHT = 1, @@ -52,17 +29,15 @@ pub enum _Unwind_Reason_Code { _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EABI + _URC_FAILURE = 9, // used only by ARM EHABI } +pub use self::_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) +pub type _Unwind_Word = uintptr_t; +pub type _Unwind_Ptr = uintptr_t; +pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code; - #[cfg(target_arch = "x86")] pub const unwinder_private_data_size: usize = 5; @@ -99,6 +74,164 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); +extern "C" { + #[unwind] + pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; + pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); + pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; + 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; +} + +cfg_if! { +if #[cfg(not(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm"))))] { + // Not ARM EHABI + #[repr(C)] + #[derive(Copy, Clone, PartialEq)] + pub enum _Unwind_Action { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16, + } + pub use self::_Unwind_Action::*; + + extern "C" { + pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word; + pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word); + pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word; + pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word); + pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) + -> _Unwind_Word; + pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; + } + +} else { + // ARM EHABI + #[repr(C)] + #[derive(Copy, Clone, PartialEq)] + pub enum _Unwind_State { + _US_VIRTUAL_UNWIND_FRAME = 0, + _US_UNWIND_FRAME_STARTING = 1, + _US_UNWIND_FRAME_RESUME = 2, + _US_ACTION_MASK = 3, + _US_FORCE_UNWIND = 8, + _US_END_OF_STACK = 16, + } + pub use self::_Unwind_State::*; + + #[repr(C)] + enum _Unwind_VRS_Result { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + use self::_Unwind_VRS_RegClass::*; + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + use self::_Unwind_VRS_DataRepresentation::*; + + pub const UNWIND_POINTER_REG: c_int = 12; + pub const UNWIND_IP_REG: c_int = 15; + + extern "C" { + fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, + regclass: _Unwind_VRS_RegClass, + regno: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut c_void) + -> _Unwind_VRS_Result; + + fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context, + regclass: _Unwind_VRS_RegClass, + regno: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut c_void) + -> _Unwind_VRS_Result; + } + + // On Android or ARM/Linux, these are implemented as macros: + + pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { + let mut val: _Unwind_Word = 0; + _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, + &mut val as *mut _ as *mut c_void); + val + } + + pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { + let mut value = value; + _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, + &mut value as *mut _ as *mut c_void); + } + + pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) + -> _Unwind_Word { + let val = _Unwind_GetGR(ctx, UNWIND_IP_REG); + (val & !1) as _Unwind_Word + } + + pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, + value: _Unwind_Word) { + // Propagate thumb bit to instruction pointer + let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1; + let value = value | thumb_state; + _Unwind_SetGR(ctx, UNWIND_IP_REG, value); + } + + pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int) + -> _Unwind_Word { + *ip_before_insn = 0; + _Unwind_GetIP(ctx) + } + + // This function also doesn't exist on Android or ARM/Linux, so make it a no-op + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void { + pc + } +} + +if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { + // Not 32-bit iOS + extern "C" { + #[unwind] + pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *mut c_void) + -> _Unwind_Reason_Code; + } +} else { + // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() + extern "C" { + #[unwind] + pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; + } + + #[inline] + pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code { + _Unwind_SjLj_RaiseException(exc) + } +} +} // cfg_if! #[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", @@ -127,122 +260,3 @@ pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reaso link(name = "gcc_eh"))] #[cfg(not(cargobuild))] extern "C" {} - -extern "C" { - // iOS on armv7 uses SjLj exceptions and requires to link - // against corresponding routine (..._SjLj_...) - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - #[unwind] - pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - - #[cfg(all(target_os = "ios", target_arch = "arm"))] - #[unwind] - fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - - pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); - - #[unwind] - pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; - - // No native _Unwind_Backtrace on iOS - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *mut libc::c_void) - -> _Unwind_Reason_Code; - - // available since GCC 4.2.0, should be fine for our purpose - #[cfg(all(not(all(target_os = "android", target_arch = "arm")), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, - 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; -} - -// ... and now we just providing access to SjLj counterspart -// through a standard name to hide those details from others -// (see also comment above regarding _Unwind_RaiseException) -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[inline] -pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code { - _Unwind_SjLj_RaiseException(exc) -} - -// On android, the function _Unwind_GetIP is a macro, and this is the -// expansion of the macro. This is all copy/pasted directly from the -// header file with the definition of _Unwind_GetIP. -#[cfg(any(all(target_os = "android", target_arch = "arm"), - all(target_os = "linux", target_arch = "arm")))] -pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { - #[repr(C)] - enum _Unwind_VRS_Result { - _UVRSR_OK = 0, - _UVRSR_NOT_IMPLEMENTED = 1, - _UVRSR_FAILED = 2, - } - #[repr(C)] - enum _Unwind_VRS_RegClass { - _UVRSC_CORE = 0, - _UVRSC_VFP = 1, - _UVRSC_FPA = 2, - _UVRSC_WMMXD = 3, - _UVRSC_WMMXC = 4, - } - #[repr(C)] - enum _Unwind_VRS_DataRepresentation { - _UVRSD_UINT32 = 0, - _UVRSD_VFPX = 1, - _UVRSD_FPAX = 2, - _UVRSD_UINT64 = 3, - _UVRSD_FLOAT = 4, - _UVRSD_DOUBLE = 5, - } - - type _Unwind_Word = libc::c_uint; - extern "C" { - fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, - klass: _Unwind_VRS_RegClass, - word: _Unwind_Word, - repr: _Unwind_VRS_DataRepresentation, - data: *mut libc::c_void) - -> _Unwind_VRS_Result; - } - - let mut val: _Unwind_Word = 0; - let ptr = &mut val as *mut _Unwind_Word; - let _ = _Unwind_VRS_Get(ctx, - _Unwind_VRS_RegClass::_UVRSC_CORE, - 15, - _Unwind_VRS_DataRepresentation::_UVRSD_UINT32, - ptr as *mut libc::c_void); - (val & !1) as libc::uintptr_t -} - -// This function doesn't exist on Android or ARM/Linux, so make it same -// to _Unwind_GetIP -#[cfg(any(all(target_os = "android", target_arch = "arm"), - all(target_os = "linux", target_arch = "arm")))] -pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, - ip_before_insn: *mut libc::c_int) - -> libc::uintptr_t { - *ip_before_insn = 0; - _Unwind_GetIP(ctx) -} - -// This function also doesn't exist on Android or ARM/Linux, so make it -// a no-op -#[cfg(any(target_os = "android", - all(target_os = "linux", target_arch = "arm")))] -pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void { - pc -} From dad29a6d03429874ddf5ce6f53045bae2e0d6fac Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 16:07:06 +0200 Subject: [PATCH 111/331] 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 c28f70b8692a..d1453b05a791 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 112/331] 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 d1453b05a791..6547cb6acbe4 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 bb90a977433e..17c093e6cac6 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 113/331] 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 c28f70b8692a..4d4d44bae309 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 8604c5494eed8d111757f23a874d9ce8ca673e2c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 24 Jul 2016 18:03:01 +0000 Subject: [PATCH 114/331] Follow-up to 1afb17ed5f9206e1e04c5d72ea724c5fadadd46c Disable gcc_personality_v0.c in rustbuild as well as the normal build. Rustbuild now gets further on FreeBSD, but it still fails due to other problems. --- src/bootstrap/native.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 05ecbc0cadaa..a78cef4f409b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -348,7 +348,9 @@ pub fn compiler_rt(build: &Build, target: &str) { ]); } } else { - sources.push("gcc_personality_v0.c"); + if !target.contains("freebsd") { + sources.push("gcc_personality_v0.c"); + } if target.contains("x86_64") { sources.extend(vec![ From 9aca38e56872ffcae9a8f64b83d6d074ab802d3c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 24 Jul 2016 15:49:26 -0400 Subject: [PATCH 115/331] 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 116/331] 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 cd00ebc2d0a6..c53f51d5bf58 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 117/331] 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 b5b6ca757270..000000000000 --- 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 118/331] 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 e7cc534c5b55..0fd95500422f 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 63eb4d9114b05695bca2639628019ca61bae7366 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 25 Jul 2016 10:18:16 -0400 Subject: [PATCH 119/331] move `during_closure_kind_inference` flag to mc We used to put the flag on the `InferCtxt`. --- src/librustc/infer/mod.rs | 16 ---------------- src/librustc/middle/expr_use_visitor.rs | 13 +++++++++++-- src/librustc/middle/mem_categorization.rs | 21 ++++++++++++++++++++- src/librustc_typeck/check/upvar.rs | 9 ++++++--- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index dfca7b924b12..2ea2978b2940 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -175,12 +175,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // any obligations set during the current snapshot. In that case, the // snapshot can't be rolled back. pub obligations_in_snapshot: Cell, - - // This is false except during closure kind inference. It is used - // by the mem-categorization code to be able to have stricter - // assertions (which are always true except during upvar - // inference). - during_closure_kind_inference: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -497,7 +491,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), obligations_in_snapshot: Cell::new(false), - during_closure_kind_inference: Cell::new(false), } } } @@ -539,7 +532,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), obligations_in_snapshot: Cell::new(false), - during_closure_kind_inference: Cell::new(false), })) } } @@ -1302,14 +1294,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|method| resolve_ty(method.ty))) } - pub fn set_during_closure_kind_inference(&self, value: bool) { - self.during_closure_kind_inference.set(value); - } - - pub fn during_closure_kind_inference(&self) -> bool { - self.during_closure_kind_inference.get() - } - /// True if errors have been reported since this infcx was /// created. This is sometimes used as a heuristic to skip /// reporting errors that often occur as a result of earlier diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 6551e0129f88..18b80a9636b4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -271,10 +271,19 @@ enum PassArgs { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) + -> Self + { + ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default()) + } + + pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + options: mc::MemCategorizationOptions) + -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::new(infcx), + mc: mc::MemCategorizationContext::with_options(infcx, options), delegate: delegate } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e4308aabf5f7..0bc3c1ae899d 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -259,6 +259,18 @@ impl ast_node for hir::Pat { #[derive(Copy, Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + options: MemCategorizationOptions, +} + +#[derive(Copy, Clone, Default)] +pub struct MemCategorizationOptions { + // If true, then when analyzing a closure upvar, if the closure + // has a missing kind, we treat it like a Fn closure. When false, + // we ICE if the closure has a missing kind. Should be false + // except during closure kind inference. It is used by the + // mem-categorization code to be able to have stricter assertions + // (which are always true except during upvar inference). + pub during_closure_kind_inference: bool, } pub type McResult = Result; @@ -362,8 +374,15 @@ impl MutabilityCategory { impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> MemCategorizationContext<'a, 'gcx, 'tcx> { + MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default()) + } + + pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + options: MemCategorizationOptions) + -> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { infcx: infcx, + options: options, } } @@ -586,7 +605,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_upvar(id, span, var_id, fn_node_id, kind) } None => { - if !self.infcx.during_closure_kind_inference() { + if !self.options.during_closure_kind_inference { span_bug!( span, "No closure kind for {:?}", diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index c1ffc668bc26..71490423f73f 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -171,10 +171,13 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id); { - self.fcx.set_during_closure_kind_inference(true); - let mut euv = euv::ExprUseVisitor::new(self, self.fcx); + let mut euv = + euv::ExprUseVisitor::with_options(self, + self.fcx, + mc::MemCategorizationOptions { + during_closure_kind_inference: true + }); euv.walk_fn(decl, body); - self.fcx.set_during_closure_kind_inference(false); } // Now that we've analyzed the closure, we know how each From 5fbcf08dd8cfc347c13d84c8ea20e3bfce6793fc Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sun, 24 Jul 2016 22:09:56 -0700 Subject: [PATCH 120/331] 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 32fdf5c20480..1e9e9e30f5cf 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 1f86005fc09eceb6b19507c466b9674013425521 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Mon, 25 Jul 2016 12:13:10 -0500 Subject: [PATCH 121/331] Use "x86-64" as the target CPU for NetBSD and Bitrig on amd64. Using "generic" disables a number of features that are present on all x86_64 cpus, the "x86-64" target cpu is the common denominator for that arch. Refs #20777 --- src/librustc_back/target/x86_64_rumprun_netbsd.rs | 1 + src/librustc_back/target/x86_64_unknown_bitrig.rs | 1 + src/librustc_back/target/x86_64_unknown_netbsd.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index af5d21c4d93e..a55aaf9699c8 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -12,6 +12,7 @@ use target::Target; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); + base.cpu = "x86-64".to_string(); base.pre_link_args.push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); base.ar = "x86_64-rumprun-netbsd-ar".to_string(); diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index 87753da540a3..2761782d46e7 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -12,6 +12,7 @@ use target::Target; pub fn target() -> Target { let mut base = super::bitrig_base::opts(); + base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index 7e6d1b78469e..6dc744cdf99d 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -12,6 +12,7 @@ use target::Target; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); + base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); From 5c0ce872fbbdb9364c970869a1ad7be486c29b37 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 25 Jul 2016 18:19:11 +0100 Subject: [PATCH 122/331] 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 2e2fc011ddbe..e4e886c85334 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 000000000000..b2104a0c80f5 --- /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 91ec69d9a3cb..d8dc115abf91 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 123/331] 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 2ea2978b2940..4e0c5b58b64d 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 124/331] 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 e34a3c4569d0..6da87fca3f35 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 125/331] 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 1f8eea56fc69..ccef6c02f9d2 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()); + /// ``` + /// + /// 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 v = [10, 40, 30, 20, 60, 50]; + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); /// - /// for group in v.split(|num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } + /// 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 126/331] 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 | 17 ++-- 14 files changed, 231 insertions(+), 170 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ce3d72de9ae9..0a1e7005f9fb 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 0a8df923b846..9df1dea45671 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 d38f979e33c5..0d327414c8fc 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 cbc246ac2a11..5d26bcd48a3b 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 18f9733040e0..a498004b390a 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 409cec282bce..63345a15e6a9 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 731425942359..91b1b82211a1 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 7dadf8d108a7..4be044c1df30 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 0211b2c9bc7b..8d69c55ecf12 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 67f73d4dd4f7..8bd3f5195ccd 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 435241f426ec..5d6429f7bdff 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 18342f2e38c1..5293d2ab0001 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 27485ee65fcc..5a718dd48e37 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 80e2a923e556..e09a64e73449 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; - } - }; + 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()) { + 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 127/331] 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 0a1e7005f9fb..27e1d0520dc9 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 9df1dea45671..07a2605026ab 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 0d327414c8fc..774c5ca6d6b2 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 a498004b390a..7547e28625c1 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 8d69c55ecf12..6883c22d6752 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 8bd3f5195ccd..b622f6861b38 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 c96be8fec2b0..b1ec7fd0ab89 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 128/331] 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 96b14a6c321c..610e25e0f8a8 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 c9235d063cba..36ea228956d4 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 408f22cf15c7..f3dc44e8efd0 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 b7085f0829f8..51386083ab3c 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 bd46f3a26a2d..bd87c91dea58 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 680dd0d63556..404763b3bd30 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 129/331] 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 610e25e0f8a8..d790391cd4c4 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 36ea228956d4..41369299e726 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, a_is_expected: bool) -> Equate<'infcx, 'gcx, 'tcx> { + Equate::new(self.clone(), a_is_expected) } - pub fn equate(&self) -> Equate<'infcx, 'gcx, 'tcx> { - Equate::new(self.clone()) + pub fn bivariate(&self, a_is_expected: bool) -> Bivariate<'infcx, 'gcx, 'tcx> { + Bivariate::new(self.clone(), a_is_expected) } - pub fn bivariate(&self) -> Bivariate<'infcx, 'gcx, 'tcx> { - Bivariate::new(self.clone()) + pub fn sub(&self, a_is_expected: bool) -> Sub<'infcx, 'gcx, 'tcx> { + Sub::new(self.clone(), a_is_expected) } - pub fn sub(&self) -> Sub<'infcx, 'gcx, 'tcx> { - Sub::new(self.clone()) + pub fn lub(&self, a_is_expected: bool) -> Lub<'infcx, 'gcx, 'tcx> { + Lub::new(self.clone(), a_is_expected) } - pub fn lub(&self) -> Lub<'infcx, 'gcx, 'tcx> { - Lub::new(self.clone()) - } - - 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 f3dc44e8efd0..7980ba91c5e0 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 51386083ab3c..7893846b2145 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 03a09917c534..386c1ba272f3 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 bd87c91dea58..6f3bd004f1fb 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 4e0c5b58b64d..9ee0da4d0edd 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 404763b3bd30..7a25ea9f3c2b 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 130/331] 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 d790391cd4c4..e54522b84336 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 41369299e726..fc5b52ee30a5 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 7980ba91c5e0..09800412e0bf 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 7893846b2145..46d5991b7adb 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 386c1ba272f3..743d6135fbb5 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 1a2bc4b5cf2e..eda78428e61a 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 6f3bd004f1fb..2639e06f2e5c 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 9ee0da4d0edd..58d2b963bbf1 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 7a25ea9f3c2b..a3e50a23d3f4 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 131/331] 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 e54522b84336..125f815feda6 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 fc5b52ee30a5..b4818f963b3b 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 09800412e0bf..e06f7303acb2 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 46d5991b7adb..5dd85a31a9a2 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 2639e06f2e5c..ad1b32ffaeb3 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 a3e50a23d3f4..2f7f5254727d 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 3873402805288fb032050ba15606f393736a993d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 28 Jun 2016 11:53:37 +0530 Subject: [PATCH 132/331] Clarify UnsafeCell docs; fix #34496 --- src/libcore/cell.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 65cb1aaaff6f..06af200e4783 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -847,6 +847,20 @@ impl<'b, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for RefM /// The `UnsafeCell` type is the only legal way to obtain aliasable data that is considered /// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior. /// +/// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or +/// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, +/// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way +/// to do this. When `UnsafeCell` is immutably aliased, it is still safe to obtain a mutable +/// reference to its interior and/or to mutate it. However, it is up to the abstraction designer +/// to ensure that no two mutable references obtained this way are active at the same time, and +/// that there are no active mutable references or mutations when an immutable reference is obtained +/// from the cell. This is often done via runtime checks. +/// +/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is +/// okay (provided you enforce the invariants some other way); it is still undefined behavior +/// to have multiple `&mut UnsafeCell` aliases. +/// +/// /// Types like `Cell` and `RefCell` use this type to wrap their internal data. /// /// # Examples @@ -916,6 +930,11 @@ impl UnsafeCell { impl UnsafeCell { /// Gets a mutable pointer to the wrapped value. /// + /// This can be cast to a pointer of any kind. + /// Ensure that the access is unique when casting to + /// `&mut T`, and ensure that there are no mutations or mutable + /// aliases going on when casting to `&T` + /// /// # Examples /// /// ``` From 47db8deff6b50512d1c6e702d4df6bd9027efe04 Mon Sep 17 00:00:00 2001 From: Rahiel Kasim Date: Tue, 26 Jul 2016 11:14:46 +0200 Subject: [PATCH 133/331] 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 b31a34a0425a..b1aee579aabc 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 134/331] 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 6956dc0d901a..01bc733d440e 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 21ce6b19ceb1..a8cb1ce49d2d 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 32ca32e76cb6..0cea7f81e363 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 000000000000..d22fa6494f03 --- /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 135/331] 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 f027d074cb6f..333219bc5e5b 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 55308a46f0ac..a63ea9d3ec77 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 4d85c9d545e5..870f8a3a1ec6 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 0d39217bd726..3e435b47110a 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 e5eb8f21382b..3bcdce57af0d 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 e01f83ed70ab..ec757b0b5d38 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 7445ff94eb50..683d5289ab53 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 f91a754ab57d..8c91d3b6a929 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 136/331] 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 c5312d0d9bbd..be0ef85d6b11 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 d464422c0a15b88a7f5791652ce1f881959fcc44 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 26 Jul 2016 15:21:25 -0500 Subject: [PATCH 137/331] rustbuild: make backtraces (RUST_BACKTRACE) optional but keep them enabled by default to maintain the status quo. When disabled shaves ~56KB off every x86_64-unknown-linux-gnu binary. To disable backtraces you have to use a config.toml (see src/bootstrap/config.toml.example for details) when building rustc/std: $ python bootstrap.py --config=config.toml --- src/bootstrap/config.rs | 4 ++++ src/bootstrap/config.toml.example | 3 +++ src/bootstrap/lib.rs | 3 +++ src/libstd/Cargo.toml | 1 + src/libstd/build.rs | 3 ++- src/libstd/panicking.rs | 16 ++++++++++++---- src/libstd/sys/common/mod.rs | 2 ++ src/libstd/sys/unix/mod.rs | 1 + src/rustc/std_shim/Cargo.toml | 1 + 9 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e64d7e5a437e..aafbf68d1b7b 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -72,6 +72,7 @@ pub struct Config { // libstd features pub debug_jemalloc: bool, pub use_jemalloc: bool, + pub backtrace: bool, // support for RUST_BACKTRACE // misc pub channel: String, @@ -134,6 +135,7 @@ struct Rust { debuginfo: Option, debug_jemalloc: Option, use_jemalloc: Option, + backtrace: Option, default_linker: Option, default_ar: Option, channel: Option, @@ -158,6 +160,7 @@ impl Config { let mut config = Config::default(); config.llvm_optimize = true; config.use_jemalloc = true; + config.backtrace = true; config.rust_optimize = true; config.rust_optimize_tests = true; config.submodules = true; @@ -230,6 +233,7 @@ impl Config { set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); + set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); config.rustc_default_linker = rust.default_linker.clone(); config.rustc_default_ar = rust.default_ar.clone(); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 6f0658423283..2894adafef62 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -99,6 +99,9 @@ # Whether or not jemalloc is built with its debug option set #debug-jemalloc = false +# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) +#backtrace = true + # The default linker that will be used by the generated compiler. Note that this # is not the linker used to link said compiler. #default-linker = "cc" diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 367322e88164..25356b86221c 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -652,6 +652,9 @@ impl Build { if self.config.use_jemalloc { features.push_str(" jemalloc"); } + if self.config.backtrace { + features.push_str(" backtrace"); + } return features } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index eded6e24f3ef..b442d21b72ba 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -27,5 +27,6 @@ build_helper = { path = "../build_helper" } gcc = "0.3" [features] +backtrace = [] jemalloc = ["alloc_jemalloc"] debug-jemalloc = ["alloc_jemalloc/debug"] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9c408366f8b4..9018e48d06bd 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -25,7 +25,8 @@ fn main() { let target = env::var("TARGET").unwrap(); let host = env::var("HOST").unwrap(); - if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){ + if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") && + !target.contains("emscripten") { build_libbacktrace(&host, &target); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index d73e9542d212..319fbdaac55d 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -28,8 +28,10 @@ use intrinsics; use mem; use raw; use sys_common::rwlock::RWLock; +#[cfg(feature = "backtrace")] use sync::atomic::{AtomicBool, Ordering}; use sys::stdio::Stderr; +#[cfg(feature = "backtrace")] use sys_common::backtrace; use sys_common::thread_info; use sys_common::util; @@ -71,6 +73,7 @@ enum Hook { static HOOK_LOCK: RWLock = RWLock::new(); static mut HOOK: Hook = Hook::Default; +#[cfg(feature = "backtrace")] static FIRST_PANIC: AtomicBool = AtomicBool::new(true); /// Registers a custom panic hook, replacing any that was previously registered. @@ -183,10 +186,12 @@ impl<'a> Location<'a> { } fn default_hook(info: &PanicInfo) { + #[cfg(feature = "backtrace")] let panics = PANIC_COUNT.with(|c| c.get()); // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. + #[cfg(feature = "backtrace")] let log_backtrace = panics >= 2 || backtrace::log_enabled(); let file = info.location.file; @@ -207,10 +212,13 @@ fn default_hook(info: &PanicInfo) { let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}", name, msg, file, line); - if log_backtrace { - let _ = backtrace::write(err); - } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { - let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace."); + #[cfg(feature = "backtrace")] + { + if log_backtrace { + let _ = backtrace::write(err); + } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { + let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace."); + } } }; diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index c9279883ae59..67b19682fc9a 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -28,6 +28,7 @@ macro_rules! rtassert { pub mod args; pub mod at_exit_imp; +#[cfg(feature = "backtrace")] pub mod backtrace; pub mod condvar; pub mod io; @@ -42,6 +43,7 @@ pub mod thread_local; pub mod util; pub mod wtf8; +#[cfg(feature = "backtrace")] #[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))), all(windows, target_env = "gnu")))] pub mod gnu; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index f0fd42fc99b8..9aac7be80176 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -30,6 +30,7 @@ use libc; pub mod weak; pub mod android; +#[cfg(feature = "backtrace")] pub mod backtrace; pub mod condvar; pub mod ext; diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 5602ef866b83..693cbe06ba98 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -46,3 +46,4 @@ std = { path = "../../libstd" } [features] jemalloc = ["std/jemalloc"] debug-jemalloc = ["std/debug-jemalloc"] +backtrace = ["std/backtrace"] From ec8518e4fbde1b578137883cc7c4fe6805723a3f Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Tue, 26 Jul 2016 18:53:47 -0700 Subject: [PATCH 138/331] 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 1e9e9e30f5cf..2284a9bbb73e 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 774fbdf40deb9b257dd6aa166096fed1eeac80c2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 26 Jul 2016 22:33:45 -0500 Subject: [PATCH 139/331] keep backtraces if using the old build system --- src/libstd/panicking.rs | 24 +++++++++++++----------- src/libstd/sys/common/mod.rs | 4 ++-- src/libstd/sys/unix/mod.rs | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 319fbdaac55d..57a4c3df70a4 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -28,11 +28,7 @@ use intrinsics; use mem; use raw; use sys_common::rwlock::RWLock; -#[cfg(feature = "backtrace")] -use sync::atomic::{AtomicBool, Ordering}; use sys::stdio::Stderr; -#[cfg(feature = "backtrace")] -use sys_common::backtrace; use sys_common::thread_info; use sys_common::util; use thread; @@ -73,8 +69,6 @@ enum Hook { static HOOK_LOCK: RWLock = RWLock::new(); static mut HOOK: Hook = Hook::Default; -#[cfg(feature = "backtrace")] -static FIRST_PANIC: AtomicBool = AtomicBool::new(true); /// Registers a custom panic hook, replacing any that was previously registered. /// @@ -186,13 +180,17 @@ impl<'a> Location<'a> { } fn default_hook(info: &PanicInfo) { - #[cfg(feature = "backtrace")] - let panics = PANIC_COUNT.with(|c| c.get()); + #[cfg(any(not(cargobuild), feature = "backtrace"))] + use sys_common::backtrace; // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. - #[cfg(feature = "backtrace")] - let log_backtrace = panics >= 2 || backtrace::log_enabled(); + #[cfg(any(not(cargobuild), feature = "backtrace"))] + let log_backtrace = { + let panics = PANIC_COUNT.with(|c| c.get()); + + panics >= 2 || backtrace::log_enabled() + }; let file = info.location.file; let line = info.location.line; @@ -212,8 +210,12 @@ fn default_hook(info: &PanicInfo) { let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}", name, msg, file, line); - #[cfg(feature = "backtrace")] + #[cfg(any(not(cargobuild), feature = "backtrace"))] { + use sync::atomic::{AtomicBool, Ordering}; + + static FIRST_PANIC: AtomicBool = AtomicBool::new(true); + if log_backtrace { let _ = backtrace::write(err); } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 67b19682fc9a..a1f3f477b3ab 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -28,7 +28,7 @@ macro_rules! rtassert { pub mod args; pub mod at_exit_imp; -#[cfg(feature = "backtrace")] +#[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; pub mod io; @@ -43,7 +43,7 @@ pub mod thread_local; pub mod util; pub mod wtf8; -#[cfg(feature = "backtrace")] +#[cfg(any(not(cargobuild), feature = "backtrace"))] #[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))), all(windows, target_env = "gnu")))] pub mod gnu; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 9aac7be80176..1c25c8f77c19 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -30,7 +30,7 @@ use libc; pub mod weak; pub mod android; -#[cfg(feature = "backtrace")] +#[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; pub mod ext; From 132bff9933e90e07a2f993882dca9fc674116f5b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 25 Jul 2016 23:04:42 +0000 Subject: [PATCH 140/331] If a single import resolves to an inaccessible name in some but not all namespaces, avoid importing the name in the inaccessible namespaces. Currently, the inaccessible namespaces are imported but cause a privacy error when used. --- src/librustc_resolve/lib.rs | 11 +--- src/librustc_resolve/resolve_imports.rs | 74 +++++++++++-------------- 2 files changed, 35 insertions(+), 50 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index aa8c706ea1e2..7a0a417d0274 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -825,8 +825,6 @@ enum NameBindingKind<'a> { Import { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, - // Some(error) if using this imported name causes the import to be a privacy error - privacy_error: Option>>, }, } @@ -1206,16 +1204,11 @@ impl<'a> Resolver<'a> { self.used_crates.insert(krate); } - let (directive, privacy_error) = match binding.kind { - NameBindingKind::Import { directive, ref privacy_error, .. } => - (directive, privacy_error), + let directive = match binding.kind { + NameBindingKind::Import { directive, .. } => directive, _ => return, }; - if let Some(error) = privacy_error.as_ref() { - self.privacy_errors.push((**error).clone()); - } - if !self.make_glob_map { return; } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 681d9ec735b4..fc5e2a48e876 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -73,13 +73,11 @@ pub struct ImportDirective<'a> { impl<'a> ImportDirective<'a> { // Given the binding to which this directive resolves in a particular namespace, // this returns the binding for the name this directive defines in that namespace. - fn import(&'a self, binding: &'a NameBinding<'a>, privacy_error: Option>>) - -> NameBinding<'a> { + fn import(&'a self, binding: &'a NameBinding<'a>) -> NameBinding<'a> { NameBinding { kind: NameBindingKind::Import { binding: binding, directive: self, - privacy_error: privacy_error, }, span: self.span, vis: self.vis, @@ -328,7 +326,7 @@ impl<'a> ::ModuleS<'a> { fn define_in_glob_importers(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { if !binding.is_importable() || !binding.is_pseudo_public() { return } for &(importer, directive) in self.glob_importers.borrow_mut().iter() { - let _ = importer.try_define_child(name, ns, directive.import(binding, None)); + let _ = importer.try_define_child(name, ns, directive.import(binding)); } } } @@ -409,7 +407,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: DUMMY_SP, vis: ty::Visibility::Public, }); - let dummy_binding = directive.import(dummy_binding, None); + let dummy_binding = directive.import(dummy_binding); let _ = source_module.try_define_child(target, ValueNS, dummy_binding.clone()); let _ = source_module.try_define_child(target, TypeNS, dummy_binding); @@ -494,14 +492,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.resolver.resolve_name_in_module(target_module, source, TypeNS, false, true); let module_ = self.resolver.current_module; + let mut privacy_error = true; for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined), (TypeNS, &type_result, type_determined)] { - if determined.get() { continue } - if let Indeterminate = *result { continue } - - determined.set(true); - if let Success(binding) = *result { - if !binding.is_importable() { + match *result { + Failed(..) if !determined.get() => { + determined.set(true); + module_.update_resolution(target, ns, |resolution| { + resolution.single_imports.directive_failed() + }); + } + Success(binding) if !binding.is_importable() => { let msg = format!("`{}` is not directly importable", target); span_err!(self.resolver.session, directive.span, E0253, "{}", &msg); // Do not import this illegal binding. Import a dummy binding and pretend @@ -509,23 +510,19 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.import_dummy_binding(module_, directive); return Success(()); } - - let privacy_error = if !self.resolver.is_accessible(binding.vis) { - Some(Box::new(PrivacyError(directive.span, source, binding))) - } else { - None - }; - - let imported_binding = directive.import(binding, privacy_error); - let conflict = module_.try_define_child(target, ns, imported_binding); - if let Err(old_binding) = conflict { - let binding = &directive.import(binding, None); - self.resolver.report_conflict(module_, target, ns, binding, old_binding); + Success(binding) if !self.resolver.is_accessible(binding.vis) => {} + Success(binding) if !determined.get() => { + determined.set(true); + let imported_binding = directive.import(binding); + let conflict = module_.try_define_child(target, ns, imported_binding); + if let Err(old_binding) = conflict { + let binding = &directive.import(binding); + self.resolver.report_conflict(module_, target, ns, binding, old_binding); + } + privacy_error = false; } - } else { - module_.update_resolution(target, ns, |resolution| { - resolution.single_imports.directive_failed(); - }); + Success(_) => privacy_error = false, + _ => {} } } @@ -556,6 +553,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => (), } + if privacy_error { + for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] { + let binding = match *result { Success(binding) => binding, _ => continue }; + self.resolver.privacy_errors.push(PrivacyError(directive.span, source, binding)); + let _ = module_.try_define_child(target, ns, directive.import(binding)); + } + } + match (&value_result, &type_result) { (&Success(binding), _) if !binding.pseudo_vis() .is_at_least(directive.vis, self.resolver) && @@ -592,19 +597,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => {} } - // Report a privacy error here if all successful namespaces are privacy errors. - let mut privacy_error = None; - for &ns in &[ValueNS, TypeNS] { - privacy_error = match module_.resolve_name(target, ns, true) { - Success(&NameBinding { - kind: NameBindingKind::Import { ref privacy_error, .. }, .. - }) => privacy_error.as_ref().map(|error| (**error).clone()), - _ => continue, - }; - if privacy_error.is_none() { break } - } - privacy_error.map(|error| self.resolver.privacy_errors.push(error)); - // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. @@ -652,7 +644,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }).collect::>(); for ((name, ns), binding) in bindings { if binding.is_importable() && binding.is_pseudo_public() { - let _ = module_.try_define_child(name, ns, directive.import(binding, None)); + let _ = module_.try_define_child(name, ns, directive.import(binding)); } } From 8205691929bc545430f1fa73e61a4f5f77fbbdc7 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 26 Jul 2016 04:16:48 +0000 Subject: [PATCH 141/331] Fix fallout in tests. --- src/test/compile-fail/privacy-ns2.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs index bf296220d2a2..7accf0ca8201 100644 --- a/src/test/compile-fail/privacy-ns2.rs +++ b/src/test/compile-fail/privacy-ns2.rs @@ -25,15 +25,15 @@ pub mod foo1 { } fn test_single1() { - use foo1::Bar; //~ ERROR function `Bar` is private + use foo1::Bar; - Bar(); + Bar(); //~ ERROR unresolved name `Bar` } fn test_list1() { - use foo1::{Bar,Baz}; //~ ERROR `Bar` is private + use foo1::{Bar,Baz}; - Bar(); + Bar(); //~ ERROR unresolved name `Bar` } // private type, public value @@ -46,15 +46,15 @@ pub mod foo2 { } fn test_single2() { - use foo2::Bar; //~ ERROR trait `Bar` is private + use foo2::Bar; - let _x : Box; + let _x : Box; //~ ERROR type name `Bar` is undefined } fn test_list2() { - use foo2::{Bar,Baz}; //~ ERROR `Bar` is private + use foo2::{Bar,Baz}; - let _x: Box; + let _x: Box; //~ ERROR type name `Bar` is undefined } // neither public From ac73335f2f5421c914fa3900567696cc6dc73d8d Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Tue, 26 Jul 2016 15:54:55 -0400 Subject: [PATCH 142/331] implement `From>` and `From<&'a [char]>` for `String` Though there are ways to convert a slice or vec of chars into a string, it would be nice to be able to just do `String::from(['a', 'b', 'c'])`, so this PR implements `From>` and `From<&'a [char]>` for String. --- src/libcollections/string.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index f91d8a5f4e1e..06952253ef3b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1881,6 +1881,26 @@ impl Into> for String { } } +#[stable(feature = "stringfromchars", since = "1.12.0")] +impl<'a> From<&'a [char]> for String { + #[inline] + fn from(v: &'a [char]) -> String { + let mut s = String::with_capacity(v.len()); + for c in v { + s.push(*c); + } + s + } +} + +#[stable(feature = "stringfromchars", since = "1.12.0")] +impl From> for String { + #[inline] + fn from(v: Vec) -> String { + String::from(v.as_slice()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Write for String { #[inline] From a72767970adbe3600d1b66eff118ba4dd732c804 Mon Sep 17 00:00:00 2001 From: "Panashe M. Fundira" Date: Wed, 27 Jul 2016 13:12:35 -0400 Subject: [PATCH 143/331] 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 43868d124a22..e3207a0a86c4 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 144/331] 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 99bc26848025..78edcd555412 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 145/331] 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 78edcd555412..067885c92fdf 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 146/331] 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 481338d1cee5..6530ccb0630d 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 81be546e0c89..307823137a71 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 aec1bae60c81..14d0c8bedec1 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 d182fd960564..8bd9feabdbeb 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 e1b170422c60..f3a18b13c678 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 60c4a7c3c90c..e666a8460e5e 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 72128e30641c..d65c89abc206 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 a2486a1330a5..a806204d0a6b 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 fd8f35da16f6..1c59262e0419 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 7bcca3a3934b..52269f0cd4a0 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 e5379aa1b42c..aaa3570fa62e 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 e6200177944b..07eb191471c4 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 cf4020eeb587..f391d4118ea7 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 12bed370eae9..445ee6c41228 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 6eb645563819..1ca8606149bf 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 302691e9a592..4876a3489d47 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 2376de123980..1de629238a13 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 c2cc624c9f9e..2c19b8109c36 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 8c1bacc28076..cb02fcc308c2 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 6446ac45f7d6..f96ec004b481 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 a7903d5db641..3489ecfe614d 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 7813d5570762..f2e865c015e3 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 527442958374..a0a8de46e2f5 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 f4f0262d476d..25132f8a044d 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 ceb17e53a555..ab967f6b40fb 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 35366659d581..4a69bce53bc9 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 ac1536b3d009..b66fb62cd591 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 a9ea52c42786..24d1a66ec2d2 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 067885c92fdf..4849a76e11d9 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 be4be8e6fc96..1c04e763417c 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 b0a81ce7ec50..906e28d2f20c 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 aea57dc4b7f9..aebf9cd68717 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 5542c9120a40..65e4b1400fcf 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 8638241f8610..4afc9bcb946c 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 e243054d0230..086e0e6bf4fe 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 a23a807a0257..064f06e9b31d 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 af5d21c4d93e..537d15f4603b 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 8f2c905cf2ee..2a1feb937f74 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 87753da540a3..81710b99b80b 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 2535071f3089..7e40d49b870a 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 d3ad0578aeb6..f38cdd4bec55 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 7908e0d581ba..ef81d397a8f1 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 3301e0e0dc93..4bad7754b390 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 7e6d1b78469e..5145e52d6b4c 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 823b0994b0a0..339dbd591a02 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 147/331] 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 4849a76e11d9..84cb6c9ba7de 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 148/331] 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 84cb6c9ba7de..f5314809228b 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 0a8df923b846..eff920608dc2 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 2dbf00e2bb60b6b3172002c7e00d516c94d9ee42 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 25 Jul 2016 21:44:57 -0400 Subject: [PATCH 149/331] Only export #[no_mangle] extern symbols during LTO Previously, all extern symbols were exported even when performing LTO. Now, we only export symbols that are also marked #[no_mangle]. Fixes #34985 --- src/librustc_metadata/decoder.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 409cec282bce..062bbc3be40f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -55,7 +55,6 @@ use rustc_serialize::Decodable; use syntax::attr; use syntax::parse::token; use syntax::ast; -use syntax::abi::Abi; use syntax::codemap; use syntax::print::pprust; use syntax::ptr::P; @@ -1542,13 +1541,9 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, let applicable = match item_family(item_doc) { ImmStatic | MutStatic => true, Fn => { - let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); + let ty::TypeScheme { generics, .. } = get_type(cdata, id, tcx); let no_generics = generics.types.is_empty(); - match ty.sty { - ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) - if fn_ty.abi != Abi::Rust => return no_generics, - _ => no_generics, - } + no_generics }, _ => false, }; From 032ea41e99b39f6af2aa26c0ba049d0d215d8ebb Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 13 Jun 2016 13:22:38 -0400 Subject: [PATCH 150/331] 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 3cbe5d602677..873d078f053e 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 151/331] 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 873d078f053e..590c23e89299 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 152/331] 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 590c23e89299..fb8896da86d7 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 153/331] 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 fb8896da86d7..5a2ec86c12f5 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 154/331] 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 5a2ec86c12f5..07b8d8e0da8a 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 155/331] 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 07b8d8e0da8a..4a55db38d381 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 156/331] 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 4a55db38d381..74c99273fa26 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 157/331] 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 74c99273fa26..e63516e58ccf 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 158/331] 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 e63516e58ccf..e1b9789a3144 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 159/331] 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 e1b9789a3144..983bd46a0c9e 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 160/331] 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 983bd46a0c9e..f9c50f0399ad 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 161/331] 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 f9c50f0399ad..ca104ff29ace 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 162/331] 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 e3207a0a86c4..c8606b0f1636 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 163/331] 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 c8606b0f1636..260d974e45d6 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 164/331] 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 260d974e45d6..b0c79a3a8854 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 6ac83de691c5eb180e2007fcbe3236fd359d2ab7 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 27 Jul 2016 02:30:50 +0800 Subject: [PATCH 165/331] Add test for string AddAssign --- src/libcollectionstest/string.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 7f0fd282ae5e..1652fb5a88d8 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -192,6 +192,17 @@ fn test_push_str() { assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam"); } +#[test] +fn test_add_assign() { + let mut s = String::new(); + s += ""; + assert_eq!(s.as_str(), ""); + s += "abc"; + assert_eq!(s.as_str(), "abc"); + s += "ประเทศไทย中华Việt Nam"; + assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); +} + #[test] fn test_push() { let mut data = String::from("ประเทศไทย中"); From 3d09b4a0d58200da84fe19cd3b0003d61e5b1791 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 27 Jul 2016 12:10:31 +0200 Subject: [PATCH 166/331] 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 333219bc5e5b..7fc6e54d69f7 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 a63ea9d3ec77..4c64019de097 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 870f8a3a1ec6..a61925cd3be5 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 3e435b47110a..a3440fe8aa64 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 3bcdce57af0d..173c55e35d51 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 ec757b0b5d38..4632419336d7 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 1ef2b58351fe..ef0042808f98 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 683d5289ab53..7e308684a256 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 8c91d3b6a929..3ae905eba279 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 d05a5a096148..865d067cdb6d 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 2c1a656290f9..c0e6ec46b55b 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 931789948159..d12bdf182fa4 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 167/331] 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 48753ccf1c35..38fd93501a52 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 168/331] 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 000000000000..f41da77ee989 --- /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 4ffbb5dd63ebc584291143ccc8e9d849e9c485d1 Mon Sep 17 00:00:00 2001 From: Aravind Gollakota Date: Sat, 23 Jul 2016 11:53:07 -0700 Subject: [PATCH 169/331] rustbuild: Ensure PATH does not contain invalid character `"` --- src/bootstrap/sanity.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 7c0f09c322f2..737492467589 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -31,6 +31,15 @@ use Build; pub fn check(build: &mut Build) { let mut checked = HashSet::new(); let path = env::var_os("PATH").unwrap_or(OsString::new()); + // On Windows, quotes are invalid characters for filename paths, and if + // one is present as part of the PATH then that can lead to the system + // being unable to identify the files properly. See + // https://github.com/rust-lang/rust/issues/34959 for more details. + if cfg!(windows) { + if path.to_string_lossy().contains("\"") { + panic!("PATH contains invalid character '\"'"); + } + } let mut need_cmd = |cmd: &OsStr| { if !checked.insert(cmd.to_owned()) { return From ca259666a55c84bae8c37be27116dd48d529b357 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Thu, 28 Jul 2016 11:48:43 +0200 Subject: [PATCH 170/331] Reduce git clone --depth from 50 to 1 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 87197a37f1d4..0abd858d8228 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ services: # our configure script, so disable auto submodule management. git: submodules: false + depth: 1 before_install: - docker build -t rust -f src/etc/Dockerfile src/etc From 8d3f20f9061273b215a7d86f8783f1ae66f9b3ae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 Jul 2016 12:55:58 +0200 Subject: [PATCH 171/331] 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 54340773a42b..1e0dc3c833e7 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 172/331] 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 1e0dc3c833e7..77587918ac94 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 173/331] 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 a32c9da9815f..fdcadd43a0fb 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 cfdaca049a2451b62d3d403ef13b78d7a2f60816 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 27 Jul 2016 16:59:33 -0700 Subject: [PATCH 174/331] Rename _ to {numerics} for unknown numeric types --- src/librustc/util/ppaux.rs | 3 ++- src/test/compile-fail/array-not-vector.rs | 2 +- src/test/compile-fail/bad-const-type.rs | 2 +- src/test/compile-fail/coerce-mut.rs | 2 +- src/test/compile-fail/coercion-slice.rs | 2 +- src/test/compile-fail/fully-qualified-type-name1.rs | 2 +- src/test/compile-fail/if-let-arm-types.rs | 2 +- src/test/compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-variable-unification-error.rs | 4 ++-- src/test/compile-fail/issue-13466.rs | 4 ++-- src/test/compile-fail/issue-17651.rs | 2 +- src/test/compile-fail/issue-19991.rs | 2 +- src/test/compile-fail/issue-26237.rs | 2 +- src/test/compile-fail/issue-4201.rs | 2 +- src/test/compile-fail/issue-4968.rs | 2 +- src/test/compile-fail/issue-7867.rs | 4 ++-- src/test/compile-fail/kindck-impl-type-params-2.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 2 +- src/test/compile-fail/match-vec-mismatch.rs | 2 +- src/test/compile-fail/method-self-arg-1.rs | 2 +- src/test/compile-fail/mut-pattern-mismatched.rs | 4 ++-- src/test/compile-fail/no_send-rc.rs | 2 +- src/test/compile-fail/range-1.rs | 2 +- src/test/compile-fail/repeat_count.rs | 2 +- .../compile-fail/slightly-nice-generic-literal-messages.rs | 4 ++-- src/test/compile-fail/str-idx.rs | 2 +- src/test/compile-fail/struct-base-wrong-type-2.rs | 2 +- src/test/compile-fail/struct-base-wrong-type.rs | 2 +- .../compile-fail/traits-inductive-overflow-simultaneous.rs | 2 +- src/test/compile-fail/tuple-arity-mismatch.rs | 2 +- src/test/compile-fail/tuple-index-out-of-bounds.rs | 2 +- src/test/compile-fail/type-mismatch-multiple.rs | 2 +- src/test/compile-fail/typeck-unsafe-always-share.rs | 2 +- src/test/compile-fail/vtable-res-trait-param.rs | 2 +- src/test/ui/mismatched_types/issue-26480.stderr | 2 +- 35 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0bfb7c1ed553..a33d914e7cf7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -974,7 +974,8 @@ impl fmt::Display for ty::InferTy { ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => write!(f, "_"), + ty::TyVar(_) => write!(f, "_"), + ty::IntVar(_) | ty::FloatVar(_) => write!(f, "{}", "{numeric}"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) diff --git a/src/test/compile-fail/array-not-vector.rs b/src/test/compile-fail/array-not-vector.rs index 1bbccae53a44..b8883e4661ea 100644 --- a/src/test/compile-fail/array-not-vector.rs +++ b/src/test/compile-fail/array-not-vector.rs @@ -12,7 +12,7 @@ fn main() { let _x: i32 = [1, 2, 3]; //~^ ERROR mismatched types //~| expected type `i32` - //~| found type `[_; 3]` + //~| found type `[{numeric}; 3]` //~| expected i32, found array of 3 elements let x: &[i32] = &[1, 2, 3]; diff --git a/src/test/compile-fail/bad-const-type.rs b/src/test/compile-fail/bad-const-type.rs index ee6ac3307279..3b6221f0df5b 100644 --- a/src/test/compile-fail/bad-const-type.rs +++ b/src/test/compile-fail/bad-const-type.rs @@ -11,6 +11,6 @@ static i: String = 10; //~^ ERROR mismatched types //~| expected type `std::string::String` -//~| found type `_` +//~| found type `{numeric}` //~| expected struct `std::string::String`, found integral variable fn main() { println!("{}", i); } diff --git a/src/test/compile-fail/coerce-mut.rs b/src/test/compile-fail/coerce-mut.rs index 634d12441a12..91222e58b78c 100644 --- a/src/test/compile-fail/coerce-mut.rs +++ b/src/test/compile-fail/coerce-mut.rs @@ -15,6 +15,6 @@ fn main() { f(&x); //~^ ERROR mismatched types //~| expected type `&mut i32` - //~| found type `&_` + //~| found type `&{numeric}` //~| values differ in mutability } diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index bd7e6c2a2131..bfec84993961 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -14,6 +14,6 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| found type `[_; 1]` + //~| found type `[{numeric}; 1]` //~| expected &-ptr, found array of 1 elements } diff --git a/src/test/compile-fail/fully-qualified-type-name1.rs b/src/test/compile-fail/fully-qualified-type-name1.rs index 5ea8ce226443..3ae95a72abdd 100644 --- a/src/test/compile-fail/fully-qualified-type-name1.rs +++ b/src/test/compile-fail/fully-qualified-type-name1.rs @@ -15,6 +15,6 @@ fn main() { x = 5; //~^ ERROR mismatched types //~| expected type `std::option::Option` - //~| found type `_` + //~| found type `{numeric}` //~| expected enum `std::option::Option`, found integral variable } diff --git a/src/test/compile-fail/if-let-arm-types.rs b/src/test/compile-fail/if-let-arm-types.rs index c7b1e1a62c20..394a6fb30d7e 100644 --- a/src/test/compile-fail/if-let-arm-types.rs +++ b/src/test/compile-fail/if-let-arm-types.rs @@ -12,7 +12,7 @@ fn main() { if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types //~^ expected (), found integral variable //~| expected type `()` - //~| found type `_` + //~| found type `{numeric}` () } else { //~ NOTE: `if let` arm with an incompatible type 1 diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 354d7b936485..fe29a840f28c 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: `[_]: std::ops::Index` is not satisfied + [0][0u8]; //~ ERROR: `[{numeric}]: std::ops::Index` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-variable-unification-error.rs b/src/test/compile-fail/integral-variable-unification-error.rs index 99f2d2516689..9dd3772c10cd 100644 --- a/src/test/compile-fail/integral-variable-unification-error.rs +++ b/src/test/compile-fail/integral-variable-unification-error.rs @@ -12,7 +12,7 @@ fn main() { let mut x = 2; x = 5.0; //~^ ERROR mismatched types - //~| expected type `_` - //~| found type `_` + //~| expected type `{numeric}` + //~| found type `{numeric}` //~| expected integral variable, found floating-point variable } diff --git a/src/test/compile-fail/issue-13466.rs b/src/test/compile-fail/issue-13466.rs index 17b96411603e..b1a5adb313fa 100644 --- a/src/test/compile-fail/issue-13466.rs +++ b/src/test/compile-fail/issue-13466.rs @@ -17,13 +17,13 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected type `std::option::Option<_>` + //~| expected type `std::option::Option<{numeric}>` //~| found type `std::result::Result<_, _>` //~| expected enum `std::option::Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected type `std::option::Option<_>` + //~| expected type `std::option::Option<{numeric}>` //~| found type `std::result::Result<_, _>` //~| expected enum `std::option::Option`, found enum `std::result::Result` }; diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 0fe01ece558e..2438c86a57c7 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -14,5 +14,5 @@ fn main() { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (|| Box::new(*(&[0][..])))(); - //~^ ERROR `[_]: std::marker::Sized` is not satisfied + //~^ ERROR `[{numeric}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/issue-19991.rs b/src/test/compile-fail/issue-19991.rs index b368daaaf587..77a83a608213 100644 --- a/src/test/compile-fail/issue-19991.rs +++ b/src/test/compile-fail/issue-19991.rs @@ -14,7 +14,7 @@ fn main() { if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause //~| expected type `()` - //~| found type `_` + //~| found type `{numeric}` //~| expected (), found integral variable 765 }; diff --git a/src/test/compile-fail/issue-26237.rs b/src/test/compile-fail/issue-26237.rs index 11e236d22126..f2d24f3998cc 100644 --- a/src/test/compile-fail/issue-26237.rs +++ b/src/test/compile-fail/issue-26237.rs @@ -11,7 +11,7 @@ macro_rules! macro_panic { ($not_a_function:expr, $some_argument:ident) => { $not_a_function($some_argument) - //~^ ERROR expected function, found `_` + //~^ ERROR expected function, found `{numeric}` } } diff --git a/src/test/compile-fail/issue-4201.rs b/src/test/compile-fail/issue-4201.rs index 58423341cc6f..65bfeed20eaa 100644 --- a/src/test/compile-fail/issue-4201.rs +++ b/src/test/compile-fail/issue-4201.rs @@ -14,7 +14,7 @@ fn main() { } else if false { //~^ ERROR if may be missing an else clause //~| expected type `()` -//~| found type `_` +//~| found type `{numeric}` //~| expected (), found integral variable 1 }; diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index 7c0905873df8..e929f0cb3113 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,7 +14,7 @@ const A: (isize,isize) = (4,2); fn main() { match 42 { A => () } //~^ ERROR mismatched types - //~| expected type `_` + //~| expected type `{numeric}` //~| found type `(isize, isize)` //~| expected integral variable, found tuple } diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs index e0de860b0eac..95ba2308bfb9 100644 --- a/src/test/compile-fail/issue-7867.rs +++ b/src/test/compile-fail/issue-7867.rs @@ -25,12 +25,12 @@ fn main() { match &Some(42) { Some(x) => (), //~^ ERROR mismatched types - //~| expected type `&std::option::Option<_>` + //~| expected type `&std::option::Option<{numeric}>` //~| found type `std::option::Option<_>` //~| expected &-ptr, found enum `std::option::Option` None => () //~^ ERROR mismatched types - //~| expected type `&std::option::Option<_>` + //~| expected type `&std::option::Option<{numeric}>` //~| found type `std::option::Option<_>` //~| expected &-ptr, found enum `std::option::Option` } diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index 1cf970e150d7..93723ae9f237 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -21,5 +21,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR `Box<_>: std::marker::Copy` is not satisfied + //~^ ERROR `Box<{numeric}>: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 2c4c25630218..30386a589837 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -20,7 +20,7 @@ fn main() { 10 ... "what" => () }; //~^^ ERROR only char and numeric types are allowed in range - //~| start type: _ + //~| start type: {numeric} //~| end type: &'static str match 5 { diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index 3ac4958e7db0..94ac49e8f60d 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -18,7 +18,7 @@ fn main() { }; match &[0, 1, 2] { - [..] => {} //~ ERROR expected an array or slice, found `&[_; 3]` + [..] => {} //~ ERROR expected an array or slice, found `&[{numeric}; 3]` }; match &[0, 1, 2] { diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs index ffa5287d4b2c..5596fb7c8079 100644 --- a/src/test/compile-fail/method-self-arg-1.rs +++ b/src/test/compile-fail/method-self-arg-1.rs @@ -24,6 +24,6 @@ fn main() { //~| expected &-ptr, found struct `Foo` Foo::bar(&42); //~ ERROR mismatched types //~| expected type `&Foo` - //~| found type `&_` + //~| found type `&{numeric}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs index 63e7dbd30def..d1fd0057d294 100644 --- a/src/test/compile-fail/mut-pattern-mismatched.rs +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -14,7 +14,7 @@ fn main() { // (separate lines to ensure the spans are accurate) let &_ //~ ERROR mismatched types - //~| expected type `&mut _` + //~| expected type `&mut {numeric}` //~| found type `&_` //~| values differ in mutability = foo; @@ -23,7 +23,7 @@ fn main() { let bar = &1; let &_ = bar; let &mut _ //~ ERROR mismatched types - //~| expected type `&_` + //~| expected type `&{numeric}` //~| found type `&mut _` //~| values differ in mutability = bar; diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index 69f6fcdc4afa..7c364e8d6fb5 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,5 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<_>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<{numeric}>: std::marker::Send` is not satisfied } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index c00be91a2d74..7d69eca5ad58 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,5 +23,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR `[_]: std::marker::Sized` is not satisfied + //~^ ERROR `[{numeric}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 3a7e9cc4191e..1bdd24abe818 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -28,7 +28,7 @@ fn main() { let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected type `usize` - //~| found type `_` + //~| found type `{numeric}` //~| expected usize, found floating-point variable //~| ERROR expected usize for repeat count, found float [E0306] let e = [0; "foo"]; diff --git a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs index 3140bb6e5731..589876a7f5ff 100644 --- a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs +++ b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs @@ -16,8 +16,8 @@ fn main() { match Foo(1.1, marker::PhantomData) { 1 => {} //~^ ERROR mismatched types - //~| expected type `Foo<_, _>` - //~| found type `_` + //~| expected type `Foo<{numeric}, _>` + //~| found type `{numeric}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/str-idx.rs b/src/test/compile-fail/str-idx.rs index b972a09b5c49..1fb93bd79091 100644 --- a/src/test/compile-fail/str-idx.rs +++ b/src/test/compile-fail/str-idx.rs @@ -10,5 +10,5 @@ pub fn main() { let s: &str = "hello"; - let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<_>` is not satisfied + let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{numeric}>` is not satisfied } diff --git a/src/test/compile-fail/struct-base-wrong-type-2.rs b/src/test/compile-fail/struct-base-wrong-type-2.rs index 1250d0dabcd9..9624af488dd8 100644 --- a/src/test/compile-fail/struct-base-wrong-type-2.rs +++ b/src/test/compile-fail/struct-base-wrong-type-2.rs @@ -24,6 +24,6 @@ fn main() { //~| expected struct `Foo`, found struct `Bar` let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types //~| expected type `Foo` - //~| found type `_` + //~| found type `{numeric}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/struct-base-wrong-type.rs b/src/test/compile-fail/struct-base-wrong-type.rs index 4503e465840f..89b57f3dcd32 100644 --- a/src/test/compile-fail/struct-base-wrong-type.rs +++ b/src/test/compile-fail/struct-base-wrong-type.rs @@ -23,7 +23,7 @@ static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types //~| expected struct `Foo`, found struct `Bar` static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types //~| expected type `Foo` - //~| found type `_` + //~| found type `{numeric}` //~| expected struct `Foo`, found integral variable fn main() { diff --git a/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs b/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs index 2968e8a7ca99..97a99cb3ce7c 100644 --- a/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs +++ b/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs @@ -26,5 +26,5 @@ fn is_ee(t: T) { fn main() { is_ee(4); - //~^ ERROR overflow evaluating the requirement `_: Tweedle + //~^ ERROR overflow evaluating the requirement `{numeric}: Tweedle } diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index e62255a4e77d..09dc9aaf000e 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -16,7 +16,7 @@ fn main() { let y = first ((1,2.0,3)); //~^ ERROR mismatched types //~| expected type `(isize, f64)` - //~| found type `(isize, f64, _)` + //~| found type `(isize, f64, {numeric})` //~| expected a tuple with 2 elements, found one with 3 elements let y = first ((1,)); diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs index c2c41fbbb2aa..4a9d59ea0ed7 100644 --- a/src/test/compile-fail/tuple-index-out-of-bounds.rs +++ b/src/test/compile-fail/tuple-index-out-of-bounds.rs @@ -20,5 +20,5 @@ fn main() { tuple.0; tuple.1; tuple.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `(_, _)` + //~^ ERROR attempted out-of-bounds tuple index `2` on type `({numeric}, {numeric})` } diff --git a/src/test/compile-fail/type-mismatch-multiple.rs b/src/test/compile-fail/type-mismatch-multiple.rs index 0f174d99fefc..681b3a559c2b 100644 --- a/src/test/compile-fail/type-mismatch-multiple.rs +++ b/src/test/compile-fail/type-mismatch-multiple.rs @@ -13,7 +13,7 @@ fn main() { let a: bool = 1; let b: i32 = true; } //~^ ERROR mismatched types //~| expected type `bool` -//~| found type `_` +//~| found type `{numeric}` //~| expected bool, found integral variable //~| ERROR mismatched types //~| expected i32, found bool diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index 6047f6770a7b..50b8ae7e48cd 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -27,7 +27,7 @@ fn test(s: T) {} fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)}); test(us); - //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied let uns = UnsafeCell::new(NoSync); test(uns); diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs index eb0baff0005d..936b23075eb9 100644 --- a/src/test/compile-fail/vtable-res-trait-param.rs +++ b/src/test/compile-fail/vtable-res-trait-param.rs @@ -24,7 +24,7 @@ impl TraitB for isize { fn call_it(b: B) -> isize { let y = 4; - b.gimme_an_a(y) //~ ERROR `_: TraitA` is not satisfied + b.gimme_an_a(y) //~ ERROR `{numeric}: TraitA` is not satisfied } fn main() { diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index ff6920d28ccf..3a8d9a16398d 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -5,7 +5,7 @@ error[E0308]: mismatched types | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize $DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) -error: non-scalar cast: `_` as `()` +error: non-scalar cast: `{numeric}` as `()` --> $DIR/issue-26480.rs:33:19 | 33 | ($x:expr) => ($x as ()) From 2b38c4bdea7acf72b8322660de5a4f86d561a65c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:33:23 -0400 Subject: [PATCH 175/331] 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 73b96651b05e..dd7f0286574d 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 741ad65c29fd..ab7013df33f1 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 e65f6bbcf7aa..a499cb10f232 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 176/331] 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 5901c42b5258..cee18232ec98 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 56938a7a8385..5444dd947612 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 9a94cc16bfe8..e1fb7d05b726 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 cbc246ac2a11..70704f5dec0d 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 d4443c6d09d7..0b60fc386a7b 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 731425942359..c896263de948 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 177/331] 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 | 123 ++++++++++++++++++----- src/librustc_incremental/persist/mod.rs | 1 + src/librustc_incremental/persist/save.rs | 51 +++++++--- src/librustc_incremental/persist/util.rs | 46 +++++++-- 7 files changed, 192 insertions(+), 54 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index e1fb7d05b726..a48ff2533485 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 ed31e0ba5105..352e5979d011 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 f57ab19a5256..95e9a16f29bb 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 0ac1018462ee..9fef2285aa7e 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>) { - let _ignore = tcx.dep_graph.in_ignore(); + if tcx.sess.opts.incremental.is_none() { + return; + } - 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); + let _ignore = tcx.dep_graph.in_ignore(); + load_dep_graph_if_exists(tcx); + 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 72ccc29c97b6..30e7d7873ecc 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 99f4d4f30729..305250d59623 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 a77a9607e773..f1e81fdb266b 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 cdc6afed389ecdcea0955eadae59ea6b008a58fe Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 26 Jul 2016 16:31:39 -0700 Subject: [PATCH 178/331] Add non-panicking abs() functions to all signed integer types. Currently, calling abs() on one of the signed integer types might panic (in debug mode at least) because the absolute value of the largest negative value can not be represented in that signed type. Unlike all other integer operations, there is currently not a non-panicking version on this function. This seems to just be an oversight in the design, therefore just adding it now. --- src/libcore/num/mod.rs | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97648cc34699..4636811aa46d 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -611,6 +611,31 @@ macro_rules! int_impl { if b {None} else {Some(a)} } + /// Checked absolute value. Computes `self.abs()`, returning `None` if + /// `self == MIN`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(no_panic_abs)] + /// + /// use std::i32; + /// + /// assert_eq!((-5i32).checked_abs(), Some(5)); + /// assert_eq!(i32::MIN.checked_abs(), None); + /// ``` + #[unstable(feature = "no_panic_abs", issue = "35057")] + #[inline] + pub fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() + } else { + Some(self) + } + } + /// Saturating integer addition. Computes `self + other`, saturating at /// the numeric bounds instead of overflowing. /// @@ -863,6 +888,36 @@ macro_rules! int_impl { self.overflowing_shr(rhs).0 } + /// Wrapping (modular) absolute value. Computes `self.abs()`, + /// wrapping around at the boundary of the type. + /// + /// The only case where such wrapping can occur is when one takes + /// the absolute value of the negative minimal value for the type + /// this is a positive value that is too large to represent in the + /// type. In such a case, this function returns `MIN` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(no_panic_abs)] + /// + /// assert_eq!(100i8.wrapping_abs(), 100); + /// assert_eq!((-100i8).wrapping_abs(), 100); + /// assert_eq!((-128i8).wrapping_abs(), -128); + /// assert_eq!((-128i8).wrapping_abs() as u8, 128); + /// ``` + #[unstable(feature = "no_panic_abs", issue = "35057")] + #[inline(always)] + pub fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } + } + /// Calculates `self` + `rhs` /// /// Returns a tuple of the addition along with a boolean indicating @@ -1071,6 +1126,35 @@ macro_rules! int_impl { (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) } + /// Computes the absolute value of `self`. + /// + /// Returns a tuple of the absolute version of self along with a + /// boolean indicating whether an overflow happened. If self is the + /// minimum value (e.g. i32::MIN for values of type i32), then the + /// minimum value will be returned again and true will be returned for + /// an overflow happening. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(no_panic_abs)] + /// + /// assert_eq!(10i8.overflowing_abs(), (10,false)); + /// assert_eq!((-10i8).overflowing_abs(), (10,false)); + /// assert_eq!((-128i8).overflowing_abs(), (-128,true)); + /// ``` + #[unstable(feature = "no_panic_abs", issue = "35057")] + #[inline] + pub fn overflowing_abs(self) -> (Self, bool) { + if self.is_negative() { + self.overflowing_neg() + } else { + (self, false) + } + } + /// Raises self to the power of `exp`, using exponentiation by squaring. /// /// # Examples From 58d4b8edd319d0f0d76024504cdfc74f89a001b1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jul 2016 12:49:59 -0400 Subject: [PATCH 179/331] 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 | 141 ++++++++++++------ src/librustc_trans/consts.rs | 2 +- src/librustc_trans/context.rs | 71 ++++++--- 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, 388 insertions(+), 101 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 352e5979d011..0d11b0794fea 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 30e7d7873ecc..1157f494ce60 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 000000000000..01ac3f6c391d --- /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 33cffa8a4801..70925218781b 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 ea8c248d0239..a77ababaa635 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); - } - - // 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); + 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); } - } - // Finalize debuginfo - if ccx.sess().opts.debuginfo != NoDebugInfo { - debuginfo::finalize(&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); + } + } + + // 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 f662ba75cc6f..571d2731fb21 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 88903726d64f..bf6962982128 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 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); } - - let index = self.index; - self.index += 1; - - Some(CrateContext { - shared: self.shared, - index: index, - local_ccxs: self.local_ccxs, - }) } } @@ -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 ef7d0ea165d6..6bc48546dfa8 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 fa0a1fdc3752..6ac64d329108 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 00c0e9110350..96a05f11bfd1 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 8073359ede87..12df8bd83708 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 fc95d208f32c..3afedb490906 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 2e90b5184326..b58295d47f21 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 402b5ed83556..19e410fef538 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 180/331] 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 000000000000..e0532e7476f5 --- /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 a77ababaa635..69a884431359 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 6ac64d329108..67475081caec 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 27485ee65fcc..f80f25a2e776 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 000000000000..e84906d12d0c --- /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 000000000000..40f4b4f0c44c --- /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 000000000000..68af20d41915 --- /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 181/331] 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 ab7013df33f1..8691894b3251 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 4936e049ef2e..f4e1c06090e5 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 a48ff2533485..f172f38b8096 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 9fef2285aa7e..6b856459aabf 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 01ac3f6c391d..7695291bf620 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 70925218781b..08d7b531c2f1 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 69a884431359..e73c4f41c941 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 12df8bd83708..32bcbf9f7562 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 3afedb490906..fc2758e50f2c 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 e84906d12d0c..b00c68a184ed 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 40f4b4f0c44c..472d11d7f902 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 182/331] 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 dd7f0286574d..c9247539990a 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 8691894b3251..bb027b11b45a 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 a0c2416d24cf..690395399efa 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 6b856459aabf..36b6c79c40f5 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 7695291bf620..c106ea8f2626 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 08d7b531c2f1..4b9d5dd9e8d6 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 e73c4f41c941..5a19ddff7462 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 bf6962982128..a8f8474e9407 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 67475081caec..81a1dbeb7fe7 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 32bcbf9f7562..ade6e8abeb32 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 000000000000..ff5fd6347144 --- /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 000000000000..55398370425a --- /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 ea77049cfa72358d6a2d6370a3f7a6a70d93b8e8 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 28 Jul 2016 09:49:31 -0700 Subject: [PATCH 183/331] Move to {integer} and {float} --- src/librustc/util/ppaux.rs | 3 ++- src/test/compile-fail/array-not-vector.rs | 2 +- src/test/compile-fail/bad-const-type.rs | 2 +- src/test/compile-fail/coerce-mut.rs | 2 +- src/test/compile-fail/coercion-slice.rs | 2 +- src/test/compile-fail/fully-qualified-type-name1.rs | 2 +- src/test/compile-fail/if-let-arm-types.rs | 2 +- src/test/compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-variable-unification-error.rs | 4 ++-- src/test/compile-fail/issue-13466.rs | 4 ++-- src/test/compile-fail/issue-17651.rs | 2 +- src/test/compile-fail/issue-19991.rs | 2 +- src/test/compile-fail/issue-26237.rs | 2 +- src/test/compile-fail/issue-4201.rs | 2 +- src/test/compile-fail/issue-4968.rs | 2 +- src/test/compile-fail/issue-7867.rs | 4 ++-- src/test/compile-fail/kindck-impl-type-params-2.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 4 ++-- src/test/compile-fail/match-vec-mismatch.rs | 2 +- src/test/compile-fail/method-self-arg-1.rs | 2 +- src/test/compile-fail/mut-pattern-mismatched.rs | 4 ++-- src/test/compile-fail/no_send-rc.rs | 2 +- src/test/compile-fail/range-1.rs | 2 +- src/test/compile-fail/repeat_count.rs | 2 +- .../compile-fail/slightly-nice-generic-literal-messages.rs | 4 ++-- src/test/compile-fail/str-idx.rs | 2 +- src/test/compile-fail/struct-base-wrong-type-2.rs | 2 +- src/test/compile-fail/struct-base-wrong-type.rs | 2 +- .../compile-fail/traits-inductive-overflow-simultaneous.rs | 2 +- src/test/compile-fail/tuple-arity-mismatch.rs | 2 +- src/test/compile-fail/tuple-index-out-of-bounds.rs | 2 +- src/test/compile-fail/type-mismatch-multiple.rs | 2 +- src/test/compile-fail/typeck-unsafe-always-share.rs | 2 +- src/test/compile-fail/vtable-res-trait-param.rs | 2 +- src/test/ui/mismatched_types/issue-26480.stderr | 2 +- 35 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a33d914e7cf7..60977a80946f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -975,7 +975,8 @@ impl fmt::Display for ty::InferTy { ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), ty::TyVar(_) => write!(f, "_"), - ty::IntVar(_) | ty::FloatVar(_) => write!(f, "{}", "{numeric}"), + ty::IntVar(_) => write!(f, "{}", "{integer}"), + ty::FloatVar(_) => write!(f, "{}", "{float}"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) diff --git a/src/test/compile-fail/array-not-vector.rs b/src/test/compile-fail/array-not-vector.rs index b8883e4661ea..47e1c09f380b 100644 --- a/src/test/compile-fail/array-not-vector.rs +++ b/src/test/compile-fail/array-not-vector.rs @@ -12,7 +12,7 @@ fn main() { let _x: i32 = [1, 2, 3]; //~^ ERROR mismatched types //~| expected type `i32` - //~| found type `[{numeric}; 3]` + //~| found type `[{integer}; 3]` //~| expected i32, found array of 3 elements let x: &[i32] = &[1, 2, 3]; diff --git a/src/test/compile-fail/bad-const-type.rs b/src/test/compile-fail/bad-const-type.rs index 3b6221f0df5b..5547d19868d3 100644 --- a/src/test/compile-fail/bad-const-type.rs +++ b/src/test/compile-fail/bad-const-type.rs @@ -11,6 +11,6 @@ static i: String = 10; //~^ ERROR mismatched types //~| expected type `std::string::String` -//~| found type `{numeric}` +//~| found type `{integer}` //~| expected struct `std::string::String`, found integral variable fn main() { println!("{}", i); } diff --git a/src/test/compile-fail/coerce-mut.rs b/src/test/compile-fail/coerce-mut.rs index 91222e58b78c..86702a7463fd 100644 --- a/src/test/compile-fail/coerce-mut.rs +++ b/src/test/compile-fail/coerce-mut.rs @@ -15,6 +15,6 @@ fn main() { f(&x); //~^ ERROR mismatched types //~| expected type `&mut i32` - //~| found type `&{numeric}` + //~| found type `&{integer}` //~| values differ in mutability } diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index bfec84993961..a619f33468f4 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -14,6 +14,6 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| found type `[{numeric}; 1]` + //~| found type `[{integer}; 1]` //~| expected &-ptr, found array of 1 elements } diff --git a/src/test/compile-fail/fully-qualified-type-name1.rs b/src/test/compile-fail/fully-qualified-type-name1.rs index 3ae95a72abdd..1a7ceb2e7639 100644 --- a/src/test/compile-fail/fully-qualified-type-name1.rs +++ b/src/test/compile-fail/fully-qualified-type-name1.rs @@ -15,6 +15,6 @@ fn main() { x = 5; //~^ ERROR mismatched types //~| expected type `std::option::Option` - //~| found type `{numeric}` + //~| found type `{integer}` //~| expected enum `std::option::Option`, found integral variable } diff --git a/src/test/compile-fail/if-let-arm-types.rs b/src/test/compile-fail/if-let-arm-types.rs index 394a6fb30d7e..40013a7ee43b 100644 --- a/src/test/compile-fail/if-let-arm-types.rs +++ b/src/test/compile-fail/if-let-arm-types.rs @@ -12,7 +12,7 @@ fn main() { if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types //~^ expected (), found integral variable //~| expected type `()` - //~| found type `{numeric}` + //~| found type `{integer}` () } else { //~ NOTE: `if let` arm with an incompatible type 1 diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index fe29a840f28c..61d54b3f8e4f 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: `[{numeric}]: std::ops::Index` is not satisfied + [0][0u8]; //~ ERROR: `[{integer}]: std::ops::Index` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-variable-unification-error.rs b/src/test/compile-fail/integral-variable-unification-error.rs index 9dd3772c10cd..f2686ae4d196 100644 --- a/src/test/compile-fail/integral-variable-unification-error.rs +++ b/src/test/compile-fail/integral-variable-unification-error.rs @@ -12,7 +12,7 @@ fn main() { let mut x = 2; x = 5.0; //~^ ERROR mismatched types - //~| expected type `{numeric}` - //~| found type `{numeric}` + //~| expected type `{integer}` + //~| found type `{float}` //~| expected integral variable, found floating-point variable } diff --git a/src/test/compile-fail/issue-13466.rs b/src/test/compile-fail/issue-13466.rs index b1a5adb313fa..abddf6ba7a38 100644 --- a/src/test/compile-fail/issue-13466.rs +++ b/src/test/compile-fail/issue-13466.rs @@ -17,13 +17,13 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected type `std::option::Option<{numeric}>` + //~| expected type `std::option::Option<{integer}>` //~| found type `std::result::Result<_, _>` //~| expected enum `std::option::Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected type `std::option::Option<{numeric}>` + //~| expected type `std::option::Option<{integer}>` //~| found type `std::result::Result<_, _>` //~| expected enum `std::option::Option`, found enum `std::result::Result` }; diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 2438c86a57c7..3ea136aca4be 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -14,5 +14,5 @@ fn main() { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (|| Box::new(*(&[0][..])))(); - //~^ ERROR `[{numeric}]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/issue-19991.rs b/src/test/compile-fail/issue-19991.rs index 77a83a608213..e07dfaf9fe59 100644 --- a/src/test/compile-fail/issue-19991.rs +++ b/src/test/compile-fail/issue-19991.rs @@ -14,7 +14,7 @@ fn main() { if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause //~| expected type `()` - //~| found type `{numeric}` + //~| found type `{integer}` //~| expected (), found integral variable 765 }; diff --git a/src/test/compile-fail/issue-26237.rs b/src/test/compile-fail/issue-26237.rs index f2d24f3998cc..22772e596b19 100644 --- a/src/test/compile-fail/issue-26237.rs +++ b/src/test/compile-fail/issue-26237.rs @@ -11,7 +11,7 @@ macro_rules! macro_panic { ($not_a_function:expr, $some_argument:ident) => { $not_a_function($some_argument) - //~^ ERROR expected function, found `{numeric}` + //~^ ERROR expected function, found `{integer}` } } diff --git a/src/test/compile-fail/issue-4201.rs b/src/test/compile-fail/issue-4201.rs index 65bfeed20eaa..b1f668d9c5e2 100644 --- a/src/test/compile-fail/issue-4201.rs +++ b/src/test/compile-fail/issue-4201.rs @@ -14,7 +14,7 @@ fn main() { } else if false { //~^ ERROR if may be missing an else clause //~| expected type `()` -//~| found type `{numeric}` +//~| found type `{integer}` //~| expected (), found integral variable 1 }; diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index e929f0cb3113..77588e5c221f 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,7 +14,7 @@ const A: (isize,isize) = (4,2); fn main() { match 42 { A => () } //~^ ERROR mismatched types - //~| expected type `{numeric}` + //~| expected type `{integer}` //~| found type `(isize, isize)` //~| expected integral variable, found tuple } diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs index 95ba2308bfb9..ed465117344d 100644 --- a/src/test/compile-fail/issue-7867.rs +++ b/src/test/compile-fail/issue-7867.rs @@ -25,12 +25,12 @@ fn main() { match &Some(42) { Some(x) => (), //~^ ERROR mismatched types - //~| expected type `&std::option::Option<{numeric}>` + //~| expected type `&std::option::Option<{integer}>` //~| found type `std::option::Option<_>` //~| expected &-ptr, found enum `std::option::Option` None => () //~^ ERROR mismatched types - //~| expected type `&std::option::Option<{numeric}>` + //~| expected type `&std::option::Option<{integer}>` //~| found type `std::option::Option<_>` //~| expected &-ptr, found enum `std::option::Option` } diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index 93723ae9f237..a455a7b2d5d0 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -21,5 +21,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR `Box<{numeric}>: std::marker::Copy` is not satisfied + //~^ ERROR `Box<{integer}>: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 30386a589837..f89b3e39390d 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -20,7 +20,7 @@ fn main() { 10 ... "what" => () }; //~^^ ERROR only char and numeric types are allowed in range - //~| start type: {numeric} + //~| start type: {integer} //~| end type: &'static str match 5 { @@ -28,6 +28,6 @@ fn main() { _ => { } }; //~^^^ ERROR mismatched types - //~| expected type `_` + //~| expected type `{integer}` //~| found type `char` } diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index 94ac49e8f60d..596cec167c21 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -18,7 +18,7 @@ fn main() { }; match &[0, 1, 2] { - [..] => {} //~ ERROR expected an array or slice, found `&[{numeric}; 3]` + [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` }; match &[0, 1, 2] { diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs index 5596fb7c8079..03816362d46c 100644 --- a/src/test/compile-fail/method-self-arg-1.rs +++ b/src/test/compile-fail/method-self-arg-1.rs @@ -24,6 +24,6 @@ fn main() { //~| expected &-ptr, found struct `Foo` Foo::bar(&42); //~ ERROR mismatched types //~| expected type `&Foo` - //~| found type `&{numeric}` + //~| found type `&{integer}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs index d1fd0057d294..318d121e4c2d 100644 --- a/src/test/compile-fail/mut-pattern-mismatched.rs +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -14,7 +14,7 @@ fn main() { // (separate lines to ensure the spans are accurate) let &_ //~ ERROR mismatched types - //~| expected type `&mut {numeric}` + //~| expected type `&mut {integer}` //~| found type `&_` //~| values differ in mutability = foo; @@ -23,7 +23,7 @@ fn main() { let bar = &1; let &_ = bar; let &mut _ //~ ERROR mismatched types - //~| expected type `&{numeric}` + //~| expected type `&{integer}` //~| found type `&mut _` //~| values differ in mutability = bar; diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index 7c364e8d6fb5..f31d37873349 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,5 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<{numeric}>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<{integer}>: std::marker::Send` is not satisfied } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 7d69eca5ad58..dc6833163a47 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,5 +23,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR `[{numeric}]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 1bdd24abe818..1758b28a3248 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -28,7 +28,7 @@ fn main() { let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected type `usize` - //~| found type `{numeric}` + //~| found type `{float}` //~| expected usize, found floating-point variable //~| ERROR expected usize for repeat count, found float [E0306] let e = [0; "foo"]; diff --git a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs index 589876a7f5ff..2eba7c2e534e 100644 --- a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs +++ b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs @@ -16,8 +16,8 @@ fn main() { match Foo(1.1, marker::PhantomData) { 1 => {} //~^ ERROR mismatched types - //~| expected type `Foo<{numeric}, _>` - //~| found type `{numeric}` + //~| expected type `Foo<{float}, _>` + //~| found type `{integer}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/str-idx.rs b/src/test/compile-fail/str-idx.rs index 1fb93bd79091..2b2c23a3ce4e 100644 --- a/src/test/compile-fail/str-idx.rs +++ b/src/test/compile-fail/str-idx.rs @@ -10,5 +10,5 @@ pub fn main() { let s: &str = "hello"; - let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{numeric}>` is not satisfied + let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{integer}>` is not satisfied } diff --git a/src/test/compile-fail/struct-base-wrong-type-2.rs b/src/test/compile-fail/struct-base-wrong-type-2.rs index 9624af488dd8..7e5510edb2c3 100644 --- a/src/test/compile-fail/struct-base-wrong-type-2.rs +++ b/src/test/compile-fail/struct-base-wrong-type-2.rs @@ -24,6 +24,6 @@ fn main() { //~| expected struct `Foo`, found struct `Bar` let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types //~| expected type `Foo` - //~| found type `{numeric}` + //~| found type `{integer}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/struct-base-wrong-type.rs b/src/test/compile-fail/struct-base-wrong-type.rs index 89b57f3dcd32..3703b15d4db8 100644 --- a/src/test/compile-fail/struct-base-wrong-type.rs +++ b/src/test/compile-fail/struct-base-wrong-type.rs @@ -23,7 +23,7 @@ static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types //~| expected struct `Foo`, found struct `Bar` static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types //~| expected type `Foo` - //~| found type `{numeric}` + //~| found type `{integer}` //~| expected struct `Foo`, found integral variable fn main() { diff --git a/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs b/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs index 97a99cb3ce7c..777746a189c5 100644 --- a/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs +++ b/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs @@ -26,5 +26,5 @@ fn is_ee(t: T) { fn main() { is_ee(4); - //~^ ERROR overflow evaluating the requirement `{numeric}: Tweedle + //~^ ERROR overflow evaluating the requirement `{integer}: Tweedle } diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index 09dc9aaf000e..a71f44102947 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -16,7 +16,7 @@ fn main() { let y = first ((1,2.0,3)); //~^ ERROR mismatched types //~| expected type `(isize, f64)` - //~| found type `(isize, f64, {numeric})` + //~| found type `(isize, f64, {integer})` //~| expected a tuple with 2 elements, found one with 3 elements let y = first ((1,)); diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs index 4a9d59ea0ed7..4597cf3d350c 100644 --- a/src/test/compile-fail/tuple-index-out-of-bounds.rs +++ b/src/test/compile-fail/tuple-index-out-of-bounds.rs @@ -20,5 +20,5 @@ fn main() { tuple.0; tuple.1; tuple.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `({numeric}, {numeric})` + //~^ ERROR attempted out-of-bounds tuple index `2` on type `({integer}, {integer})` } diff --git a/src/test/compile-fail/type-mismatch-multiple.rs b/src/test/compile-fail/type-mismatch-multiple.rs index 681b3a559c2b..9359c0359566 100644 --- a/src/test/compile-fail/type-mismatch-multiple.rs +++ b/src/test/compile-fail/type-mismatch-multiple.rs @@ -13,7 +13,7 @@ fn main() { let a: bool = 1; let b: i32 = true; } //~^ ERROR mismatched types //~| expected type `bool` -//~| found type `{numeric}` +//~| found type `{integer}` //~| expected bool, found integral variable //~| ERROR mismatched types //~| expected i32, found bool diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index 50b8ae7e48cd..f0172777cdab 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -27,7 +27,7 @@ fn test(s: T) {} fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)}); test(us); - //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied let uns = UnsafeCell::new(NoSync); test(uns); diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs index 936b23075eb9..8b3e9369ece4 100644 --- a/src/test/compile-fail/vtable-res-trait-param.rs +++ b/src/test/compile-fail/vtable-res-trait-param.rs @@ -24,7 +24,7 @@ impl TraitB for isize { fn call_it(b: B) -> isize { let y = 4; - b.gimme_an_a(y) //~ ERROR `{numeric}: TraitA` is not satisfied + b.gimme_an_a(y) //~ ERROR `{integer}: TraitA` is not satisfied } fn main() { diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 3a8d9a16398d..45638a65915c 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -5,7 +5,7 @@ error[E0308]: mismatched types | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize $DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) -error: non-scalar cast: `{numeric}` as `()` +error: non-scalar cast: `{integer}` as `()` --> $DIR/issue-26480.rs:33:19 | 33 | ($x:expr) => ($x as ()) From 6dc98cf099d1fc3209e1354144f2190c052c8a0b Mon Sep 17 00:00:00 2001 From: mcarton Date: Thu, 28 Jul 2016 19:33:31 +0200 Subject: [PATCH 184/331] Revert "Remove unused methods from MultiSpan" This reverts commit f7019a4e2f80577d38ec35fcebd64d5970b15f78. This removed the only way to make a suggestion with more than one substitute. Bring it back until we come up with a better solution. --- src/libsyntax_pos/lib.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index c96be8fec2b0..7dfe19452a2a 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -193,6 +193,20 @@ 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)); } @@ -240,10 +254,7 @@ impl MultiSpan { impl From for MultiSpan { fn from(span: Span) -> MultiSpan { - MultiSpan { - primary_spans: vec![span], - span_labels: vec![] - } + MultiSpan::from_span(span) } } From e359147d1214c6fe8e010118c5df05ca10f0a2b9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 28 Jul 2016 15:39:02 -0400 Subject: [PATCH 185/331] 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 70704f5dec0d..d433bdea6eca 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 186/331] 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 d433bdea6eca..7b1e0d2d0c8b 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 bb6c27e74d08b78709b6fb87f5cb149f4366ccb6 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 28 Jul 2016 11:30:38 +0200 Subject: [PATCH 187/331] Escape the unmatched surrogates with lower-case hexadecimal numbers It's done the same way for the rest of the codepoint escapes. --- src/libstd/sys/common/wtf8.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index c0e6ec46b55b..c1b4f8a8c88c 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -408,7 +408,7 @@ impl fmt::Debug for Wtf8 { &self.bytes[pos .. surrogate_pos] )}, )?; - write!(formatter, "\\u{{{:X}}}", surrogate)?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; pos = surrogate_pos + 3; } } @@ -1066,7 +1066,7 @@ mod tests { fn wtf8buf_show() { let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{D800}\""); + assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); } #[test] From 3563e400cc834bece5064e57ad698163865687d7 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 28 Jul 2016 19:02:25 -0700 Subject: [PATCH 188/331] 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 666d0946ecc8..24fcf886ef03 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 From f459e801fd6cfad61e81ed12e6c364f0776d6ed4 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 28 Jul 2016 22:09:31 -0400 Subject: [PATCH 189/331] Rewrite `collections::LinkedList::append` doc example. --- src/libcollections/linked_list.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 3d5c3125fae2..6842f02e0e19 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -203,19 +203,22 @@ impl LinkedList { /// ``` /// use std::collections::LinkedList; /// - /// let mut a = LinkedList::new(); - /// let mut b = LinkedList::new(); - /// a.push_back(1); - /// a.push_back(2); - /// b.push_back(3); - /// b.push_back(4); + /// let mut list1 = LinkedList::new(); + /// list1.push_back('a'); /// - /// a.append(&mut b); + /// let mut list2 = LinkedList::new(); + /// list2.push_back('b'); + /// list2.push_back('c'); /// - /// for e in &a { - /// println!("{}", e); // prints 1, then 2, then 3, then 4 - /// } - /// println!("{}", b.len()); // prints 0 + /// list1.append(&mut list2); + /// + /// let mut iter = list1.iter(); + /// assert_eq!(iter.next(), Some(&'a')); + /// assert_eq!(iter.next(), Some(&'b')); + /// assert_eq!(iter.next(), Some(&'c')); + /// assert!(iter.next().is_none()); + /// + /// assert!(list2.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn append(&mut self, other: &mut Self) { From d22a9a294052ca2fe97862d32c768e581baf797f Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 00:29:47 +0200 Subject: [PATCH 190/331] Upgrade to rust-llvm-2016-07-09 --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index 7ca76af03bb0..a5b8261c9a0e 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 7ca76af03bb04659562890d6b4f223fffe0d748f +Subproject commit a5b8261c9a0ea200bc4da345ae43823989ad46ed From 7420874a97a268d1c75dbc0e95231e4c8a1d513a Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 00:38:30 +0200 Subject: [PATCH 191/331] [LLVM-3.9] Rename custom methods to Rust-specific ones --- src/librustc_llvm/lib.rs | 6 +++--- src/librustc_trans/builder.rs | 2 +- src/rustllvm/RustWrapper.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index e757201c8863..f14df2a7b484 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -226,7 +226,7 @@ impl Attributes { pub fn apply_callsite(&self, idx: usize, callsite: ValueRef) { unsafe { - LLVMAddCallSiteAttribute(callsite, idx as c_uint, self.regular.bits()); + LLVMRustAddCallSiteAttribute(callsite, idx as c_uint, self.regular.bits()); if self.dereferenceable_bytes != 0 { LLVMAddDereferenceableCallSiteAttr(callsite, idx as c_uint, self.dereferenceable_bytes); @@ -1056,7 +1056,7 @@ extern { pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: c_uint, align: c_uint); - pub fn LLVMAddCallSiteAttribute(Instr: ValueRef, + pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: uint64_t); pub fn LLVMAddDereferenceableCallSiteAttr(Instr: ValueRef, @@ -1561,7 +1561,7 @@ extern { Alignment: c_uint) -> ValueRef; - pub fn LLVMBuildAtomicCmpXchg(B: BuilderRef, + pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef, LHS: ValueRef, CMP: ValueRef, RHS: ValueRef, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index e88257dcd4cf..7495f2b753b8 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -1083,7 +1083,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { failure_order: AtomicOrdering, weak: llvm::Bool) -> ValueRef { unsafe { - llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, + llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, order, failure_order, weak) } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index fadd95c9a724..bc38245d3512 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -99,7 +99,7 @@ extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } -extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { +extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addRawValue(Val); @@ -203,7 +203,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, return wrap(unwrap(B)->Insert(si)); } -extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, +extern "C" LLVMValueRef LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef target, LLVMValueRef old, LLVMValueRef source, From fba1f8f1239e45aa44bacfa0f955a24e3ade6982 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 00:40:38 +0200 Subject: [PATCH 192/331] [LLVM-3.9] Setup the compile unit information immediately Since LLVM reversed the order of the debug info graphs, we need to have a compile unit that exists *before* any functions (`DISubprogram`s) are created. This allows the LLVM debug info builder to automatically link the functions to the compile unit. --- src/librustc_trans/context.rs | 4 +++- src/librustc_trans/debuginfo/metadata.rs | 30 ++++++++++++++---------- src/librustc_trans/debuginfo/mod.rs | 5 ++-- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a8f8474e9407..aa60110fab37 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -558,7 +558,9 @@ impl<'tcx> LocalCrateContext<'tcx> { &llmod_id[..]); let dbg_cx = if shared.tcx.sess.opts.debuginfo != NoDebugInfo { - Some(debuginfo::CrateDebugContext::new(llmod)) + let dctx = debuginfo::CrateDebugContext::new(llmod); + debuginfo::metadata::compile_unit_metadata(shared, &dctx, shared.tcx.sess); + Some(dctx) } else { None }; diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 46813d957dce..1119ee07230e 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -18,7 +18,9 @@ use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align fn_should_be_ignored, is_node_local_to_unit}; use super::namespace::mangled_name_of_item; use super::type_names::{compute_debuginfo_type_name, push_debuginfo_type_name}; -use super::{declare_local, VariableKind, VariableAccess}; +use super::{declare_local, VariableKind, VariableAccess, CrateDebugContext}; +use context::SharedCrateContext; +use session::Session; use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; @@ -48,7 +50,6 @@ use syntax::ast; use syntax::parse::token; use syntax_pos::{self, Span}; - // From DWARF 5. // See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1 const DW_LANG_RUST: c_uint = 0x1c; @@ -981,14 +982,17 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return ptr_metadata; } -pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { - let work_dir = &cx.sess().working_dir; - let compile_unit_name = match cx.sess().local_crate_source_file { - None => fallback_path(cx), +pub fn compile_unit_metadata(scc: &SharedCrateContext, + debug_context: &CrateDebugContext, + sess: &Session) + -> DIDescriptor { + let work_dir = &sess.working_dir; + let compile_unit_name = match sess.local_crate_source_file { + None => fallback_path(scc), Some(ref abs_path) => { if abs_path.is_relative() { - cx.sess().warn("debuginfo: Invalid path to crate's local root source file!"); - fallback_path(cx) + sess.warn("debuginfo: Invalid path to crate's local root source file!"); + fallback_path(scc) } else { match abs_path.strip_prefix(work_dir) { Ok(ref p) if p.is_relative() => { @@ -998,7 +1002,7 @@ pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { path2cstr(&Path::new(".").join(p)) } } - _ => fallback_path(cx) + _ => fallback_path(scc) } } } @@ -1015,19 +1019,19 @@ pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { let split_name = "\0"; return unsafe { llvm::LLVMDIBuilderCreateCompileUnit( - debug_context(cx).builder, + debug_context.builder, DW_LANG_RUST, compile_unit_name, work_dir.as_ptr(), producer.as_ptr(), - cx.sess().opts.optimize != config::OptLevel::No, + sess.opts.optimize != config::OptLevel::No, flags.as_ptr() as *const _, 0, split_name.as_ptr() as *const _) }; - fn fallback_path(cx: &CrateContext) -> CString { - CString::new(cx.link_meta().crate_name.clone()).unwrap() + fn fallback_path(scc: &::context::SharedCrateContext) -> CString { + CString::new(scc.link_meta().crate_name.clone()).unwrap() } } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 8c5b3ed54c2f..ed20d949d55c 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -18,7 +18,7 @@ use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; use self::namespace::mangled_name_of_item; use self::type_names::compute_debuginfo_type_name; use self::metadata::{type_metadata, diverging_type_metadata}; -use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; +use self::metadata::{file_metadata, scope_metadata, TypeMap}; use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; @@ -50,7 +50,7 @@ pub mod gdb; mod utils; mod namespace; mod type_names; -mod metadata; +pub mod metadata; mod create_scope_map; mod source_loc; @@ -168,7 +168,6 @@ pub fn finalize(cx: &CrateContext) { } debug!("finalize"); - let _ = compile_unit_metadata(cx); if gdb::needs_gdb_debug_scripts_section(cx) { // Add a .debug_gdb_scripts section to this compile-unit. This will From 6ed5db8d351038622b180be917ef2e2e3f0727b2 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 00:42:20 +0200 Subject: [PATCH 193/331] [LLVM-3.9] Specify that we are using the legacy interface LLVM pass manager infrastructure is currently getting rewritten to be more flexible, but the rewrite isn't complete yet. --- src/rustllvm/PassWrapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 3564f338a029..95ad686161f1 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -267,7 +267,7 @@ LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, // similar code in clang's BackendUtil.cpp file. extern "C" void LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) { - FunctionPassManager *P = unwrap(PM); + llvm::legacy::FunctionPassManager *P = unwrap(PM); P->doInitialization(); for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E; ++I) @@ -294,7 +294,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, const char *path, TargetMachine::CodeGenFileType FileType) { - PassManager *PM = unwrap(PMR); + llvm::legacy::PassManager *PM = unwrap(PMR); std::string ErrorInfo; std::error_code EC; @@ -320,7 +320,7 @@ extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M, const char* path) { - PassManager *PM = unwrap(PMR); + llvm::legacy::PassManager *PM = unwrap(PMR); std::string ErrorInfo; std::error_code EC; From 5b44e10fb7e9d1226af11df26ee5fa78b8d54cc3 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 00:42:44 +0200 Subject: [PATCH 194/331] [LLVM-3.9] Preserve certain functions when internalizing This makes sure to still use the old way for older LLVM versions. --- src/rustllvm/PassWrapper.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 95ad686161f1..64edc79a86a3 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -358,9 +358,24 @@ LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) { extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **symbols, size_t len) { - PassManager passes; + llvm::legacy::PassManager passes; + +#if LLVM_VERSION_MINOR <= 8 ArrayRef ref(symbols, len); passes.add(llvm::createInternalizePass(ref)); +#else + auto PreserveFunctions = [=](const GlobalValue &GV) { + for (size_t i=0; i Date: Wed, 13 Jul 2016 15:29:24 +0200 Subject: [PATCH 195/331] [LLVM-3.9] Replace NewArchiveIterator with NewArchiveMember The new NewArchiveMember is simpler and requires less context, according to upstream. This was changed in http://reviews.llvm.org/D21721 --- src/rustllvm/ArchiveWrapper.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 1e7b04c814ce..cdd11e8838c4 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -150,19 +150,33 @@ LLVMRustWriteArchive(char *Dst, const LLVMRustArchiveMember **NewMembers, bool WriteSymbtab, Archive::Kind Kind) { - std::vector Members; + std::vector Members; for (size_t i = 0; i < NumMembers; i++) { auto Member = NewMembers[i]; assert(Member->name); if (Member->filename) { -#if LLVM_VERSION_MINOR >= 8 - Members.push_back(NewArchiveIterator(Member->filename)); +#if LLVM_VERSION_MINOR >= 9 + Expected MOrErr = NewArchiveMember::getFile(Member->filename, true); + if (!MOrErr) { + LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); + return -1; + } + Members.push_back(std::move(*MOrErr)); #else Members.push_back(NewArchiveIterator(Member->filename, Member->name)); #endif } else { +#if LLVM_VERSION_MINOR >= 9 + Expected MOrErr = NewArchiveMember::getOldMember(Member->child, true); + if (!MOrErr) { + LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); + return -1; + } + Members.push_back(std::move(*MOrErr)); +#else Members.push_back(NewArchiveIterator(Member->child, Member->name)); +#endif } } #if LLVM_VERSION_MINOR >= 8 From dbb4178f4effa2f7686aca70d5fdfa0eff94e692 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 16:06:50 +0200 Subject: [PATCH 196/331] [LLVM-3.9] Update return type for Archive::create Changed in https://github.com/rust-lang/llvm/commit/0b21d88fd31b4bfb6fdb7e2f1ed5f93639d5bd1c --- src/rustllvm/ArchiveWrapper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index cdd11e8838c4..514d25297ee2 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -43,11 +43,19 @@ LLVMRustOpenArchive(char *path) { return nullptr; } +#if LLVM_VERSION_MINOR <= 8 ErrorOr> archive_or = +#else + Expected> archive_or = +#endif Archive::create(buf_or.get()->getMemBufferRef()); if (!archive_or) { +#if LLVM_VERSION_MINOR <= 8 LLVMRustSetLastError(archive_or.getError().message().c_str()); +#else + LLVMRustSetLastError(toString(archive_or.takeError()).c_str()); +#endif return nullptr; } From 9e706f90cbc844bb09187e01acd4ae075130bc81 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 13 Jul 2016 00:41:40 +0200 Subject: [PATCH 197/331] [LLVM-3.9] Configure PIE at the module level instead of compilation unit level This was deleted here[1] which appears to be replaced by this[2] which is a new setPIELevel function on the LLVM module itself. [1]: http://reviews.llvm.org/D19753 [2]: http://reviews.llvm.org/D19671 --- src/librustc_llvm/lib.rs | 1 + src/librustc_trans/context.rs | 1 + src/rustllvm/PassWrapper.cpp | 10 ++++++++++ 3 files changed, 12 insertions(+) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index f14df2a7b484..4fc866752eb9 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -2155,6 +2155,7 @@ extern { pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char); pub fn LLVMRustUnsetComdat(V: ValueRef); + pub fn LLVMRustSetModulePIELevel(M: ModuleRef); } // LLVM requires symbols from this library, but apparently they're not printed diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index aa60110fab37..2437fa954d18 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -352,6 +352,7 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR let llvm_target = sess.target.target.llvm_target.as_bytes(); let llvm_target = CString::new(llvm_target).unwrap(); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + llvm::LLVMRustSetModulePIELevel(llmod); (llcx, llmod) } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 64edc79a86a3..edf83bf80d6d 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -188,7 +188,10 @@ LLVMRustCreateTargetMachine(const char *triple, } TargetOptions Options; +#if LLVM_VERSION_MINOR <= 8 Options.PositionIndependentExecutable = PositionIndependentExecutable; +#endif + Options.FloatABIType = FloatABI::Default; if (UseSoftFloat) { Options.FloatABIType = FloatABI::Soft; @@ -411,3 +414,10 @@ extern "C" LLVMTargetDataRef LLVMRustGetModuleDataLayout(LLVMModuleRef M) { return wrap(&unwrap(M)->getDataLayout()); } + +extern "C" void +LLVMRustSetModulePIELevel(LLVMModuleRef M) { +#if LLVM_VERSION_MINOR >= 9 + unwrap(M)->setPIELevel(PIELevel::Level::Default); +#endif +} From 12ccff99bf254fe3721ad389953eb53b723872e4 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 14 Jul 2016 19:28:54 +0200 Subject: [PATCH 198/331] Use relative path to type --- src/librustc_trans/debuginfo/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 1119ee07230e..09059cc378ac 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1030,7 +1030,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, split_name.as_ptr() as *const _) }; - fn fallback_path(scc: &::context::SharedCrateContext) -> CString { + fn fallback_path(scc: &SharedCrateContext) -> CString { CString::new(scc.link_meta().crate_name.clone()).unwrap() } } From deafab19be13e8cd33e55b211ba8835488747a05 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 14 Jul 2016 21:26:09 +0200 Subject: [PATCH 199/331] [LLVM-3.9] Increase PIELevel Previously, we had a PositionIndependentExecutable, now we simply choose the highest level. This should be equivalent. :cake: --- src/rustllvm/PassWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index edf83bf80d6d..d4ef4e807f5d 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -418,6 +418,6 @@ LLVMRustGetModuleDataLayout(LLVMModuleRef M) { extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) { #if LLVM_VERSION_MINOR >= 9 - unwrap(M)->setPIELevel(PIELevel::Level::Default); + unwrap(M)->setPIELevel(PIELevel::Level::Large); #endif } From 1bc04472609aec664ce434f7a3b7df7e06e80637 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 14 Jul 2016 21:27:14 +0200 Subject: [PATCH 200/331] [LLVM-3.9] Maintain backward compatibility in Archiver --- src/rustllvm/ArchiveWrapper.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 514d25297ee2..03b0aaf45b81 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -158,7 +158,12 @@ LLVMRustWriteArchive(char *Dst, const LLVMRustArchiveMember **NewMembers, bool WriteSymbtab, Archive::Kind Kind) { + +#if LLVM_VERSION_MINOR >= 9 std::vector Members; +#else + std::vector Members; +#endif for (size_t i = 0; i < NumMembers; i++) { auto Member = NewMembers[i]; @@ -171,6 +176,8 @@ LLVMRustWriteArchive(char *Dst, return -1; } Members.push_back(std::move(*MOrErr)); +#elif LLVM_VERSION_MINOR == 8 + Members.push_back(NewArchiveIterator(Member->filename)); #else Members.push_back(NewArchiveIterator(Member->filename, Member->name)); #endif From 1798c1aa598a03e0d4d2440d15bdb2ae242b392e Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 14 Jul 2016 23:40:14 +0200 Subject: [PATCH 201/331] Refactor determining of relocation model into methods --- src/librustc_trans/back/write.rs | 26 +++------------------ src/librustc_trans/context.rs | 39 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 4b9d5dd9e8d6..87815c63f799 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -24,6 +24,7 @@ use util::fs::link_or_copy; use errors::{self, Handler, Level, DiagnosticBuilder}; use errors::emitter::Emitter; use syntax_pos::MultiSpan; +use context::{is_pie_binary, get_reloc_model}; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -154,32 +155,11 @@ fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { } pub fn create_target_machine(sess: &Session) -> TargetMachineRef { - let reloc_model_arg = match sess.opts.cg.relocation_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.relocation_model[..], - }; - let reloc_model = match reloc_model_arg { - "pic" => llvm::RelocPIC, - "static" => llvm::RelocStatic, - "default" => llvm::RelocDefault, - "dynamic-no-pic" => llvm::RelocDynamicNoPic, - _ => { - sess.err(&format!("{:?} is not a valid relocation mode", - sess.opts - .cg - .relocation_model)); - sess.abort_if_errors(); - bug!(); - } - }; + let reloc_model = get_reloc_model(sess); let opt_level = get_llvm_opt_level(sess.opts.optimize); let use_softfp = sess.opts.cg.soft_float; - let any_library = sess.crate_types.borrow().iter().any(|ty| { - *ty != config::CrateTypeExecutable - }); - let ffunction_sections = sess.target.target.options.function_sections; let fdata_sections = ffunction_sections; @@ -220,7 +200,7 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { reloc_model, opt_level, use_softfp, - !any_library && reloc_model == llvm::RelocPIC, + is_pie_binary(sess), ffunction_sections, fdata_sections, ) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 2437fa954d18..d8b3089bc998 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -34,6 +34,7 @@ use rustc::ty::subst::{Substs, VecPerParamSpace}; use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; use session::Session; +use session::config; use symbol_map::SymbolMap; use util::sha2::Sha256; use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; @@ -322,6 +323,38 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { } } +pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { + let reloc_model_arg = match sess.opts.cg.relocation_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.relocation_model[..], + }; + + match reloc_model_arg { + "pic" => llvm::RelocPIC, + "static" => llvm::RelocStatic, + "default" => llvm::RelocDefault, + "dynamic-no-pic" => llvm::RelocDynamicNoPic, + _ => { + sess.err(&format!("{:?} is not a valid relocation mode", + sess.opts + .cg + .relocation_model)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn is_any_library(sess: &Session) -> bool { + sess.crate_types.borrow().iter().any(|ty| { + *ty != config::CrateTypeExecutable + }) +} + +pub fn is_pie_binary(sess: &Session) -> bool { + !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocPIC +} + unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); let mod_name = CString::new(mod_name).unwrap(); @@ -352,7 +385,11 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR let llvm_target = sess.target.target.llvm_target.as_bytes(); let llvm_target = CString::new(llvm_target).unwrap(); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); - llvm::LLVMRustSetModulePIELevel(llmod); + + if is_pie_binary(sess) { + llvm::LLVMRustSetModulePIELevel(llmod); + } + (llcx, llmod) } From 2bcb2b89902762dd1b2e00a7b6ae8c0566470cc1 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sat, 16 Jul 2016 17:23:00 +0200 Subject: [PATCH 202/331] Upgrade LLVM to include std::thread patch --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index a5b8261c9a0e..6e665b76d2b6 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit a5b8261c9a0ea200bc4da345ae43823989ad46ed +Subproject commit 6e665b76d2b64256a932a61ac3eeb5ce2971c185 From d0e5aa48201ec100cbd8c519f0a8de0554a84ac7 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sat, 16 Jul 2016 17:24:02 +0200 Subject: [PATCH 203/331] Upgrade compiler-rt --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index ac3d1cda612e..3c51a621bb34 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit ac3d1cda612edccb6f1da53cbf7716e248405f3b +Subproject commit 3c51a621bb34f31bcb76e8e582945a7e045ce11d From f439aeef070da498f5a75b7cf17080bde0e72738 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sat, 16 Jul 2016 19:36:51 +0200 Subject: [PATCH 204/331] [LLVM-3.9] Use old way of getting next child This was changed back in https://github.com/rust-lang/llvm/commit/aacf2fbf --- src/rustllvm/ArchiveWrapper.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 03b0aaf45b81..b6d352e4516c 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -79,7 +79,12 @@ extern "C" RustArchiveIterator* LLVMRustArchiveIteratorNew(RustArchive *ra) { Archive *ar = ra->getBinary(); RustArchiveIterator *rai = new RustArchiveIterator(); +#if LLVM_VERSION_MINOR >= 9 + Error err; + rai->cur = ar->child_begin(err); +#else rai->cur = ar->child_begin(); +#endif rai->end = ar->child_end(); return rai; } @@ -88,8 +93,8 @@ extern "C" const Archive::Child* LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { if (rai->cur == rai->end) return NULL; -#if LLVM_VERSION_MINOR >= 8 - const ErrorOr* cur = rai->cur.operator->(); +#if LLVM_VERSION_MINOR == 8 + Archive::Child* cur = rai->cur.operator->(); if (!*cur) { LLVMRustSetLastError(cur->getError().message().c_str()); return NULL; From 09c3f33ec2a5035d35307598a7e66132747ead9d Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sat, 16 Jul 2016 19:44:43 +0200 Subject: [PATCH 205/331] Flip LLVM verion check clause --- src/rustllvm/ArchiveWrapper.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index b6d352e4516c..5e8250b908c8 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -79,11 +79,11 @@ extern "C" RustArchiveIterator* LLVMRustArchiveIteratorNew(RustArchive *ra) { Archive *ar = ra->getBinary(); RustArchiveIterator *rai = new RustArchiveIterator(); -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_MINOR <= 8 + rai->cur = ar->child_begin(); +#else Error err; rai->cur = ar->child_begin(err); -#else - rai->cur = ar->child_begin(); #endif rai->end = ar->child_end(); return rai; @@ -164,10 +164,10 @@ LLVMRustWriteArchive(char *Dst, bool WriteSymbtab, Archive::Kind Kind) { -#if LLVM_VERSION_MINOR >= 9 - std::vector Members; -#else +#if LLVM_VERSION_MINOR <= 8 std::vector Members; +#else + std::vector Members; #endif for (size_t i = 0; i < NumMembers; i++) { @@ -187,15 +187,15 @@ LLVMRustWriteArchive(char *Dst, Members.push_back(NewArchiveIterator(Member->filename, Member->name)); #endif } else { -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_MINOR <= 8 + Members.push_back(NewArchiveIterator(Member->child, Member->name)); +#else Expected MOrErr = NewArchiveMember::getOldMember(Member->child, true); if (!MOrErr) { LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); return -1; } Members.push_back(std::move(*MOrErr)); -#else - Members.push_back(NewArchiveIterator(Member->child, Member->name)); #endif } } From ad262d54dce230d712a2be6db6aa59e1851769ef Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 21 Jul 2016 11:12:31 +0200 Subject: [PATCH 206/331] Update compiler-rt --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index 3c51a621bb34..8598065bd965 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit 3c51a621bb34f31bcb76e8e582945a7e045ce11d +Subproject commit 8598065bd965d9713bfafb6c1e766d63a7b17b89 From 2c92756dde884bbfa5efef9b4cbd846882a7d46e Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 21 Jul 2016 11:24:05 +0200 Subject: [PATCH 207/331] Upgrade llvm --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 6e665b76d2b6..fb2893b136c6 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 6e665b76d2b64256a932a61ac3eeb5ce2971c185 +Subproject commit fb2893b136c6a83a6f34f708fac2530d95e2db65 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1953fc5a6b48..09ce8a931748 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-06-23 +2016-07-20 From dc7076b52e2464a703de7d87fa6c60b8fc98ada9 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 21 Jul 2016 11:24:35 +0200 Subject: [PATCH 208/331] [LLVM-3.9] Pass correct relocation model flag --- configure | 5 +++++ mk/platform.mk | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/configure b/configure index d2ec457a1c8b..af29ef3d39c2 100755 --- a/configure +++ b/configure @@ -1020,6 +1020,11 @@ then err "bad LLVM version: $LLVM_VERSION, need >=3.7" ;; esac + + if "$CFG_LLVM_ROOT/bin/llvm-mc" -help | grep "-relocation-model"; then + CFG_LLVM_MC_HAS_RELOCATION_MODEL=1 + putvar CFG_LLVM_MC_HAS_RELOCATION_MODEL + fi fi # Even when the user overrides the choice of CC, still try to detect diff --git a/mk/platform.mk b/mk/platform.mk index c2644621c571..d601cab7221f 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -221,12 +221,19 @@ define CFG_MAKE_TOOLCHAIN LLVM_MC_RELOCATION_MODEL="default" endif + # LLVM changed this flag in 3.9 + ifdef CFG_LLVM_MC_HAS_RELOCATION_MODEL + LLVM_MC_RELOC_FLAG := -relocation-model=$$(LLVM_MC_RELOCATION_MODEL) + else + LLVM_MC_RELOC_FLAG := -position-independent + endif + # We're using llvm-mc as our assembler because it supports # .cfi pseudo-ops on mac CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(2) | \ $$(LLVM_MC_$$(CFG_BUILD)) \ -assemble \ - -relocation-model=$$(LLVM_MC_RELOCATION_MODEL) \ + $$(LLVM_MC_RELOC_FLAG) \ -filetype=obj \ -triple=$(1) \ -o=$$(1) From 079db4f9715ab5c495115b11adcca5f5bd4ed260 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 21 Jul 2016 11:24:51 +0200 Subject: [PATCH 209/331] Use correct error handling type --- src/rustllvm/ArchiveWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 5e8250b908c8..935052a51134 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -94,7 +94,7 @@ LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { if (rai->cur == rai->end) return NULL; #if LLVM_VERSION_MINOR == 8 - Archive::Child* cur = rai->cur.operator->(); + const ErrorOr* cur = rai->cur.operator->(); if (!*cur) { LLVMRustSetLastError(cur->getError().message().c_str()); return NULL; From 2c16e24643976523e6858fd41a1ded0429a96ef1 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sun, 24 Jul 2016 22:31:16 +0200 Subject: [PATCH 210/331] Use C type when passing value to LLVM pass Previously the C type LLVMRelocMode (available as RelocMode in Rust) was passed as is to the function. However createTargetMachine expects a Reloc::Model, which is an enum just one value short. Additionally, the function was marked as requiring Reloc::Model in the C code, but RelocMode on the Rust-side. We now use the correct C type LLVMRelocMode and convert it to an Optional as expected by the createTargetMachine call the same the original LLVMCreateTargetMachine function does. See https://github.com/llvm-mirror/llvm/blob/c9b262bfbd5b9fb6f10749dba1465569f39bd625/lib/Target/TargetMachineC.cpp#L104-L121 This was found by @eddyb. --- src/rustllvm/PassWrapper.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index d4ef4e807f5d..a1276060271b 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -167,12 +167,35 @@ LLVMRustCreateTargetMachine(const char *triple, const char *cpu, const char *feature, CodeModel::Model CM, - Reloc::Model RM, + LLVMRelocMode Reloc, CodeGenOpt::Level OptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, bool DataSections) { + +#if LLVM_VERSION_MINOR <= 8 + Reloc::Model RM; +#else + Optional RM; +#endif + switch (Reloc){ + case LLVMRelocStatic: + RM = Reloc::Static; + break; + case LLVMRelocPIC: + RM = Reloc::PIC_; + break; + case LLVMRelocDynamicNoPic: + RM = Reloc::DynamicNoPIC; + break; + default: +#if LLVM_VERSION_MINOR <= 8 + RM = Reloc::Default; +#endif + break; + } + std::string Error; Triple Trip(Triple::normalize(triple)); const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(), From a36595ed14b4ded33d207040e5bcd3da169ecc20 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Sun, 24 Jul 2016 22:34:37 +0200 Subject: [PATCH 211/331] Force check of error The passed error needs to be checked. Otherwise it will force an abort when it is deconstructed, but a success value. --- src/rustllvm/ArchiveWrapper.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 935052a51134..3d48024c8798 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -73,6 +73,9 @@ LLVMRustDestroyArchive(RustArchive *ar) { struct RustArchiveIterator { Archive::child_iterator cur; Archive::child_iterator end; +#if LLVM_VERSION_MINOR >= 9 + Error err; +#endif }; extern "C" RustArchiveIterator* @@ -82,8 +85,11 @@ LLVMRustArchiveIteratorNew(RustArchive *ra) { #if LLVM_VERSION_MINOR <= 8 rai->cur = ar->child_begin(); #else - Error err; - rai->cur = ar->child_begin(err); + rai->cur = ar->child_begin(rai->err); + if (rai->err) { + LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); + return NULL; + } #endif rai->end = ar->child_end(); return rai; @@ -91,6 +97,12 @@ LLVMRustArchiveIteratorNew(RustArchive *ra) { extern "C" const Archive::Child* LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { +#if LLVM_VERSION_MINOR >= 9 + if (rai->err) { + LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); + return NULL; + } +#endif if (rai->cur == rai->end) return NULL; #if LLVM_VERSION_MINOR == 8 From d851428cc352254aed0dd894d1a9970a228ec9ed Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 25 Jul 2016 10:20:05 -0700 Subject: [PATCH 212/331] configure: Fix grep invocation for llvm-mc argument --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index af29ef3d39c2..3e2cbcbe3644 100755 --- a/configure +++ b/configure @@ -1021,7 +1021,8 @@ then ;; esac - if "$CFG_LLVM_ROOT/bin/llvm-mc" -help | grep "-relocation-model"; then + if "$CFG_LLVM_ROOT/bin/llvm-mc" -help | grep -- "-relocation-model"; then + msg "found older llvm-mc" CFG_LLVM_MC_HAS_RELOCATION_MODEL=1 putvar CFG_LLVM_MC_HAS_RELOCATION_MODEL fi From e8f76661f13620f075626d27f94750ea94d6cf2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 25 Jul 2016 10:21:31 -0700 Subject: [PATCH 213/331] rustc: Fix data-layout for AArch64 targets Also relax the assertion whenever we have a custom LLVM root as LLVM may disagree about exact specifics. --- .../target/aarch64_linux_android.rs | 2 +- .../target/aarch64_unknown_linux_gnu.rs | 2 +- src/librustc_trans/context.rs | 20 ++++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 81be546e0c89..a5be1a227f1e 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { llvm_target: "aarch64-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), - data_layout: "e-m:e-i64:64-i128:128-n32:64-S128".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), target_os: "android".to_string(), target_env: "".to_string(), diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index aec1bae60c81..2dc9355e22f0 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_env: "gnu".to_string(), - data_layout: "e-m:e-i64:64-i128:128-n32:64-S128".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), target_os: "linux".to_string(), target_vendor: "unknown".to_string(), diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d8b3089bc998..792169b08a4c 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -370,7 +370,25 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR let data_layout = str::from_utf8(CStr::from_ptr(data_layout).to_bytes()) .ok().expect("got a non-UTF8 data-layout from LLVM"); - if sess.target.target.data_layout != data_layout { + // Unfortunately LLVM target specs change over time, and right now we + // don't have proper support to work with any more than one + // `data_layout` than the one that is in the rust-lang/rust repo. If + // this compiler is configured against a custom LLVM, we may have a + // differing data layout, even though we should update our own to use + // that one. + // + // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we + // disable this check entirely as we may be configured with something + // that has a different target layout. + // + // Unsure if this will actually cause breakage when rustc is configured + // as such. + // + // FIXME(#34960) + let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); + let custom_llvm_used = cfg_llvm_root.trim() != ""; + + if !custom_llvm_used && sess.target.target.data_layout != data_layout { bug!("data-layout for builtin `{}` target, `{}`, \ differs from LLVM default, `{}`", sess.target.target.llvm_target, From 5fa55781bd77f7a9fbdb3af8fa4e1b0cd0b1cf06 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 25 Jul 2016 13:32:59 -0700 Subject: [PATCH 214/331] test: Remove the execution-engine test We don't actually officially support this at all, and the execution engine support in LLVM we've had to gut as it's not compiling on MinGW, so just delete this test for now. --- src/test/run-make/execution-engine/Makefile | 21 -- src/test/run-make/execution-engine/test.rs | 282 -------------------- 2 files changed, 303 deletions(-) delete mode 100644 src/test/run-make/execution-engine/Makefile delete mode 100644 src/test/run-make/execution-engine/test.rs diff --git a/src/test/run-make/execution-engine/Makefile b/src/test/run-make/execution-engine/Makefile deleted file mode 100644 index 4c818cd99e2d..000000000000 --- a/src/test/run-make/execution-engine/Makefile +++ /dev/null @@ -1,21 +0,0 @@ --include ../tools.mk - -# FIXME: ignore freebsd -# This is a basic test of LLVM ExecutionEngine functionality using compiled -# Rust code built using the `rustc` crate. - -ifeq ($(filter executionengine,$(LLVM_COMPONENTS)),executionengine) - -ifneq ($(shell uname),FreeBSD) -all: - $(RUSTC) test.rs - $(call RUN,test $(RUSTC)) -else -all: - -endif - -else -all: - -endif diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs deleted file mode 100644 index b58295d47f21..000000000000 --- a/src/test/run-make/execution-engine/test.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private)] -#![feature(libc)] - -extern crate libc; -extern crate rustc; -extern crate rustc_driver; -extern crate rustc_lint; -extern crate rustc_llvm as llvm; -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}; -use std::mem::transmute; -use std::path::PathBuf; -use std::rc::Rc; -use std::thread::Builder; - -use rustc::dep_graph::DepGraph; -use rustc::hir::map as ast_map; -use rustc::middle::cstore::LinkagePreference; -use rustc::ty; -use rustc::session::config::{self, basic_options, build_configuration, Input, Options}; -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; - -fn main() { - // Currently trips an assertion on i686-msvc, presumably because the support - // in LLVM is a little young. - if cfg!(target_env = "msvc") && cfg!(target_arch = "x86") { - return - } - - let program = r#" - #[no_mangle] - pub static TEST_STATIC: i32 = 42; - "#; - - let program2 = r#" - #[no_mangle] - pub fn test_add(a: i32, b: i32) -> i32 { a + b } - "#; - - let mut path = match std::env::args().nth(2) { - Some(path) => PathBuf::from(&path), - None => panic!("missing rustc path") - }; - - // Remove two segments from rustc path to get sysroot. - path.pop(); - path.pop(); - - let mut ee = ExecutionEngine::new(program, path); - - let test_static = match ee.get_global("TEST_STATIC") { - Some(g) => g as *const i32, - None => panic!("failed to get global") - }; - - assert_eq!(unsafe { *test_static }, 42); - - ee.add_module(program2); - - let test_add: fn(i32, i32) -> i32; - - test_add = match ee.get_function("test_add") { - Some(f) => unsafe { transmute(f) }, - None => panic!("failed to get function") - }; - - assert_eq!(test_add(1, 2), 3); -} - -struct ExecutionEngine { - ee: llvm::ExecutionEngineRef, - modules: Vec, - sysroot: PathBuf, -} - -impl ExecutionEngine { - pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine { - let (llmod, deps) = compile_program(program, sysroot.clone()) - .expect("failed to compile program"); - - let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) }; - - if ee.is_null() { - panic!("Failed to create ExecutionEngine: {}", llvm_error()); - } - - let ee = ExecutionEngine{ - ee: ee, - modules: vec![llmod], - sysroot: sysroot, - }; - - ee.load_deps(&deps); - ee - } - - pub fn add_module(&mut self, program: &str) { - let (llmod, deps) = compile_program(program, self.sysroot.clone()) - .expect("failed to compile program in add_module"); - - unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); } - - self.modules.push(llmod); - self.load_deps(&deps); - } - - /// Returns a raw pointer to the named function. - pub fn get_function(&mut self, name: &str) -> Option<*const c_void> { - let s = CString::new(name.as_bytes()).unwrap(); - - for &m in &self.modules { - let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) }; - - if !fv.is_null() { - let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) }; - - assert!(!fp.is_null()); - return Some(fp); - } - } - None - } - - /// Returns a raw pointer to the named global item. - pub fn get_global(&mut self, name: &str) -> Option<*const c_void> { - let s = CString::new(name.as_bytes()).unwrap(); - - for &m in &self.modules { - let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) }; - - if !gv.is_null() { - let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) }; - - assert!(!gp.is_null()); - return Some(gp); - } - } - None - } - - /// Loads all dependencies of compiled code. - /// Expects a series of paths to dynamic library files. - fn load_deps(&self, deps: &[PathBuf]) { - for path in deps { - let s = match path.as_os_str().to_str() { - Some(s) => s, - None => panic!( - "Could not convert crate path to UTF-8 string: {:?}", path) - }; - let cs = CString::new(s).unwrap(); - - let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) }; - - if res == 0 { - panic!("Failed to load crate {:?}: {}", - path.display(), llvm_error()); - } - } - } -} - -impl Drop for ExecutionEngine { - fn drop(&mut self) { - unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) }; - } -} - -/// Returns last error from LLVM wrapper code. -fn llvm_error() -> String { - String::from_utf8_lossy( - unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() }) - .into_owned() -} - -fn build_exec_options(sysroot: PathBuf) -> Options { - let mut opts = basic_options(); - - // librustc derives sysroot from the executable name. - // Since we are not rustc, we must specify it. - opts.maybe_sysroot = Some(sysroot); - - // Prefer faster build time - opts.optimize = config::OptLevel::No; - - // Don't require a `main` function - opts.crate_types = vec![config::CrateTypeDylib]; - - opts -} - -/// Compiles input up to phase 4, translation to LLVM. -/// -/// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries -/// for crates used in the given input. -fn compile_program(input: &str, sysroot: PathBuf) - -> Option<(llvm::ModuleRef, Vec)> { - let input = Input::Str { - name: driver::anon_src(), - input: input.to_string(), - }; - let thread = Builder::new().name("compile_program".to_string()); - - let handle = thread.spawn(move || { - let opts = build_exec_options(sysroot); - let dep_graph = DepGraph::new(opts.build_dep_graph()); - let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = build_session(opts, - &dep_graph, - None, - Registry::new(&rustc::DIAGNOSTICS), - cstore.clone()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let cfg = build_configuration(&sess); - - let id = "input".to_string(); - - let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); - - let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = { - driver::phase_2_configure_and_expand( - &sess, &cstore, krate, &id, None, MakeGlobMap::No, |_| Ok(()), - ).expect("phase_2 returned `None`") - }; - - let arenas = ty::CtxtArenas::new(); - let ast_map = ast_map::map_crate(&mut hir_forest, defs); - - abort_on_err(driver::phase_3_run_analysis_passes( - &sess, ast_map, analysis, resolutions, &arenas, &id, - |tcx, mir_map, analysis, _| { - - let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis); - - let crates = tcx.sess.cstore.used_crates(LinkagePreference::RequireDynamic); - - // Collect crates used in the session. - // Reverse order finds dependencies first. - let deps = crates.into_iter().rev() - .filter_map(|(_, p)| p).collect(); - - assert_eq!(trans.modules.len(), 1); - 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; - - (modp, deps) - }), &sess) - }).unwrap(); - - match handle.join() { - Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)), - Err(_) => None - } -} From 75bcda4cf1c2d16bda20d1efb0c87b227d973180 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 25 Jul 2016 10:23:34 -0700 Subject: [PATCH 215/331] rustc: Update LLVM to the LLVM 3.9 release branch The 3.9 release of LLVM isn't out yet, but this moves us onto that branch to start tracking it. --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index fb2893b136c6..6879bb3b6ac9 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit fb2893b136c6a83a6f34f708fac2530d95e2db65 +Subproject commit 6879bb3b6ac975987250b10314e7e4069846e8c1 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 09ce8a931748..e871763a48dc 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-07-20 +2016-07-25b From 0509be1f6bc48da753d7383275d3c39591f3650c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 25 Jul 2016 15:37:12 -0700 Subject: [PATCH 216/331] Update parsing llvm-config output Now it prints full paths on MSVC, but we're only interested in path names --- src/etc/mklldeps.py | 7 +++++++ src/librustc_llvm/build.rs | 19 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 8381e4f70409..24b007576aa2 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -77,6 +77,13 @@ for lib in out.strip().replace("\n", ' ').split(' '): lib = lib.strip()[2:] elif lib[0] == '-': lib = lib.strip()[1:] + # If this actually points at a literal file then we're on MSVC which now + # prints full paths, so get just the name of the library and strip off the + # trailing ".lib" + elif os.path.exists(lib): + lib = os.path.basename(lib)[:-4] + elif lib[-4:] == '.lib': + lib = lib[:-4] f.write("#[link(name = \"" + lib + "\"") if not llvm_shared and 'LLVM' in lib: f.write(", kind = \"static\"") diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index a2c808cbcb6b..085ea240a505 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -13,7 +13,7 @@ extern crate build_helper; use std::process::Command; use std::env; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use build_helper::output; @@ -135,8 +135,17 @@ fn main() { &lib[2..] } else if lib.starts_with("-") { &lib[1..] + } else if Path::new(lib).exists() { + // On MSVC llvm-config will print the full name to libraries, but + // we're only interested in the name part + let name = Path::new(lib).file_name().unwrap().to_str().unwrap(); + name.trim_right_matches(".lib") + } else if lib.ends_with(".lib") { + // Some MSVC libraries just come up with `.lib` tacked on, so chop + // that off + lib.trim_right_matches(".lib") } else { - continue; + continue }; // Don't need or want this library, but LLVM's CMake build system @@ -145,7 +154,7 @@ fn main() { // library and it otherwise may just pull in extra dependencies on // libedit which we don't want if name == "LLVMLineEditor" { - continue; + continue } let kind = if name.starts_with("LLVM") { @@ -165,7 +174,9 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { - if is_crossed { + if lib.starts_with("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", &lib[9..]); + } else if is_crossed { if lib.starts_with("-L") { println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); From 2492d24baa57ab0364e7d94ce833e57e503434e5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 25 Jul 2016 18:36:03 -0700 Subject: [PATCH 217/331] llvm: Remove no longer existent LLVMAddTargetData binding --- src/librustc_llvm/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 4fc866752eb9..6905abc29024 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -1591,9 +1591,6 @@ extern { /// Creates target data from a target layout string. pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef; - /// Adds the target data to the given pass manager. The pass manager - /// references the target data only weakly. - pub fn LLVMAddTargetData(TD: TargetDataRef, PM: PassManagerRef); /// Number of bytes clobbered when doing a Store to *T. pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; From 330dd39bb2864648cda1dce928bf4b52f1457f09 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Thu, 7 Jul 2016 08:15:10 -0400 Subject: [PATCH 218/331] Remove NO_FILE_METADATA; always use unknown_file_metadata instead of passing 0 --- src/librustc_trans/debuginfo/metadata.rs | 14 +++++++------- src/librustc_trans/debuginfo/namespace.rs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 09059cc378ac..387f24378ce0 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -68,7 +68,6 @@ pub const UNKNOWN_LINE_NUMBER: c_uint = 0; pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; // ptr::null() doesn't work :( -pub const NO_FILE_METADATA: DIFile = (0 as DIFile); pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope); const FLAGS_NONE: c_uint = 0; @@ -616,7 +615,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unsafe { llvm::LLVMDIBuilderCreateSubroutineType( DIB(cx), - NO_FILE_METADATA, + unknown_file_metadata(cx), create_DIArray(DIB(cx), &signature_metadata[..])) }, false); @@ -653,6 +652,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); let trait_llvm_type = type_of::type_of(cx, trait_object_type); + let file_metadata = unknown_file_metadata(cx); composite_type_metadata(cx, trait_llvm_type, @@ -660,7 +660,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, &[], containing_scope, - NO_FILE_METADATA, + file_metadata, syntax_pos::DUMMY_SP) } @@ -1628,7 +1628,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), containing_scope, name.as_ptr(), - NO_FILE_METADATA, + file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(discriminant_size), bytes_to_bits(discriminant_align), @@ -1774,7 +1774,7 @@ fn set_members_of_composite_type(cx: &CrateContext, DIB(cx), composite_type_metadata, member_name.as_ptr(), - NO_FILE_METADATA, + unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(member_size), bytes_to_bits(member_align), @@ -1817,7 +1817,7 @@ fn create_struct_stub(cx: &CrateContext, DIB(cx), containing_scope, name.as_ptr(), - NO_FILE_METADATA, + unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(struct_size), bytes_to_bits(struct_align), @@ -1857,7 +1857,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, let loc = span_start(cx, span); (file_metadata(cx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) } else { - (NO_FILE_METADATA, UNKNOWN_LINE_NUMBER) + (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 167229ddfd98..736a8c1c7d70 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -10,7 +10,7 @@ // Namespace Handling. -use super::metadata::{file_metadata, NO_FILE_METADATA, UNKNOWN_LINE_NUMBER}; +use super::metadata::{file_metadata, unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{DIB, debug_context, span_start}; use llvm; @@ -74,7 +74,7 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope { let loc = span_start(ccx, span); (file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) } else { - (NO_FILE_METADATA, UNKNOWN_LINE_NUMBER) + (unknown_file_metadata(ccx), UNKNOWN_LINE_NUMBER) }; let scope = unsafe { From f38762a881255812d8ec9d7b0309b513bed9b8b5 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Wed, 27 Jul 2016 00:18:19 +0200 Subject: [PATCH 219/331] [LLVM-3.9] Use llvm-3.9 branch --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index 6879bb3b6ac9..e31fa33700cd 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 6879bb3b6ac975987250b10314e7e4069846e8c1 +Subproject commit e31fa33700cdb1a1e6964247f3d222b4b4d33ff7 From 52430727cd45611b2d308d2e57fc6b71e2c902d8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 Jul 2016 15:09:39 -0700 Subject: [PATCH 220/331] test: Fix a test on MSVC Apparently MSVC now has namespaces in backtraces! --- src/test/run-pass/backtrace.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index ad38dc8f4525..f1ce17c0736b 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -46,19 +46,7 @@ fn template(me: &str) -> Command { } fn expected(fn_name: &str) -> String { - // FIXME(#32481) - // - // On windows, we read the function name from debuginfo using some - // system APIs. For whatever reason, these APIs seem to use the - // "name" field, which is only the "relative" name, not the full - // name with namespace info, so we just see `foo` and not - // `backtrace::foo` as we see on linux (which uses the linkage - // name). - if cfg!(windows) && cfg!(target_env = "msvc") { - format!(" - {}", fn_name) - } else { - format!(" - backtrace::{}", fn_name) - } + format!(" - backtrace::{}", fn_name) } fn runtest(me: &str) { From 7c0cd30c4b49905cb9ddf83daa3acfc77906ff91 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Fri, 29 Jul 2016 10:26:56 +0200 Subject: [PATCH 221/331] Update LLVM again --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index e31fa33700cd..327e422d9b9d 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit e31fa33700cdb1a1e6964247f3d222b4b4d33ff7 +Subproject commit 327e422d9b9df5bc02d947b69d8020817b5a2bfc From 2a41b31a88356d5a772cb644ab8d29af0bf44742 Mon Sep 17 00:00:00 2001 From: Wang Xuerui Date: Fri, 29 Jul 2016 16:40:10 +0800 Subject: [PATCH 222/331] syntax_ext: format: fix ICE with bad named arguments --- src/libsyntax_ext/format.rs | 4 +++- src/test/compile-fail/ifmt-bad-arg.rs | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 94bb78edaacd..1f6f57c70f72 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -406,7 +406,9 @@ impl<'a, 'b> Context<'a, 'b> { let arg_idx = match arg_index_consumed.get_mut(i) { None => 0, // error already emitted elsewhere Some(offset) => { - let arg_idx = self.arg_index_map[i][*offset]; + let ref idx_map = self.arg_index_map[i]; + // unwrap_or branch: error already emitted elsewhere + let arg_idx = *idx_map.get(*offset).unwrap_or(&0); *offset += 1; arg_idx } diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 272ad980feb4..59c61a42e077 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -41,6 +41,12 @@ fn main() { //~^ ERROR invalid reference to argument `0` (no arguments given) //~^^ ERROR invalid reference to argument `1` (no arguments given) + // bad named arguments, #35082 + + format!("{valuea} {valueb}", valuea=5, valuec=7); + //~^ ERROR there is no argument named `valueb` + //~^^ ERROR named argument never used + // bad syntax of the format string format!("{"); //~ ERROR: expected `'}'` but string was terminated From 415fde498a561f22eb7e431b31a31906764a196b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 28 Jul 2016 05:58:45 -0400 Subject: [PATCH 223/331] intravisit: Fold functionality of IdVisitor into the regular Visitor. --- src/librustc/hir/intravisit.rs | 255 ++++++---------------- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/mod.rs | 6 +- src/librustc/lint/context.rs | 36 ++- src/librustc/middle/cstore.rs | 7 +- src/librustc/middle/effect.rs | 4 +- src/librustc/middle/liveness.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 10 +- src/librustc_incremental/calculate_svh.rs | 8 +- src/librustc_metadata/astencode.rs | 10 +- src/librustc_mir/mir_map.rs | 2 +- src/librustc_passes/consts.rs | 2 +- src/librustc_passes/rvalues.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_typeck/check/upvar.rs | 2 +- 16 files changed, 119 insertions(+), 233 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 442c85af22a2..a06fc21764de 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -94,11 +94,14 @@ pub trait Visitor<'v> : Sized { /////////////////////////////////////////////////////////////////////////// + fn visit_id(&mut self, _node_id: NodeId) { + // Nothing to do. + } fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } - fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { - walk_mod(self, m) + fn visit_mod(&mut self, m: &'v Mod, _s: Span, n: NodeId) { + walk_mod(self, m, n) } fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) @@ -135,8 +138,8 @@ pub trait Visitor<'v> : Sized { fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) { walk_where_predicate(self, predicate) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { - walk_fn(self, fk, fd, b, s) + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) { + walk_fn(self, fk, fd, b, s, id) } fn visit_trait_item(&mut self, ti: &'v TraitItem) { walk_trait_item(self, ti) @@ -157,7 +160,7 @@ pub trait Visitor<'v> : Sized { s: &'v VariantData, _: Name, _: &'v Generics, - _: NodeId, + _parent_id: NodeId, _: Span) { walk_struct_def(self, s) } @@ -225,24 +228,28 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { } pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { + visitor.visit_id(macro_def.id); visitor.visit_name(macro_def.span, macro_def.name); walk_opt_name(visitor, macro_def.span, macro_def.imported_from); walk_list!(visitor, visit_attribute, ¯o_def.attrs); } -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_id: NodeId) { + visitor.visit_id(mod_node_id); for &item_id in &module.item_ids { visitor.visit_nested_item(item_id); } } pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + visitor.visit_id(local.id); visitor.visit_pat(&local.pat); walk_list!(visitor, visit_ty, &local.ty); walk_list!(visitor, visit_expr, &local.init); } pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { + visitor.visit_id(lifetime.id); visitor.visit_name(lifetime.span, lifetime.name); } @@ -263,6 +270,7 @@ pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) where V: Visitor<'v> { + visitor.visit_id(trait_ref.ref_id); visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } @@ -271,9 +279,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_name(item.span, item.name); match item.node { ItemExternCrate(opt_name) => { + visitor.visit_id(item.id); walk_opt_name(visitor, item.span, opt_name) } ItemUse(ref vp) => { + visitor.visit_id(item.id); match vp.node { ViewPathSimple(name, ref path) => { visitor.visit_name(vp.span, name); @@ -292,6 +302,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemStatic(ref typ, _, ref expr) | ItemConst(ref typ, ref expr) => { + visitor.visit_id(item.id); visitor.visit_ty(typ); visitor.visit_expr(expr); } @@ -309,23 +320,29 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { item.id) } ItemMod(ref module) => { + // visit_mod() takes care of visiting the Item's NodeId visitor.visit_mod(module, item.span, item.id) } ItemForeignMod(ref foreign_module) => { + visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } ItemTy(ref typ, ref type_parameters) => { + visitor.visit_id(item.id); visitor.visit_ty(typ); visitor.visit_generics(type_parameters) } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); + // visit_enum_def() takes care of visiting the Item's NodeId visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } ItemDefaultImpl(_, ref trait_ref) => { + visitor.visit_id(item.id); visitor.visit_trait_ref(trait_ref) } ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { + visitor.visit_id(item.id); visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); @@ -333,9 +350,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemStruct(ref struct_definition, ref generics) => { visitor.visit_generics(generics); + visitor.visit_id(item.id); visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); } ItemTrait(_, ref generics, ref bounds, ref methods) => { + visitor.visit_id(item.id); visitor.visit_generics(generics); walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_trait_item, methods); @@ -348,6 +367,7 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, generics: &'v Generics, item_id: NodeId) { + visitor.visit_id(item_id); walk_list!(visitor, visit_variant, &enum_definition.variants, @@ -358,18 +378,20 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, generics: &'v Generics, - item_id: NodeId) { + parent_item_id: NodeId) { visitor.visit_name(variant.span, variant.node.name); visitor.visit_variant_data(&variant.node.data, variant.node.name, generics, - item_id, + parent_item_id, variant.span); walk_list!(visitor, visit_expr, &variant.node.disr_expr); walk_list!(visitor, visit_attribute, &variant.node.attrs); } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { + visitor.visit_id(typ.id); + match typ.node { TyVec(ref ty) => { visitor.visit_ty(ty) @@ -421,6 +443,7 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem) { + visitor.visit_id(item.node.id()); walk_opt_name(visitor, item.span, item.node.name()); walk_opt_name(visitor, item.span, item.node.rename()); } @@ -450,11 +473,13 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, type_binding: &'v TypeBinding) { + visitor.visit_id(type_binding.id); visitor.visit_name(type_binding.span, type_binding.name); visitor.visit_ty(&type_binding.ty); } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { + visitor.visit_id(pattern.id); match pattern.node { PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); @@ -499,6 +524,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) { + visitor.visit_id(foreign_item.id); visitor.visit_vis(&foreign_item.vis); visitor.visit_name(foreign_item.span, foreign_item.name); @@ -526,11 +552,13 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyPar pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { for param in &generics.ty_params { + visitor.visit_id(param.id); visitor.visit_name(param.span, param.name); walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); walk_list!(visitor, visit_ty, ¶m.default); } walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); + visitor.visit_id(generics.where_clause.id); walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); } @@ -557,6 +585,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>( ref path, ref ty, ..}) => { + visitor.visit_id(id); visitor.visit_path(path, id); visitor.visit_ty(ty); } @@ -571,6 +600,7 @@ pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionR pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { for argument in &function_declaration.inputs { + visitor.visit_id(argument.id); visitor.visit_pat(&argument.pat); visitor.visit_ty(&argument.ty) } @@ -579,6 +609,7 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: & pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { for argument in &function_declaration.inputs { + visitor.visit_id(argument.id); visitor.visit_ty(&argument.ty) } walk_fn_ret_ty(visitor, &function_declaration.output) @@ -600,7 +631,9 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>, function_declaration: &'v FnDecl, function_body: &'v Block, - _span: Span) { + _span: Span, + id: NodeId) { + visitor.visit_id(id); walk_fn_decl(visitor, function_declaration); walk_fn_kind(visitor, function_kind); visitor.visit_block(function_body) @@ -611,10 +644,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_list!(visitor, visit_attribute, &trait_item.attrs); match trait_item.node { ConstTraitItem(ref ty, ref default) => { + visitor.visit_id(trait_item.id); visitor.visit_ty(ty); walk_list!(visitor, visit_expr, default); } MethodTraitItem(ref sig, None) => { + visitor.visit_id(trait_item.id); visitor.visit_generics(&sig.generics); walk_fn_decl(visitor, &sig.decl); } @@ -629,6 +664,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai trait_item.id); } TypeTraitItem(ref bounds, ref default) => { + visitor.visit_id(trait_item.id); walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_ty, default); } @@ -641,6 +677,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt walk_list!(visitor, visit_attribute, &impl_item.attrs); match impl_item.node { ImplItemKind::Const(ref ty, ref expr) => { + visitor.visit_id(impl_item.id); visitor.visit_ty(ty); visitor.visit_expr(expr); } @@ -655,16 +692,19 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt impl_item.id); } ImplItemKind::Type(ref ty) => { + visitor.visit_id(impl_item.id); visitor.visit_ty(ty); } } } pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { + visitor.visit_id(struct_definition.id()); walk_list!(visitor, visit_struct_field, struct_definition.fields()); } pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { + visitor.visit_id(struct_field.id); visitor.visit_vis(&struct_field.vis); visitor.visit_name(struct_field.span, struct_field.name); visitor.visit_ty(&struct_field.ty); @@ -672,14 +712,20 @@ pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v } pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { + visitor.visit_id(block.id); walk_list!(visitor, visit_stmt, &block.stmts); walk_list!(visitor, visit_expr, &block.expr); } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { match statement.node { - StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), - StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { + StmtDecl(ref declaration, id) => { + visitor.visit_id(id); + visitor.visit_decl(declaration) + } + StmtExpr(ref expression, id) | + StmtSemi(ref expression, id) => { + visitor.visit_id(id); visitor.visit_expr(expression) } } @@ -693,6 +739,7 @@ pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { } pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { + visitor.visit_id(expression.id); match expression.node { ExprBox(ref subexpression) => { visitor.visit_expr(subexpression) @@ -815,6 +862,7 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { if let Visibility::Restricted { ref path, id } = *vis { + visitor.visit_id(id); visitor.visit_path(path, id) } } @@ -837,15 +885,16 @@ impl IdRange { self.min >= self.max } + pub fn contains(&self, id: NodeId) -> bool { + id >= self.min && id < self.max + } + pub fn add(&mut self, id: NodeId) { self.min = cmp::min(self.min, id); self.max = cmp::max(self.max, id + 1); } } -pub trait IdVisitingOperation { - fn visit_id(&mut self, node_id: NodeId); -} pub struct IdRangeComputingVisitor { pub result: IdRange, @@ -861,181 +910,12 @@ impl IdRangeComputingVisitor { } } -impl IdVisitingOperation for IdRangeComputingVisitor { +impl<'v> Visitor<'v> for IdRangeComputingVisitor { fn visit_id(&mut self, id: NodeId) { self.result.add(id); } } -pub struct IdVisitor<'a, O: 'a> { - operation: &'a mut O, - - // In general, the id visitor visits the contents of an item, but - // not including nested trait/impl items, nor other nested items. - // The base visitor itself always skips nested items, but not - // trait/impl items. This means in particular that if you start by - // visiting a trait or an impl, you should not visit the - // trait/impl items respectively. This is handled by setting - // `skip_members` to true when `visit_item` is on the stack. This - // way, if the user begins by calling `visit_trait_item`, we will - // visit the trait item, but if they begin with `visit_item`, we - // won't visit the (nested) trait items. - skip_members: bool, -} - -impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { - pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> { - IdVisitor { operation: operation, skip_members: false } - } - - fn visit_generics_helper(&mut self, generics: &Generics) { - for type_parameter in generics.ty_params.iter() { - self.operation.visit_id(type_parameter.id) - } - for lifetime in &generics.lifetimes { - self.operation.visit_id(lifetime.lifetime.id) - } - } -} - -impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { - fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { - self.operation.visit_id(node_id); - walk_mod(self, module) - } - - fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { - self.operation.visit_id(foreign_item.id); - walk_foreign_item(self, foreign_item) - } - - fn visit_item(&mut self, item: &Item) { - assert!(!self.skip_members); - self.skip_members = true; - - self.operation.visit_id(item.id); - match item.node { - ItemUse(ref view_path) => { - match view_path.node { - ViewPathSimple(_, _) | - ViewPathGlob(_) => {} - ViewPathList(_, ref paths) => { - for path in paths { - self.operation.visit_id(path.node.id()) - } - } - } - } - _ => {} - } - walk_item(self, item); - - self.skip_members = false; - } - - fn visit_local(&mut self, local: &Local) { - self.operation.visit_id(local.id); - walk_local(self, local) - } - - fn visit_block(&mut self, block: &Block) { - self.operation.visit_id(block.id); - walk_block(self, block) - } - - fn visit_stmt(&mut self, statement: &Stmt) { - self.operation.visit_id(statement.node.id()); - walk_stmt(self, statement) - } - - fn visit_pat(&mut self, pattern: &Pat) { - self.operation.visit_id(pattern.id); - walk_pat(self, pattern) - } - - fn visit_expr(&mut self, expression: &Expr) { - self.operation.visit_id(expression.id); - walk_expr(self, expression) - } - - fn visit_ty(&mut self, typ: &Ty) { - self.operation.visit_id(typ.id); - walk_ty(self, typ) - } - - fn visit_generics(&mut self, generics: &Generics) { - self.visit_generics_helper(generics); - walk_generics(self, generics) - } - - fn visit_fn(&mut self, - function_kind: FnKind<'v>, - function_declaration: &'v FnDecl, - block: &'v Block, - span: Span, - node_id: NodeId) { - self.operation.visit_id(node_id); - - match function_kind { - FnKind::ItemFn(_, generics, _, _, _, _, _) => { - self.visit_generics_helper(generics) - } - FnKind::Method(_, sig, _, _) => { - self.visit_generics_helper(&sig.generics) - } - FnKind::Closure(_) => {} - } - - for argument in &function_declaration.inputs { - self.operation.visit_id(argument.id) - } - - walk_fn(self, function_kind, function_declaration, block, span); - } - - fn visit_struct_field(&mut self, struct_field: &StructField) { - self.operation.visit_id(struct_field.id); - walk_struct_field(self, struct_field) - } - - fn visit_variant_data(&mut self, - struct_def: &VariantData, - _: Name, - _: &Generics, - _: NodeId, - _: Span) { - self.operation.visit_id(struct_def.id()); - walk_struct_def(self, struct_def); - } - - fn visit_trait_item(&mut self, ti: &TraitItem) { - if !self.skip_members { - self.operation.visit_id(ti.id); - walk_trait_item(self, ti); - } - } - - fn visit_impl_item(&mut self, ii: &ImplItem) { - if !self.skip_members { - self.operation.visit_id(ii.id); - walk_impl_item(self, ii); - } - } - - fn visit_lifetime(&mut self, lifetime: &Lifetime) { - self.operation.visit_id(lifetime.id); - } - - fn visit_lifetime_def(&mut self, def: &LifetimeDef) { - self.visit_lifetime(&def.lifetime); - } - - fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { - self.operation.visit_id(trait_ref.ref_id); - walk_trait_ref(self, trait_ref); - } -} - /// Computes the id range for a single fn body, ignoring nested items. pub fn compute_id_range_for_fn_body(fk: FnKind, decl: &FnDecl, @@ -1043,8 +923,7 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, sp: Span, id: NodeId) -> IdRange { - let mut visitor = IdRangeComputingVisitor { result: IdRange::max() }; - let mut id_visitor = IdVisitor::new(&mut visitor); - id_visitor.visit_fn(fk, decl, body, sp, id); - id_visitor.operation.result + let mut visitor = IdRangeComputingVisitor::new(); + visitor.visit_fn(fk, decl, body, sp, id); + visitor.result() } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 693d7a2edfca..b3f222b22e89 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -197,7 +197,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, b: &'ast Block, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); - intravisit::walk_fn(self, fk, fd, b, s); + intravisit::walk_fn(self, fk, fd, b, s, id); } fn visit_block(&mut self, block: &'ast Block) { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 655f80ec0723..20bf4f7d3edb 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1362,9 +1362,9 @@ pub enum ViewPath_ { /// TraitRef's appear in impls. /// /// resolve maps each TraitRef's ref_id to its defining trait; that's all -/// that the ref_id is for. The impl_id maps to the "self type" of this impl. -/// If this impl is an ItemImpl, the impl_id is redundant (it could be the -/// same as the impl's node id). +/// that the ref_id is for. Note that ref_id's value is not the NodeId of the +/// trait being referred to but just a unique NodeId that serves as a key +/// within the DefMap. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TraitRef { pub path: Path, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ce3d72de9ae9..a55957c4d193 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -45,7 +45,6 @@ use syntax_pos::Span; use errors::DiagnosticBuilder; use hir; use hir::intravisit as hir_visit; -use hir::intravisit::{IdVisitor, IdVisitingOperation}; use syntax::visit as ast_visit; /// Information about the registered lints. @@ -663,9 +662,11 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { } fn visit_ids(&mut self, f: F) - where F: FnOnce(&mut IdVisitor) + where F: FnOnce(&mut IdVisitor) { - let mut v = IdVisitor::new(self); + let mut v = IdVisitor { + cx: self + }; f(&mut v); } } @@ -779,7 +780,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, body: &'v hir::Block, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); - hir_visit::walk_fn(self, fk, decl, body, span); + hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); } @@ -820,7 +821,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) { run_lints!(self, check_mod, late_passes, m, s, n); - hir_visit::walk_mod(self, m); + hir_visit::walk_mod(self, m, n); run_lints!(self, check_mod_post, late_passes, m, s, n); } @@ -859,7 +860,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, late_passes, trait_item); - cx.visit_ids(|v| v.visit_trait_item(trait_item)); + cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item)); hir_visit::walk_trait_item(cx, trait_item); run_lints!(cx, check_trait_item_post, late_passes, trait_item); }); @@ -868,7 +869,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, late_passes, impl_item); - cx.visit_ids(|v| v.visit_impl_item(impl_item)); + cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item)); hir_visit::walk_impl_item(cx, impl_item); run_lints!(cx, check_impl_item_post, late_passes, impl_item); }); @@ -1046,16 +1047,30 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { } } +struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> { + cx: &'a mut LateContext<'b, 'tcx> +} + // Output any lints that were previously added to the session. -impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> { +impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { + fn visit_id(&mut self, id: ast::NodeId) { - if let Some(lints) = self.sess().lints.borrow_mut().remove(&id) { + if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); for (lint_id, span, msg) in lints { - self.span_lint(lint_id.lint, span, &msg[..]) + self.cx.span_lint(lint_id.lint, span, &msg[..]) } } } + + fn visit_trait_item(&mut self, _ti: &hir::TraitItem) { + // Do not recurse into trait or impl items automatically. These are + // processed separately by calling hir_visit::walk_trait_item() + } + + fn visit_impl_item(&mut self, _ii: &hir::ImplItem) { + // See visit_trait_item() + } } enum CheckLintNameResult { @@ -1172,7 +1187,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Visit the whole crate. cx.with_lint_attrs(&krate.attrs, |cx| { - cx.visit_id(ast::CRATE_NODE_ID); cx.visit_ids(|v| { hir_visit::walk_crate(v, krate); }); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index fd9463b13c05..484aacfd9ecc 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -44,7 +44,7 @@ use syntax::parse::token::InternedString; use syntax_pos::Span; use rustc_back::target::Target; use hir; -use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor}; +use hir::intravisit::Visitor; pub use self::DefLike::{DlDef, DlField, DlImpl}; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; @@ -292,11 +292,6 @@ impl InlinedItem { InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii), } } - - pub fn visit_ids(&self, operation: &mut O) { - let mut id_visitor = IdVisitor::new(operation); - self.visit(&mut id_visitor); - } } // FIXME: find a better place for this? diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 6fe98119c706..446767ecbcab 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl, - block: &'v hir::Block, span: Span, _: ast::NodeId) { + block: &'v hir::Block, span: Span, id: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { FnKind::ItemFn(_, _, unsafety, _, _, _, _) => @@ -96,7 +96,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { self.unsafe_context = UnsafeContext::new(SafeContext) } - intravisit::walk_fn(self, fn_kind, fn_decl, block, span); + intravisit::walk_fn(self, fn_kind, fn_decl, block, span, id); self.unsafe_context = old_unsafe_context } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ea3765c76f89..1222b5f42a19 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -390,7 +390,7 @@ fn visit_fn(ir: &mut IrMaps, // gather up the various local variables, significant expressions, // and so forth: - intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp); + intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp, id); // Special nodes and variables: // - exit_ln represents the end of the fn, either by return or panic diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e86120b73bf9..1fe47cd48538 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -197,7 +197,7 @@ fn borrowck_fn(this: &mut BorrowckCtxt, decl, body); - intravisit::walk_fn(this, fk, decl, body, sp); + intravisit::walk_fn(this, fk, decl, body, sp, id); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 915a0cf0bdc7..d3952de2fbe3 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -34,7 +34,7 @@ use std::iter::{FromIterator, IntoIterator, repeat}; use rustc::hir; use rustc::hir::{Pat, PatKind}; -use rustc::hir::intravisit::{self, IdVisitor, IdVisitingOperation, Visitor, FnKind}; +use rustc::hir::intravisit::{self, Visitor, FnKind}; use rustc_back::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; @@ -474,7 +474,7 @@ struct RenamingRecorder<'map> { renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId> } -impl<'map> IdVisitingOperation for RenamingRecorder<'map> { +impl<'v, 'map> Visitor<'v> for RenamingRecorder<'map> { fn visit_id(&mut self, node_id: NodeId) { let key = (node_id, self.origin_span); self.renaming_map.insert(key, self.substituted_node_id); @@ -529,9 +529,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { renaming_map: renaming_map, }; - let mut id_visitor = IdVisitor::new(&mut renaming_recorder); - - id_visitor.visit_expr(const_expr); + renaming_recorder.visit_expr(const_expr); } } } @@ -1049,7 +1047,7 @@ fn check_fn(cx: &mut MatchCheckCtxt, _ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id), } - intravisit::walk_fn(cx, kind, decl, body, sp); + intravisit::walk_fn(cx, kind, decl, body, sp, fn_id); for input in &decl.inputs { check_irrefutable(cx, &input.pat, true); diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index 7b1e0d2d0c8b..f9fa5154e20f 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -384,9 +384,9 @@ mod svh_visitor { SawItem.hash(self.st); visit::walk_item(self, i) } - fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) { + 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) + SawMod.hash(self.st); visit::walk_mod(self, m, n) } fn visit_decl(&mut self, d: &'a Decl) { @@ -405,9 +405,9 @@ mod svh_visitor { } fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, - b: &'a Block, s: Span, _: NodeId) { + b: &'a Block, s: Span, n: NodeId) { debug!("visit_fn: st={:?}", self.st); - SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s) + SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n) } fn visit_trait_item(&mut self, ti: &'a TraitItem) { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 2e8c5a7c2341..454c805ab577 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -18,7 +18,7 @@ use rustc::session::Session; use rustc::hir; use rustc::hir::fold; use rustc::hir::fold::Folder; -use rustc::hir::intravisit::{IdRange, IdRangeComputingVisitor, IdVisitingOperation}; +use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; use common as c; use cstore; @@ -693,7 +693,7 @@ struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w: &'a mut Encoder<'b>, } -impl<'a, 'b, 'c, 'tcx> IdVisitingOperation for +impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> { fn visit_id(&mut self, id: ast::NodeId) { encode_side_tables_for_id(self.ecx, self.rbml_w, id) @@ -704,7 +704,7 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext, rbml_w: &mut Encoder, ii: &InlinedItem) { rbml_w.start_tag(c::tag_table as usize); - ii.visit_ids(&mut SideTableEncodingIdVisitor { + ii.visit(&mut SideTableEncodingIdVisitor { ecx: ecx, rbml_w: rbml_w }); @@ -1242,9 +1242,9 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { } } -fn inlined_item_id_range(v: &InlinedItem) -> IdRange { +fn inlined_item_id_range(ii: &InlinedItem) -> IdRange { let mut visitor = IdRangeComputingVisitor::new(); - v.visit_ids(&mut visitor); + ii.visit(&mut visitor); visitor.result() } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index b7c5f35892b0..11d6b0779275 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { build::construct_fn(cx, id, arguments, fn_sig.output, body) }); - intravisit::walk_fn(self, fk, decl, body, span); + intravisit::walk_fn(self, fk, decl, body, span, id); } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b0ba38f1db67..1030a4b0116d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -158,7 +158,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { let qualif = self.with_mode(mode, |this| { this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b)); - intravisit::walk_fn(this, fk, fd, b, s); + intravisit::walk_fn(this, fk, fd, b, s, fn_id); this.qualif }); diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index 4684683f0250..2a5dc50cae92 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx); euv.walk_fn(fd, b); }); - intravisit::walk_fn(self, fk, fd, b, s) + intravisit::walk_fn(self, fk, fd, b, s, fn_id) } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index acaf9b9b2fae..793e52d37920 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } } - intravisit::walk_mod(self, m); + intravisit::walk_mod(self, m, id); } fn visit_macro_def(&mut self, md: &'v hir::MacroDef) { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 702dd5f8de58..6fdbc3282bcc 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -503,7 +503,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> { span: Span, id: ast::NodeId) { - intravisit::walk_fn(self, fn_kind, decl, body, span); + intravisit::walk_fn(self, fn_kind, decl, body, span, id); self.analyze_closure(id, span, decl, body); } } From e805cb6374550190f8b3c4582fe67ae40d5b7a16 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 29 Jul 2016 14:32:35 +0200 Subject: [PATCH 224/331] Add io::Error doc examples --- src/libstd/io/error.rs | 145 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 05ae8ed5b0b6..63016a1a7959 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -208,6 +208,14 @@ impl Error { /// This function reads the value of `errno` for the target platform (e.g. /// `GetLastError` on Windows) and will return a corresponding instance of /// `Error` for the error code. + /// + /// # Examples + /// + /// ``` + /// use std::io::Error; + /// + /// println!("last OS error: {:?}", Error::last_os_error()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn last_os_error() -> Error { Error::from_raw_os_error(sys::os::errno() as i32) @@ -248,6 +256,27 @@ impl Error { /// If this `Error` was constructed via `last_os_error` or /// `from_raw_os_error`, then this function will return `Some`, otherwise /// it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_os_error(err: &Error) { + /// if let Some(raw_os_err) = err.raw_os_error() { + /// println!("raw OS error: {:?}", raw_os_err); + /// } else { + /// println!("Not an OS error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "raw OS error: ...". + /// print_os_error(&Error::last_os_error()); + /// // Will print "Not an OS error". + /// print_os_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn raw_os_error(&self) -> Option { match self.repr { @@ -260,6 +289,27 @@ impl Error { /// /// If this `Error` was constructed via `new` then this function will /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {:?}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { match self.repr { @@ -273,6 +323,63 @@ impl Error { /// /// If this `Error` was constructed via `new` then this function will /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// use std::{error, fmt}; + /// use std::fmt::Display; + /// + /// #[derive(Debug)] + /// struct MyError { + /// v: String, + /// } + /// + /// impl MyError { + /// fn new() -> MyError { + /// MyError { + /// v: "oh no!".to_owned() + /// } + /// } + /// + /// fn change_message(&mut self, new_message: &str) { + /// self.v = new_message.to_owned(); + /// } + /// } + /// + /// impl error::Error for MyError { + /// fn description(&self) -> &str { &self.v } + /// } + /// + /// impl Display for MyError { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "MyError: {}", &self.v) + /// } + /// } + /// + /// fn change_error(mut err: Error) -> Error { + /// if let Some(inner_err) = err.get_mut() { + /// inner_err.downcast_mut::().unwrap().change_message("I've been changed!"); + /// } + /// err + /// } + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&change_error(Error::last_os_error())); + /// // Will print "Inner error: ...". + /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); + /// } + /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { match self.repr { @@ -285,6 +392,27 @@ impl Error { /// /// If this `Error` was constructed via `new` then this function will /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// if let Some(inner_err) = err.into_inner() { + /// println!("Inner error: {}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] pub fn into_inner(self) -> Option> { match self.repr { @@ -294,6 +422,23 @@ impl Error { } /// Returns the corresponding `ErrorKind` for this error. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// println!("{:?}", err.kind()); + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { match self.repr { From aad5f6f912298bd0a4cc1dea698b652f81badd29 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 30 Jul 2016 00:53:18 +0200 Subject: [PATCH 225/331] Add doc example for io::Stderr --- src/libstd/io/stdio.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c4b573db5f2d..a25bc038b7ba 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -505,6 +505,21 @@ impl Stderr { /// /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Write` trait for writing data. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// + /// fn foo() -> io::Result<()> { + /// let stderr = io::stderr(); + /// let mut handle = stderr.lock(); + /// + /// try!(handle.write(b"hello world")); + /// + /// Ok(()) + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StderrLock { StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } From 451683f0eec360bf4adbec5c19be764b7fac79e4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 30 Jul 2016 00:56:14 +0200 Subject: [PATCH 226/331] Add doc example for Stdin --- src/libstd/io/stdio.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index a25bc038b7ba..d7566d5c9a4f 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -240,6 +240,21 @@ impl Stdin { /// /// [`Read`]: trait.Read.html /// [`BufRead`]: trait.BufRead.html + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Read}; + /// + /// # fn foo() -> io::Result { + /// let mut buffer = String::new(); + /// let stdin = io::stdin(); + /// let mut handle = stdin.lock(); + /// + /// try!(handle.read_to_string(&mut buffer)); + /// # Ok(buffer) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdinLock { StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } From aeb3af898ae426031376a345f91e04bfc7af32f8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 30 Jul 2016 00:57:20 +0200 Subject: [PATCH 227/331] Add doc example for Stdout --- src/libstd/io/stdio.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d7566d5c9a4f..b8b66a58359e 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -414,6 +414,21 @@ impl Stdout { /// /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Write` trait for writing data. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// + /// # fn foo() -> io::Result<()> { + /// let stdout = io::stdout(); + /// let mut handle = stdout.lock(); + /// + /// try!(handle.write(b"hello world")); + /// + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdoutLock { StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } From 2bed205d3be05682b84693edeed4d84d850eb801 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 30 Jul 2016 13:30:41 +0200 Subject: [PATCH 228/331] Add io::Take doc example --- src/libstd/io/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index d5b255ee5737..3d1ee5b7ae7c 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1482,6 +1482,24 @@ impl Take { /// /// This instance may reach EOF after reading fewer bytes than indicated by /// this method if the underlying `Read` instance reaches EOF. + /// + /// # Examples + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let f = try!(File::open("foo.txt")); + /// + /// // read at most five bytes + /// let handle = f.take(5); + /// + /// println!("limit: {}", handle.limit()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } } From fda473f00fa07b9a8246b104396f9922e54bff16 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 30 Jul 2016 13:37:52 +0200 Subject: [PATCH 229/331] Add urls in std::io types --- src/libstd/io/error.rs | 8 +++++++- src/libstd/io/mod.rs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 63016a1a7959..5333b0a531ea 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -55,7 +55,9 @@ pub type Result = result::Result; /// /// Errors mostly originate from the underlying OS, but custom instances of /// `Error` can be created with crafted error messages and a particular value of -/// `ErrorKind`. +/// [`ErrorKind`]. +/// +/// [`ErrorKind`]: enum.ErrorKind.html #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Error { @@ -77,6 +79,10 @@ struct Custom { /// /// This list is intended to grow over time and it is not recommended to /// exhaustively match against it. +/// +/// It is used with the [`io::Error`] type. +/// +/// [`io::Error`]: struct.Error.html #[derive(Copy, PartialEq, Eq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 3d1ee5b7ae7c..88fd4186e0a2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1082,16 +1082,22 @@ pub trait Seek { /// /// If the seek operation completed successfully, /// this method returns the new position from the start of the stream. - /// That position can be used later with `SeekFrom::Start`. + /// That position can be used later with [`SeekFrom::Start`]. /// /// # Errors /// /// Seeking to a negative offset is considered an error. + /// + /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start #[stable(feature = "rust1", since = "1.0.0")] fn seek(&mut self, pos: SeekFrom) -> Result; } /// Enumeration of possible methods to seek within an I/O object. +/// +/// It is used by the [`Seek`] trait. +/// +/// [`Seek`]: trait.Seek.html #[derive(Copy, PartialEq, Eq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SeekFrom { From 03652157f9da55ea58debabe22bb7105ef8ebdf7 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sun, 31 Jul 2016 00:58:30 +0900 Subject: [PATCH 230/331] Suppress unused type parameter error when type has error field --- src/librustc/ty/util.rs | 15 +++++++++++++++ src/librustc_typeck/check/wfcheck.rs | 5 +++++ src/test/compile-fail/issue-35075.rs | 19 +++++++++++++++++++ .../resolve-type-param-in-item-in-trait.rs | 11 ++++------- 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/issue-35075.rs diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 21c14e6fe4c3..fadf36471555 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -182,6 +182,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pat_util::arm_contains_ref_binding(arm) } + pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + for field in def.all_fields() { + let field_ty = field.ty(self, substs); + if let TyError = field_ty.sty { + return true; + } + } + } + _ => () + } + false + } + /// Returns the type of element at index `i` in tuple or tuple-like type `t`. /// For an enum `t`, `variant` is None only if `t` is a univariant enum. pub fn positional_element_ty(self, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 907cb734c2ff..34a91b22981e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -454,6 +454,11 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { item: &hir::Item, ast_generics: &hir::Generics) { + let ty = self.tcx().node_id_to_type(item.id); + if self.tcx().has_error_field(ty) { + return; + } + let item_def_id = self.tcx().map.local_def_id(item.id); let ty_predicates = self.tcx().lookup_predicates(item_def_id); let variances = self.tcx().item_variances(item_def_id); diff --git a/src/test/compile-fail/issue-35075.rs b/src/test/compile-fail/issue-35075.rs new file mode 100644 index 000000000000..a70452dcbd09 --- /dev/null +++ b/src/test/compile-fail/issue-35075.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Bar { + inner: Foo //~ ERROR type name `Foo` is undefined or not in scope +} + +enum Baz { + Foo(Foo) //~ ERROR type name `Foo` is undefined or not in scope +} + +fn main() {} diff --git a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs index 30ff1ed0e26f..a1572b856664 100644 --- a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs +++ b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs @@ -13,9 +13,8 @@ // scope (in this case, the enum). trait TraitA { - fn outer(self) { + fn outer(&self) { enum Foo { - //~^ ERROR parameter `B` is never used Variance(A) //~^ ERROR can't use type parameters from outer function } @@ -23,23 +22,21 @@ trait TraitA { } trait TraitB { - fn outer(self) { + fn outer(&self) { struct Foo(A); //~^ ERROR can't use type parameters from outer function - //~^^ ERROR parameter `B` is never used } } trait TraitC { - fn outer(self) { + fn outer(&self) { struct Foo { a: A } //~^ ERROR can't use type parameters from outer function - //~^^ ERROR parameter `B` is never used } } trait TraitD { - fn outer(self) { + fn outer(&self) { fn foo(a: A) { } //~^ ERROR can't use type parameters from outer function } From 57cad5722db3043804bc4c38ec3b456e9ff497be Mon Sep 17 00:00:00 2001 From: Timon Van Overveldt Date: Wed, 27 Apr 2016 18:02:31 -0700 Subject: [PATCH 231/331] Update gcc crate dependency to 0.3.27. This is to pull in changes to support ARM MUSL targets. This change also commits a couple of other cargo-generated changes to other dependencies in the various Cargo.toml files. --- src/bootstrap/Cargo.lock | 12 ++++++------ src/liballoc_jemalloc/Cargo.toml | 2 +- src/libflate/Cargo.toml | 2 +- src/librustc_llvm/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/libstd/Cargo.toml | 2 +- src/rustc/std_shim/Cargo.lock | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 1290f2a404b2..02698d6f7a12 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -7,8 +7,8 @@ dependencies = [ "filetime 0.1.10 (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)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -33,7 +33,7 @@ name = "filetime" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -53,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "kernel32-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -62,7 +62,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -75,7 +75,7 @@ name = "num_cpus" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 768a0c2c0a54..25b3c8a3a0a8 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -16,7 +16,7 @@ libc = { path = "../rustc/libc_shim" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3.17" +gcc = "0.3.27" [features] debug = [] diff --git a/src/libflate/Cargo.toml b/src/libflate/Cargo.toml index 52aa6bb86ef9..5423da9c81c0 100644 --- a/src/libflate/Cargo.toml +++ b/src/libflate/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["dylib"] [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index 05d20911a5dc..f97daa22ff66 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -17,4 +17,4 @@ rustc_bitflags = { path = "../librustc_bitflags" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index a41d3b0253a3..3e510bdc9002 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -28,4 +28,4 @@ log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index b442d21b72ba..3ce6841fdd4c 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -24,7 +24,7 @@ unwind = { path = "../libunwind" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" [features] backtrace = [] diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index bad46966ffa6..70aef55d799c 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -18,7 +18,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -49,7 +49,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -101,7 +101,7 @@ dependencies = [ "build_helper 0.1.0", "collections 0.0.0", "core 0.0.0", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", From f7247d1071206db45103c994b0077fcb0d8f75cf Mon Sep 17 00:00:00 2001 From: Timon Van Overveldt Date: Wed, 27 Apr 2016 18:02:31 -0700 Subject: [PATCH 232/331] Add ARM MUSL targets. The targets are: - `arm-unknown-linux-musleabi` - `arm-unknown-linux-musleabihf` - `armv7-unknown-linux-musleabihf` These mirror the existing `gnueabi` targets. All of these targets produce fully static binaries, similar to the x86 MUSL targets. For now these targets can only be used with `--rustbuild` builds, as https://github.com/rust-lang/compiler-rt/pull/22 only made the necessary compiler-rt changes in the CMake configs, not the plain GNU Make configs. I've tested these targets GCC 5.3.0 compiled again musl-1.1.12 (downloaded from http://musl.codu.org/). An example `./configure` invocation is: ``` ./configure \ --enable-rustbuild --target=arm-unknown-linux-musleabi \ --musl-root="$MUSL_ROOT" ``` where `MUSL_ROOT` points to the `arm-linux-musleabi` prefix. Usually that path will be of the form `/foobar/arm-linux-musleabi/arm-linux-musleabi`. Usually the cross-compile toolchain will live under `/foobar/arm-linux-musleabi/bin`. That path should either by added to your `PATH` variable, or you should add a section to your `config.toml` as follows: ``` [target.arm-unknown-linux-musleabi] cc = "/foobar/arm-linux-musleabi/bin/arm-linux-musleabi-gcc" cxx = "/foobar/arm-linux-musleabi/bin/arm-linux-musleabi-g++" ``` As a prerequisite you'll also have to put a cross-compiled static `libunwind.a` library in `$MUSL_ROOT/lib`. This is similar to [how the x86_64 MUSL targets are built] (https://doc.rust-lang.org/book/advanced-linking.html). --- configure | 2 +- mk/cfg/arm-unknown-linux-musleabi.mk | 3 + mk/cfg/arm-unknown-linux-musleabihf.mk | 3 + mk/cfg/armv7-unknown-linux-musleabihf.mk | 3 + src/bootstrap/compile.rs | 3 +- src/bootstrap/sanity.rs | 2 +- src/liballoc_jemalloc/build.rs | 11 ++- src/liballoc_jemalloc/lib.rs | 4 +- .../target/arm_unknown_linux_musleabi.rs | 33 +++++++++ .../target/arm_unknown_linux_musleabihf.rs | 33 +++++++++ .../target/armv7_unknown_linux_musleabihf.rs | 34 +++++++++ src/librustc_back/target/mod.rs | 4 ++ src/librustc_back/target/musl_base.rs | 72 +++++++++++++++++++ src/libstd/rtdeps.rs | 4 +- src/libstd/sys/unix/thread.rs | 8 ++- 15 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 mk/cfg/arm-unknown-linux-musleabi.mk create mode 100644 mk/cfg/arm-unknown-linux-musleabihf.mk create mode 100644 mk/cfg/armv7-unknown-linux-musleabihf.mk create mode 100644 src/librustc_back/target/arm_unknown_linux_musleabi.rs create mode 100644 src/librustc_back/target/arm_unknown_linux_musleabihf.rs create mode 100644 src/librustc_back/target/armv7_unknown_linux_musleabihf.rs create mode 100644 src/librustc_back/target/musl_base.rs diff --git a/configure b/configure index d2ec457a1c8b..a7e24a506fbe 100755 --- a/configure +++ b/configure @@ -1192,7 +1192,7 @@ do ;; - x86_64-*-musl) + x86_64-*-musl | arm-*-musleabi) if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ] then err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found" diff --git a/mk/cfg/arm-unknown-linux-musleabi.mk b/mk/cfg/arm-unknown-linux-musleabi.mk new file mode 100644 index 000000000000..8120250150d4 --- /dev/null +++ b/mk/cfg/arm-unknown-linux-musleabi.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. \ No newline at end of file diff --git a/mk/cfg/arm-unknown-linux-musleabihf.mk b/mk/cfg/arm-unknown-linux-musleabihf.mk new file mode 100644 index 000000000000..8120250150d4 --- /dev/null +++ b/mk/cfg/arm-unknown-linux-musleabihf.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. \ No newline at end of file diff --git a/mk/cfg/armv7-unknown-linux-musleabihf.mk b/mk/cfg/armv7-unknown-linux-musleabihf.mk new file mode 100644 index 000000000000..8120250150d4 --- /dev/null +++ b/mk/cfg/armv7-unknown-linux-musleabihf.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. \ No newline at end of file diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 8ec9c7f0109f..061192ebd134 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -92,8 +92,7 @@ pub fn std_link(build: &Build, } add_to_sysroot(&out_dir, &libdir); - if target.contains("musl") && - (target.contains("x86_64") || target.contains("i686")) { + if target.contains("musl") && !target.contains("mips") { copy_third_party_objects(build, target, &libdir); } } diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 737492467589..09f96782e718 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -109,7 +109,7 @@ pub fn check(build: &mut Build) { } // Make sure musl-root is valid if specified - if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { + if target.contains("musl") && !target.contains("mips") { match build.config.musl_root { Some(ref root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index d1b3583d256b..dc1b8d6ea983 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -73,7 +73,16 @@ fn main() { .replace("\\", "/")) .current_dir(&build_dir) .env("CC", compiler.path()) - .env("EXTRA_CFLAGS", cflags) + .env("EXTRA_CFLAGS", cflags.clone()) + // jemalloc generates Makefile deps using GCC's "-MM" flag. This means + // that GCC will run the preprocessor, and only the preprocessor, over + // jemalloc's source files. If we don't specify CPPFLAGS, then at least + // on ARM that step fails with a "Missing implementation for 32-bit + // atomic operations" error. This is because no "-march" flag will be + // passed to GCC, and then GCC won't define the + // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to + // select an atomic operation implementation. + .env("CPPFLAGS", cflags.clone()) .env("AR", &ar) .env("RANLIB", format!("{} s", ar.display())); diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 347e97e6ffc0..ccf3d978fe43 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -36,7 +36,9 @@ use libc::{c_int, c_void, size_t}; #[cfg_attr(target_os = "android", link(name = "gcc"))] #[cfg_attr(all(not(windows), not(target_os = "android"), - not(target_env = "musl")), + not(target_env = "musl"), + not(target_env = "musleabi"), + not(target_env = "musleabihf")), link(name = "pthread"))] #[cfg(not(cargobuild))] extern "C" {} diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs new file mode 100644 index 000000000000..906f60f1c9a1 --- /dev/null +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -0,0 +1,33 @@ +// 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 target::Target; + +pub fn target() -> Target { + let mut base = super::musl_base::opts(); + + // Most of these settings are copied from the arm_unknown_linux_gnueabi + // target. + base.features = "+v6".to_string(); + Target { + // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it + // to determine the calling convention and float ABI, and it doesn't + // support the "musleabi" value. + llvm_target: "arm-unknown-linux-gnueabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musleabi".to_string(), + target_vendor: "unknown".to_string(), + options: base, + } +} diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs new file mode 100644 index 000000000000..3051721b8c21 --- /dev/null +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -0,0 +1,33 @@ +// 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 target::Target; + +pub fn target() -> Target { + let mut base = super::musl_base::opts(); + + // Most of these settings are copied from the arm_unknown_linux_gnueabihf + // target. + base.features = "+v6,+vfp2".to_string(); + Target { + // It's important we use "gnueabihf" and not "musleabihf" here. LLVM + // uses it to determine the calling convention and float ABI, and it + // doesn't support the "musleabihf" value. + llvm_target: "arm-unknown-linux-gnueabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musleabi".to_string(), + target_vendor: "unknown".to_string(), + options: base, + } +} diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs new file mode 100644 index 000000000000..8732681fb492 --- /dev/null +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::Target; + +pub fn target() -> Target { + let mut base = super::musl_base::opts(); + + // Most of these settings are copied from the armv7_unknown_linux_gnueabihf + // target. + base.features = "+v7,+vfp3,+neon".to_string(); + base.cpu = "cortex-a8".to_string(); + Target { + // It's important we use "gnueabihf" and not "musleabihf" here. LLVM + // uses it to determine the calling convention and float ABI, and LLVM + // doesn't support the "musleabihf" value. + llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musleabi".to_string(), + target_vendor: "unknown".to_string(), + options: base, + } +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index f5314809228b..694b1340bbbf 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -59,6 +59,7 @@ mod freebsd_base; mod linux_base; mod linux_musl_base; mod openbsd_base; +mod musl_base; mod netbsd_base; mod solaris_base; mod windows_base; @@ -134,7 +135,10 @@ supported_targets! { ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), + ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), + ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), + ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), ("i686-unknown-linux-musl", i686_unknown_linux_musl), diff --git a/src/librustc_back/target/musl_base.rs b/src/librustc_back/target/musl_base.rs new file mode 100644 index 000000000000..77cf015e1d9b --- /dev/null +++ b/src/librustc_back/target/musl_base.rs @@ -0,0 +1,72 @@ +// 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 target::TargetOptions; + +pub fn opts() -> TargetOptions { + let mut base = super::linux_base::opts(); + + // Make sure that the linker/gcc really don't pull in anything, including + // default objects, libs, etc. + base.pre_link_args.push("-nostdlib".to_string()); + base.pre_link_args.push("-static".to_string()); + + // At least when this was tested, the linker would not add the + // `GNU_EH_FRAME` program header to executables generated, which is required + // when unwinding to locate the unwinding information. I'm not sure why this + // argument is *not* necessary for normal builds, but it can't hurt! + base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string()); + + // There's a whole bunch of circular dependencies when dealing with MUSL + // unfortunately. To put this in perspective libc is statically linked to + // liblibc and libunwind is statically linked to libstd: + // + // * libcore depends on `fmod` which is in libc (transitively in liblibc). + // liblibc, however, depends on libcore. + // * compiler-rt has personality symbols that depend on libunwind, but + // libunwind is in libstd which depends on compiler-rt. + // + // Recall that linkers discard libraries and object files as much as + // possible, and with all the static linking and archives flying around with + // MUSL the linker is super aggressively stripping out objects. For example + // the first case has fmod stripped from liblibc (it's in its own object + // file) so it's not there when libcore needs it. In the second example all + // the unused symbols from libunwind are stripped (each is in its own object + // file in libstd) before we end up linking compiler-rt which depends on + // those symbols. + // + // To deal with these circular dependencies we just force the compiler to + // link everything as a group, not stripping anything out until everything + // is processed. The linker will still perform a pass to strip out object + // files but it won't do so until all objects/archives have been processed. + base.pre_link_args.push("-Wl,-(".to_string()); + base.post_link_args.push("-Wl,-)".to_string()); + + // When generating a statically linked executable there's generally some + // small setup needed which is listed in these files. These are provided by + // a musl toolchain and are linked by default by the `musl-gcc` script. Note + // that `gcc` also does this by default, it just uses some different files. + // + // Each target directory for musl has these object files included in it so + // they'll be included from there. + base.pre_link_objects_exe.push("crt1.o".to_string()); + base.pre_link_objects_exe.push("crti.o".to_string()); + base.post_link_objects.push("crtn.o".to_string()); + + // MUSL support doesn't currently include dynamic linking, so there's no + // need for dylibs or rpath business. Additionally `-pie` is incompatible + // with `-static`, so we can't pass `-pie`. + base.dynamic_linking = false; + base.has_rpath = false; + base.position_independent_executables = false; + + return base; +} + diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index a11200873d50..f23ac32f51c3 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -19,7 +19,9 @@ // // On Linux, librt and libdl are indirect dependencies via std, // and binutils 2.22+ won't add them automatically -#[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[cfg(all(target_os = "linux", not(any(target_env = "musl", + target_env = "musleabi", + target_env = "musleabihf"))))] #[link(name = "dl")] #[link(name = "pthread")] extern {} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 1061ca87f647..7f05aec4e6ea 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -171,7 +171,9 @@ impl Drop for Thread { } } -#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))), +#[cfg(all(not(all(target_os = "linux", not(any(target_env = "musl", + target_env = "musleabi", + target_env = "musleabihf")))), not(target_os = "freebsd"), not(target_os = "macos"), not(target_os = "bitrig"), @@ -185,7 +187,9 @@ pub mod guard { } -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), +#[cfg(any(all(target_os = "linux", not(any(target_env = "musl", + target_env = "musleabi", + target_env = "musleabihf"))), target_os = "freebsd", target_os = "macos", target_os = "bitrig", From 9ffd0fe5a75b8eb640f0bd94385c7b5f675c7e95 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 26 Jul 2016 16:17:14 -0500 Subject: [PATCH 233/331] arm-musl targets now use cfg(env = "musl") --- .gitmodules | 2 +- src/liballoc_jemalloc/lib.rs | 4 +--- src/liblibc | 2 +- src/librustc_back/target/arm_unknown_linux_musleabi.rs | 2 +- src/librustc_back/target/arm_unknown_linux_musleabihf.rs | 2 +- .../target/armv7_unknown_linux_musleabihf.rs | 2 +- src/libstd/rtdeps.rs | 4 +--- src/libstd/sys/unix/thread.rs | 8 ++------ 8 files changed, 9 insertions(+), 17 deletions(-) diff --git a/.gitmodules b/.gitmodules index 39288a7ae490..61697a37960e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,4 +16,4 @@ url = https://github.com/rust-lang/rust-installer.git [submodule "src/liblibc"] path = src/liblibc - url = https://github.com/rust-lang/libc.git + url = https://github.com/japaric/libc.git diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index ccf3d978fe43..347e97e6ffc0 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -36,9 +36,7 @@ use libc::{c_int, c_void, size_t}; #[cfg_attr(target_os = "android", link(name = "gcc"))] #[cfg_attr(all(not(windows), not(target_os = "android"), - not(target_env = "musl"), - not(target_env = "musleabi"), - not(target_env = "musleabihf")), + not(target_env = "musl")), link(name = "pthread"))] #[cfg(not(cargobuild))] extern "C" {} diff --git a/src/liblibc b/src/liblibc index b0d62534d48b..23a5092adcec 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit b0d62534d48b711c8978d1bbe8cca0558ae7b1cb +Subproject commit 23a5092adcecc8c755e7887337e52f357353cad7 diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 906f60f1c9a1..f2dff16a2842 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -26,7 +26,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), target_os: "linux".to_string(), - target_env: "musleabi".to_string(), + target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, } diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index 3051721b8c21..89da0213198b 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -26,7 +26,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), target_os: "linux".to_string(), - target_env: "musleabi".to_string(), + target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, } diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index 8732681fb492..3b9ac8e21f2e 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -27,7 +27,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), target_os: "linux".to_string(), - target_env: "musleabi".to_string(), + target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, } diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index f23ac32f51c3..c2572dfa5e15 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -19,9 +19,7 @@ // // On Linux, librt and libdl are indirect dependencies via std, // and binutils 2.22+ won't add them automatically -#[cfg(all(target_os = "linux", not(any(target_env = "musl", - target_env = "musleabi", - target_env = "musleabihf"))))] +#[cfg(all(target_os = "linux", not(any(target_env = "musl"))))] #[link(name = "dl")] #[link(name = "pthread")] extern {} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 7f05aec4e6ea..65ebce0baa28 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -171,9 +171,7 @@ impl Drop for Thread { } } -#[cfg(all(not(all(target_os = "linux", not(any(target_env = "musl", - target_env = "musleabi", - target_env = "musleabihf")))), +#[cfg(all(not(all(target_os = "linux", not(any(target_env = "musl")))), not(target_os = "freebsd"), not(target_os = "macos"), not(target_os = "bitrig"), @@ -187,9 +185,7 @@ pub mod guard { } -#[cfg(any(all(target_os = "linux", not(any(target_env = "musl", - target_env = "musleabi", - target_env = "musleabihf"))), +#[cfg(any(all(target_os = "linux", not(any(target_env = "musl"))), target_os = "freebsd", target_os = "macos", target_os = "bitrig", From e50bcf340423f1c738c4781cd5c5df4f404a9169 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 26 Jul 2016 19:27:43 -0500 Subject: [PATCH 234/331] arm-musl: set max_atomic_width --- src/librustc_back/target/arm_unknown_linux_musleabi.rs | 1 + src/librustc_back/target/arm_unknown_linux_musleabihf.rs | 1 + src/librustc_back/target/armv7_unknown_linux_musleabihf.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index f2dff16a2842..825fc45f2be6 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -16,6 +16,7 @@ pub fn target() -> Target { // Most of these settings are copied from the arm_unknown_linux_gnueabi // target. base.features = "+v6".to_string(); + base.max_atomic_width = 64; Target { // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it // to determine the calling convention and float ABI, and it doesn't diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index 89da0213198b..6694c6a2795b 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -16,6 +16,7 @@ pub fn target() -> Target { // Most of these settings are copied from the arm_unknown_linux_gnueabihf // target. base.features = "+v6,+vfp2".to_string(); + base.max_atomic_width = 64; Target { // It's important we use "gnueabihf" and not "musleabihf" here. LLVM // uses it to determine the calling convention and float ABI, and it diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index 3b9ac8e21f2e..a7ef70edf481 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -17,6 +17,7 @@ pub fn target() -> Target { // target. base.features = "+v7,+vfp3,+neon".to_string(); base.cpu = "cortex-a8".to_string(); + base.max_atomic_width = 64; Target { // It's important we use "gnueabihf" and not "musleabihf" here. LLVM // uses it to determine the calling convention and float ABI, and LLVM From f0ec906d186a87b4b4c08b71a82f0e8803a110df Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 26 Jul 2016 20:09:50 -0500 Subject: [PATCH 235/331] arm-musl: statically link to libunwind --- src/libunwind/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ebe6fd54799e..fd446f5a4f94 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -16,7 +16,7 @@ fn main() { let target = env::var("TARGET").unwrap(); if target.contains("linux") { - if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { + if target.contains("musl") && !target.contains("mips") { println!("cargo:rustc-link-lib=static=unwind"); } else if !target.contains("android") { println!("cargo:rustc-link-lib=gcc_s"); From b38953709d75178db30020c29be0cb4ff2e4be5b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 26 Jul 2016 21:30:02 -0500 Subject: [PATCH 236/331] rustc_back/target: remove musl_base it's the same as linux_musl_base --- .../target/arm_unknown_linux_musleabi.rs | 2 +- .../target/arm_unknown_linux_musleabihf.rs | 2 +- .../target/armv7_unknown_linux_musleabihf.rs | 2 +- src/librustc_back/target/mod.rs | 1 - src/librustc_back/target/musl_base.rs | 72 ------------------- 5 files changed, 3 insertions(+), 76 deletions(-) delete mode 100644 src/librustc_back/target/musl_base.rs diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 825fc45f2be6..4bc363d0ffda 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -11,7 +11,7 @@ use target::Target; pub fn target() -> Target { - let mut base = super::musl_base::opts(); + let mut base = super::linux_musl_base::opts(); // Most of these settings are copied from the arm_unknown_linux_gnueabi // target. diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index 6694c6a2795b..d96f7443dd9c 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -11,7 +11,7 @@ use target::Target; pub fn target() -> Target { - let mut base = super::musl_base::opts(); + let mut base = super::linux_musl_base::opts(); // Most of these settings are copied from the arm_unknown_linux_gnueabihf // target. diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index a7ef70edf481..6cb75cbf04cb 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -11,7 +11,7 @@ use target::Target; pub fn target() -> Target { - let mut base = super::musl_base::opts(); + let mut base = super::linux_musl_base::opts(); // Most of these settings are copied from the armv7_unknown_linux_gnueabihf // target. diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 694b1340bbbf..ecfbeaca3517 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -59,7 +59,6 @@ mod freebsd_base; mod linux_base; mod linux_musl_base; mod openbsd_base; -mod musl_base; mod netbsd_base; mod solaris_base; mod windows_base; diff --git a/src/librustc_back/target/musl_base.rs b/src/librustc_back/target/musl_base.rs deleted file mode 100644 index 77cf015e1d9b..000000000000 --- a/src/librustc_back/target/musl_base.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use target::TargetOptions; - -pub fn opts() -> TargetOptions { - let mut base = super::linux_base::opts(); - - // Make sure that the linker/gcc really don't pull in anything, including - // default objects, libs, etc. - base.pre_link_args.push("-nostdlib".to_string()); - base.pre_link_args.push("-static".to_string()); - - // At least when this was tested, the linker would not add the - // `GNU_EH_FRAME` program header to executables generated, which is required - // when unwinding to locate the unwinding information. I'm not sure why this - // argument is *not* necessary for normal builds, but it can't hurt! - base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string()); - - // There's a whole bunch of circular dependencies when dealing with MUSL - // unfortunately. To put this in perspective libc is statically linked to - // liblibc and libunwind is statically linked to libstd: - // - // * libcore depends on `fmod` which is in libc (transitively in liblibc). - // liblibc, however, depends on libcore. - // * compiler-rt has personality symbols that depend on libunwind, but - // libunwind is in libstd which depends on compiler-rt. - // - // Recall that linkers discard libraries and object files as much as - // possible, and with all the static linking and archives flying around with - // MUSL the linker is super aggressively stripping out objects. For example - // the first case has fmod stripped from liblibc (it's in its own object - // file) so it's not there when libcore needs it. In the second example all - // the unused symbols from libunwind are stripped (each is in its own object - // file in libstd) before we end up linking compiler-rt which depends on - // those symbols. - // - // To deal with these circular dependencies we just force the compiler to - // link everything as a group, not stripping anything out until everything - // is processed. The linker will still perform a pass to strip out object - // files but it won't do so until all objects/archives have been processed. - base.pre_link_args.push("-Wl,-(".to_string()); - base.post_link_args.push("-Wl,-)".to_string()); - - // When generating a statically linked executable there's generally some - // small setup needed which is listed in these files. These are provided by - // a musl toolchain and are linked by default by the `musl-gcc` script. Note - // that `gcc` also does this by default, it just uses some different files. - // - // Each target directory for musl has these object files included in it so - // they'll be included from there. - base.pre_link_objects_exe.push("crt1.o".to_string()); - base.pre_link_objects_exe.push("crti.o".to_string()); - base.post_link_objects.push("crtn.o".to_string()); - - // MUSL support doesn't currently include dynamic linking, so there's no - // need for dylibs or rpath business. Additionally `-pie` is incompatible - // with `-static`, so we can't pass `-pie`. - base.dynamic_linking = false; - base.has_rpath = false; - base.position_independent_executables = false; - - return base; -} - From ea009939904021aaba59f9ca8038b646a65a27d6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 27 Jul 2016 11:37:15 -0500 Subject: [PATCH 237/331] remove some `any`s that are no longer necessary --- src/libstd/rtdeps.rs | 2 +- src/libstd/sys/unix/thread.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index c2572dfa5e15..a11200873d50 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -19,7 +19,7 @@ // // On Linux, librt and libdl are indirect dependencies via std, // and binutils 2.22+ won't add them automatically -#[cfg(all(target_os = "linux", not(any(target_env = "musl"))))] +#[cfg(all(target_os = "linux", not(target_env = "musl")))] #[link(name = "dl")] #[link(name = "pthread")] extern {} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 65ebce0baa28..1061ca87f647 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -171,7 +171,7 @@ impl Drop for Thread { } } -#[cfg(all(not(all(target_os = "linux", not(any(target_env = "musl")))), +#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))), not(target_os = "freebsd"), not(target_os = "macos"), not(target_os = "bitrig"), @@ -185,7 +185,7 @@ pub mod guard { } -#[cfg(any(all(target_os = "linux", not(any(target_env = "musl"))), +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", target_os = "macos", target_os = "bitrig", From 87fa075dbae4496c94559f4009c58938e7affc4b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 27 Jul 2016 11:39:58 -0500 Subject: [PATCH 238/331] point the libc submodule back to rust-lang/libc --- .gitmodules | 2 +- src/liblibc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 61697a37960e..39288a7ae490 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,4 +16,4 @@ url = https://github.com/rust-lang/rust-installer.git [submodule "src/liblibc"] path = src/liblibc - url = https://github.com/japaric/libc.git + url = https://github.com/rust-lang/libc.git diff --git a/src/liblibc b/src/liblibc index 23a5092adcec..5066b7dcab7e 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 23a5092adcecc8c755e7887337e52f357353cad7 +Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b From eb6173806d972b839711139ae107dda690febe3a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 30 Jul 2016 15:44:59 -0500 Subject: [PATCH 239/331] return TargetResult --- src/librustc_back/target/arm_unknown_linux_musleabi.rs | 8 ++++---- src/librustc_back/target/arm_unknown_linux_musleabihf.rs | 8 ++++---- .../target/armv7_unknown_linux_musleabihf.rs | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 4bc363d0ffda..028c91eadaeb 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.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(); // Most of these settings are copied from the arm_unknown_linux_gnueabi // target. base.features = "+v6".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it // to determine the calling convention and float ABI, and it doesn't // support the "musleabi" value. @@ -30,5 +30,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index d96f7443dd9c..c7dda186f425 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.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(); // Most of these settings are copied from the arm_unknown_linux_gnueabihf // target. base.features = "+v6,+vfp2".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { // It's important we use "gnueabihf" and not "musleabihf" here. LLVM // uses it to determine the calling convention and float ABI, and it // doesn't support the "musleabihf" value. @@ -30,5 +30,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index 6cb75cbf04cb..e40704e5d499 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.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::linux_musl_base::opts(); // Most of these settings are copied from the armv7_unknown_linux_gnueabihf @@ -18,7 +18,7 @@ pub fn target() -> Target { base.features = "+v7,+vfp3,+neon".to_string(); base.cpu = "cortex-a8".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { // It's important we use "gnueabihf" and not "musleabihf" here. LLVM // uses it to determine the calling convention and float ABI, and LLVM // doesn't support the "musleabihf" value. @@ -31,5 +31,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } From 661b4f09fb8d765292521f618bcb8d79da544154 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sun, 12 Jun 2016 17:46:43 -0700 Subject: [PATCH 240/331] diagnostically note source of overruling outer forbid When we emit E0453 (lint level attribute overruled by outer `forbid` lint level), it could be helpful to note where the `forbid` level was set, for the convenience of users who, e.g., believe that the correct fix is to weaken the `forbid` to `deny`. --- src/librustc/lint/context.rs | 22 ++++++++++++++----- .../lint-plugin-forbid-attrs.rs | 2 ++ src/test/compile-fail/lint-forbid-attr.rs | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 357276e31f5b..daac315e14de 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -29,7 +29,7 @@ use dep_graph::DepNode; use middle::privacy::AccessLevels; use ty::TyCtxt; use session::{config, early_error, Session}; -use lint::{Level, LevelSource, Lint, LintId, LintPass}; +use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource}; use lint::{EarlyLintPassObject, LateLintPassObject}; use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; @@ -599,13 +599,23 @@ pub trait LintContext: Sized { }; for (lint_id, level, span) in v { - let now = self.lints().get_level_source(lint_id).0; + let (now, now_source) = self.lints().get_level_source(lint_id); if now == Forbid && level != Forbid { let lint_name = lint_id.as_str(); - span_err!(self.sess(), span, E0453, - "{}({}) overruled by outer forbid({})", - level.as_str(), lint_name, - lint_name); + let mut diag_builder = struct_span_err!(self.sess(), span, E0453, + "{}({}) overruled by outer forbid({})", + level.as_str(), lint_name, + lint_name); + match now_source { + LintSource::Default => &mut diag_builder, + LintSource::Node(forbid_source_span) => { + diag_builder.span_note(forbid_source_span, + "`forbid` lint level set here") + }, + LintSource::CommandLine => { + diag_builder.note("`forbid` lint level was set on command line") + } + }.emit() } else if now != level { let src = self.lints().get_level_source(lint_id).1; self.level_stack().push((lint_id, (now, src))); diff --git a/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs index 83c845bfdf96..61a8ee88a708 100644 --- a/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs @@ -14,6 +14,8 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] #![forbid(test_lint)] +//~^ NOTE lint level defined here +//~| NOTE `forbid` lint level set here fn lintme() { } //~ ERROR item is named 'lintme' diff --git a/src/test/compile-fail/lint-forbid-attr.rs b/src/test/compile-fail/lint-forbid-attr.rs index fcc8fb6f933b..fd2513c5a066 100644 --- a/src/test/compile-fail/lint-forbid-attr.rs +++ b/src/test/compile-fail/lint-forbid-attr.rs @@ -9,6 +9,7 @@ // except according to those terms. #![forbid(deprecated)] +//~^ NOTE `forbid` lint level set here #[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated) fn main() { From 2eea1f3097a303378b2cd2870fecde853bb884b3 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 30 Jul 2016 23:21:48 -0400 Subject: [PATCH 241/331] Rewrite `slice::chunks` doc example to not require printing. --- src/libcollections/slice.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ccef6c02f9d2..ff2b8cdea227 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -577,15 +577,13 @@ impl [T] { /// /// # Example /// - /// Print the slice two elements at a time (i.e. `[1,2]`, - /// `[3,4]`, `[5]`): - /// - /// ```rust - /// let v = &[1, 2, 3, 4, 5]; - /// - /// for chunk in v.chunks(2) { - /// println!("{:?}", chunk); - /// } + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] From 443f1ca83c8b323d530ba62ed1974a75f94e0e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 30 Jul 2016 13:06:49 +0200 Subject: [PATCH 242/331] Suggest use of `--print target-list` when target is not found. If given target could not be found suggest using `--print target-list`. Previously, error has been reported as: $ rustc --target x86-unknown-linux-gnu error: Error loading target specification: Could not find specification for target "x86-unknown-linux-gnu" After changes it looks as follows: rustc --target x86-unknown-linux-gnu error: Error loading target specification: Could not find specification for target "x86-unknown-linux-gnu" help: Use `--print target-list` for a list of built-in targets --- src/librustc/session/config.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 690395399efa..34df476e5c82 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -30,7 +30,7 @@ use syntax::parse; use syntax::parse::token::InternedString; use syntax::feature_gate::UnstableFeatures; -use errors::{ColorConfig, Handler}; +use errors::{ColorConfig, FatalError, Handler}; use getopts; use std::collections::HashMap; @@ -836,7 +836,10 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { let target = match Target::search(&opts.target_triple) { Ok(t) => t, Err(e) => { - panic!(sp.fatal(&format!("Error loading target specification: {}", e))); + sp.struct_fatal(&format!("Error loading target specification: {}", e)) + .help("Use `--print target-list` for a list of built-in targets") + .emit(); + panic!(FatalError); } }; From b77b9b72fe5eb4f7c157816d109b220ab3f2de2c Mon Sep 17 00:00:00 2001 From: Jonathan Giddy Date: Sun, 31 Jul 2016 12:43:39 +0100 Subject: [PATCH 243/331] Provide more explicit example of wildcard version in guessing game doc. Beginners may try to adapt the tutorial to develop their own code. When using different dependencies, they may use the wildcard for versioning. Since they are new to the language, they will not know that the wildcard asterisk is a string, not a token. Make the correct format more explicit, to remove one potential source of frustration. --- src/doc/book/guessing-game.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index 6ce75efd1031..22cf6068e4d5 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -365,7 +365,7 @@ numbers. A bare number like above is actually shorthand for `^0.3.0`, meaning "anything compatible with 0.3.0". If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` (note the two equal signs). -And if we wanted to use the latest version we could use `*`. +And if we wanted to use the latest version we could use `rand="*"`. We could also use a range of versions. [Cargo’s documentation][cargodoc] contains more details. From a80d329b68f88da4f35a4c05337b5ae0920c20c4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 13 Jul 2016 17:07:11 +0300 Subject: [PATCH 244/331] Don't gate methods `Fn(Mut,Once)::call(mut,once)` with feature `unboxed_closures` They are already gated with feature `fn_traits` --- src/libcollections/lib.rs | 1 - src/libcoretest/lib.rs | 1 - src/librustc_driver/lib.rs | 1 - src/librustc_typeck/check/callee.rs | 29 +------ src/librustc_typeck/diagnostics.rs | 84 +------------------ .../bound-lifetime-constrained.rs | 1 - .../cache/wasm-issue-32330.rs | 1 - .../borrowck-call-is-borrow-issue-12224.rs | 2 - .../borrowck/borrowck-unboxed-closures.rs | 2 - ...ture-gate-unboxed-closures-method-calls.rs | 6 +- ...eature-gate-unboxed-closures-ufcs-calls.rs | 8 +- src/test/compile-fail/fn-trait-formatting.rs | 1 - src/test/compile-fail/issue-16939.rs | 2 - src/test/compile-fail/issue-17033.rs | 2 - src/test/compile-fail/issue-17545.rs | 2 - src/test/compile-fail/issue-17551.rs | 2 - src/test/compile-fail/issue-18532.rs | 2 - src/test/compile-fail/issue-19521.rs | 2 - src/test/compile-fail/issue-19707.rs | 1 - src/test/compile-fail/issue-4335.rs | 2 - ...ased-on-type-no-recursive-stack-closure.rs | 2 - .../regionck-unboxed-closure-lifetimes.rs | 2 - .../regions-escape-unboxed-closure.rs | 2 - ...regions-return-ref-to-upvar-issue-17403.rs | 2 - .../compile-fail/regions-steal-closure.rs | 2 - .../unboxed-closure-immutable-capture.rs | 2 - .../compile-fail/unboxed-closure-region.rs | 2 - ...unboxed-closure-sugar-nonexistent-trait.rs | 2 - .../unboxed-closures-borrow-conflict.rs | 2 - ...nfer-argument-types-two-region-pointers.rs | 2 - ...-closures-infer-explicit-call-too-early.rs | 2 - .../unboxed-closures-type-mismatch.rs | 2 - .../unboxed-closures-unsafe-extern-fn.rs | 2 - .../unboxed-closures-wrong-abi.rs | 2 - ...boxed-closures-wrong-arg-type-extern-fn.rs | 2 - .../var-captured-in-sendable-closure.rs | 2 +- .../var-captured-in-stack-closure.rs | 2 +- src/test/run-pass/assignability-trait.rs | 3 - .../associated-types-impl-redirect.rs | 2 +- ...iated-types-where-clause-impl-ambiguity.rs | 2 +- src/test/run-pass/auxiliary/issue-18711.rs | 1 - .../auxiliary/unboxed-closures-cross-crate.rs | 2 - .../run-pass/bare-fn-implements-fn-mut.rs | 2 - .../borrowck/borrowck-move-by-capture-ok.rs | 1 - .../capture-clauses-unboxed-closures.rs | 3 - .../closure-bounds-can-capture-chan.rs | 2 - src/test/run-pass/closure-reform.rs | 2 - src/test/run-pass/hashmap-memory.rs | 2 +- src/test/run-pass/hrtb-parse.rs | 1 - .../hrtb-precedence-of-plus-where-clause.rs | 2 - src/test/run-pass/hrtb-precedence-of-plus.rs | 1 - .../hrtb-trait-object-paren-notation.rs | 3 - .../run-pass/hrtb-unboxed-closure-trait.rs | 2 - src/test/run-pass/issue-10718.rs | 2 - src/test/run-pass/issue-16560.rs | 2 - src/test/run-pass/issue-16668.rs | 1 - src/test/run-pass/issue-16774.rs | 1 - src/test/run-pass/issue-17816.rs | 2 - src/test/run-pass/issue-18652.rs | 3 - src/test/run-pass/issue-18685.rs | 2 - src/test/run-pass/issue-18711.rs | 2 - src/test/run-pass/issue-19127.rs | 2 - src/test/run-pass/issue-19135.rs | 2 - src/test/run-pass/mir_trans_calls.rs | 2 +- src/test/run-pass/trait-bounds-in-arc.rs | 1 - src/test/run-pass/type-id-higher-rank.rs | 2 +- .../run-pass/unboxed-closures-all-traits.rs | 3 +- .../unboxed-closures-blanket-fn-mut.rs | 3 +- .../run-pass/unboxed-closures-blanket-fn.rs | 3 +- src/test/run-pass/unboxed-closures-boxed.rs | 1 - src/test/run-pass/unboxed-closures-by-ref.rs | 3 - .../unboxed-closures-call-fn-autoderef.rs | 3 - .../unboxed-closures-call-sugar-autoderef.rs | 3 - ...ed-closures-call-sugar-object-autoderef.rs | 1 - .../unboxed-closures-call-sugar-object.rs | 1 - .../unboxed-closures-counter-not-moved.rs | 1 - .../unboxed-closures-direct-sugary-call.rs | 2 - src/test/run-pass/unboxed-closures-drop.rs | 3 - .../run-pass/unboxed-closures-extern-fn.rs | 4 - ...unboxed-closures-fn-as-fnmut-and-fnonce.rs | 1 - .../unboxed-closures-fnmut-as-fnonce.rs | 1 - src/test/run-pass/unboxed-closures-generic.rs | 2 - ...oxed-closures-infer-fnmut-calling-fnmut.rs | 1 - .../unboxed-closures-infer-fnmut-move.rs | 1 - .../run-pass/unboxed-closures-infer-fnmut.rs | 1 - .../run-pass/unboxed-closures-infer-kind.rs | 3 - .../run-pass/unboxed-closures-infer-upvar.rs | 1 - .../run-pass/unboxed-closures-move-mutable.rs | 1 - ...ures-move-some-upvars-in-by-ref-closure.rs | 1 - src/test/run-pass/unboxed-closures-simple.rs | 3 - .../unboxed-closures-single-word-env.rs | 3 - .../unboxed-closures-static-call-fn-once.rs | 2 - .../run-pass/unboxed-closures-sugar-object.rs | 2 - .../unboxed-closures-unique-type-id.rs | 3 - .../run-pass/unboxed-closures-zero-args.rs | 2 - .../where-clauses-unboxed-closures.rs | 2 - 96 files changed, 20 insertions(+), 282 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 7fc6e54d69f7..21387a1aa955 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -49,7 +49,6 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(step_by)] -#![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] #![feature(unsafe_no_drop_flag)] diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index ef0042808f98..9428b4096bfe 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -31,7 +31,6 @@ #![feature(step_by)] #![feature(test)] #![feature(try_from)] -#![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 766e3883f266..f49d47fb0815 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -31,7 +31,6 @@ #![feature(set_stdio)] #![feature(staged_api)] #![feature(question_mark)] -#![feature(unboxed_closures)] extern crate arena; extern crate flate; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 9c6727ebbfcf..bd2c05ba66d4 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -27,33 +27,8 @@ use rustc::hir; /// to `trait_id` (this only cares about the trait, not the specific /// method that is called) pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) { - let tcx = ccx.tcx; - let did = Some(trait_id); - let li = &tcx.lang_items; - - if did == li.drop_trait() { - span_err!(tcx.sess, span, E0040, "explicit use of destructor method"); - } else if !tcx.sess.features.borrow().unboxed_closures { - // the #[feature(unboxed_closures)] feature isn't - // activated so we need to enforce the closure - // restrictions. - - let method = if did == li.fn_trait() { - "call" - } else if did == li.fn_mut_trait() { - "call_mut" - } else if did == li.fn_once_trait() { - "call_once" - } else { - return // not a closure method, everything is OK. - }; - - struct_span_err!(tcx.sess, span, E0174, - "explicit use of unboxed closure method `{}` is experimental", - method) - .help("add `#![feature(unboxed_closures)]` to the crate \ - attributes to enable") - .emit(); + if ccx.tcx.lang_items.drop_trait() == Some(trait_id) { + span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method"); } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 500f624ea3f7..cd2259a28346 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1944,89 +1944,6 @@ To learn more about traits, take a look at the Book: https://doc.rust-lang.org/book/traits.html "##, -E0174: r##" -This error occurs because of the explicit use of unboxed closure methods -that are an experimental feature in current Rust version. - -Example of erroneous code: - -```compile_fail -fn foo(mut f: F) { - f.call(("call",)); - // error: explicit use of unboxed closure method `call` - f.call_mut(("call_mut",)); - // error: explicit use of unboxed closure method `call_mut` - f.call_once(("call_once",)); - // error: explicit use of unboxed closure method `call_once` -} - -fn bar(text: &str) { - println!("Calling {} it works!", text); -} - -fn main() { - foo(bar); -} -``` - -Rust's implementation of closures is a bit different than other languages. -They are effectively syntax sugar for traits `Fn`, `FnMut` and `FnOnce`. -To understand better how the closures are implemented see here: -https://doc.rust-lang.org/book/closures.html#closure-implementation - -To fix this you can call them using parenthesis, like this: `foo()`. -When you execute the closure with parenthesis, under the hood you are executing -the method `call`, `call_mut` or `call_once`. However, using them explicitly is -currently an experimental feature. - -Example of an implicit call: - -``` -fn foo(f: F) { - f("using ()"); // Calling using () it works! -} - -fn bar(text: &str) { - println!("Calling {} it works!", text); -} - -fn main() { - foo(bar); -} -``` - -To enable the explicit calls you need to add `#![feature(unboxed_closures)]`. - -This feature is still unstable so you will also need to add -`#![feature(fn_traits)]`. -More details about this issue here: -https://github.com/rust-lang/rust/issues/29625 - -Example of use: - -``` -#![feature(fn_traits)] -#![feature(unboxed_closures)] - -fn foo(mut f: F) { - f.call(("call",)); // Calling 'call' it works! - f.call_mut(("call_mut",)); // Calling 'call_mut' it works! - f.call_once(("call_once",)); // Calling 'call_once' it works! -} - -fn bar(text: &str) { - println!("Calling '{}' it works!", text); -} - -fn main() { - foo(bar); -} -``` - -To see more about closures take a look here: -https://doc.rust-lang.org/book/closures.html` -"##, - E0178: r##" In types, the `+` type operator has low precedence, so it is often necessary to use parentheses. @@ -4049,6 +3966,7 @@ register_diagnostics! { E0167, // E0168, // E0173, // manual implementations of unboxed closure traits are experimental +// E0174, E0182, E0183, // E0187, // can't infer the kind of the closure diff --git a/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs index f60f06b4ec83..de6ce798d635 100644 --- a/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs +++ b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs @@ -12,7 +12,6 @@ #![allow(dead_code)] #![feature(rustc_attrs)] -#![feature(unboxed_closures)] #![deny(hr_lifetime_in_assoc_type)] trait Foo<'a> { diff --git a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs index 01db4770a38b..6ba09acc0e79 100644 --- a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs +++ b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs @@ -13,7 +13,6 @@ #![allow(dead_code, unused_variables)] #![deny(hr_lifetime_in_assoc_type)] -#![feature(unboxed_closures)] use std::str::Chars; diff --git a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs b/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs index 7626f354eb46..e4ae565fe92f 100644 --- a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs @@ -10,8 +10,6 @@ // Ensure that invoking a closure counts as a unique immutable borrow -#![feature(unboxed_closures)] - type Fn<'a> = Box; struct Test<'a> { diff --git a/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs b/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs index 1c12ca9c1de7..0f9829ab259a 100644 --- a/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs +++ b/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls, unboxed_closures)] - fn a isize>(mut f: F) { let g = &mut f; f(1, 2); //~ ERROR cannot borrow `f` as immutable diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs index eea1f61d6397..253d1633b1c4 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs @@ -11,9 +11,9 @@ #![allow(dead_code)] fn foo(mut f: F) { - f.call(()); //~ ERROR explicit use of unboxed closure method `call` - f.call_mut(()); //~ ERROR explicit use of unboxed closure method `call_mut` - f.call_once(()); //~ ERROR explicit use of unboxed closure method `call_once` + f.call(()); //~ ERROR use of unstable library feature 'fn_traits' + f.call_mut(()); //~ ERROR use of unstable library feature 'fn_traits' + f.call_once(()); //~ ERROR use of unstable library feature 'fn_traits' } fn main() {} diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs index f15c5c4da2c4..902b3c1774c1 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs @@ -10,10 +10,10 @@ #![allow(dead_code)] -fn foo(mut f: F, mut g: F) { - Fn::call(&g, ()); //~ ERROR explicit use of unboxed closure method `call` - FnMut::call_mut(&mut g, ()); //~ ERROR explicit use of unboxed closure method `call_mut` - FnOnce::call_once(g, ()); //~ ERROR explicit use of unboxed closure method `call_once` +fn foo(mut f: F) { + Fn::call(&f, ()); //~ ERROR use of unstable library feature 'fn_traits' + FnMut::call_mut(&mut f, ()); //~ ERROR use of unstable library feature 'fn_traits' + FnOnce::call_once(f, ()); //~ ERROR use of unstable library feature 'fn_traits' } fn main() {} diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index fd140cd1d391..e01a0412cef4 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] #![feature(box_syntax)] fn needs_fn(x: F) where F: Fn(isize) -> isize {} diff --git a/src/test/compile-fail/issue-16939.rs b/src/test/compile-fail/issue-16939.rs index 7ec3fef5c878..e16c58b8a6c1 100644 --- a/src/test/compile-fail/issue-16939.rs +++ b/src/test/compile-fail/issue-16939.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls, unboxed_closures)] - // Make sure we don't ICE when making an overloaded call with the // wrong arity. diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs index f0fe01b41597..0ec05b941a96 100644 --- a/src/test/compile-fail/issue-17033.rs +++ b/src/test/compile-fail/issue-17033.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls)] - fn f<'r>(p: &'r mut fn(p: &mut ())) { (*p)(()) //~ ERROR mismatched types //~| expected type `&mut ()` diff --git a/src/test/compile-fail/issue-17545.rs b/src/test/compile-fail/issue-17545.rs index 84800218efc9..49435f83ce3c 100644 --- a/src/test/compile-fail/issue-17545.rs +++ b/src/test/compile-fail/issue-17545.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - pub fn foo<'a, F: Fn(&'a ())>(bar: F) { bar.call(( &(), //~ ERROR borrowed value does not live long enough diff --git a/src/test/compile-fail/issue-17551.rs b/src/test/compile-fail/issue-17551.rs index 5781cb741174..5e69553d3a48 100644 --- a/src/test/compile-fail/issue-17551.rs +++ b/src/test/compile-fail/issue-17551.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::marker; struct B(marker::PhantomData); diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 9cf922ae9900..94eab97c42a1 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -12,8 +12,6 @@ // when a type error or unconstrained type variable propagates // into it. -#![feature(unboxed_closures)] - fn main() { (return)((),()); //~^ ERROR the type of this value must be known diff --git a/src/test/compile-fail/issue-19521.rs b/src/test/compile-fail/issue-19521.rs index 58a95e9da2bf..93d95ca0b0f9 100644 --- a/src/test/compile-fail/issue-19521.rs +++ b/src/test/compile-fail/issue-19521.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn main() { "".homura()(); //~ ERROR no method named `homura` found } diff --git a/src/test/compile-fail/issue-19707.rs b/src/test/compile-fail/issue-19707.rs index 9affb44b7445..beeb7da6d389 100644 --- a/src/test/compile-fail/issue-19707.rs +++ b/src/test/compile-fail/issue-19707.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] #![allow(dead_code)] type foo = fn(&u8, &u8) -> &u8; //~ ERROR missing lifetime specifier diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 0089bff3e8fd..9a1b5d9b83d2 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box T + 'r> { diff --git a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs index 5af326b42984..df9a3519d5d6 100644 --- a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs +++ b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs @@ -12,8 +12,6 @@ // bound must be noncopyable. For details see // http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ -#![feature(unboxed_closures)] - struct R<'a> { // This struct is needed to create the // otherwise infinite type of a fn that diff --git a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs index 5db9a01c0128..8ec6036762f4 100644 --- a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs +++ b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures, overloaded_calls)] - use std::ops::FnMut; fn main() { diff --git a/src/test/compile-fail/regions-escape-unboxed-closure.rs b/src/test/compile-fail/regions-escape-unboxed-closure.rs index abbefd254888..cf41fad27083 100644 --- a/src/test/compile-fail/regions-escape-unboxed-closure.rs +++ b/src/test/compile-fail/regions-escape-unboxed-closure.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn with_int(f: &mut FnMut(&isize)) { } diff --git a/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs b/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs index 1e2224eafaeb..99e5cc031538 100644 --- a/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs +++ b/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs @@ -10,8 +10,6 @@ // Test that closures cannot subvert aliasing restrictions -#![feature(overloaded_calls, unboxed_closures)] - fn main() { // Unboxed closure case { diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index a30d8471a317..8ade8b239b3b 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - struct closure_box<'a> { cl: Box, } diff --git a/src/test/compile-fail/unboxed-closure-immutable-capture.rs b/src/test/compile-fail/unboxed-closure-immutable-capture.rs index 5be2738b47ef..2d9983742295 100644 --- a/src/test/compile-fail/unboxed-closure-immutable-capture.rs +++ b/src/test/compile-fail/unboxed-closure-immutable-capture.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - // Test that even unboxed closures that are capable of mutating their // environment cannot mutate captured variables that have not been // declared mutable (#18335) diff --git a/src/test/compile-fail/unboxed-closure-region.rs b/src/test/compile-fail/unboxed-closure-region.rs index eee1b6ce30b5..1c86dda3378a 100644 --- a/src/test/compile-fail/unboxed-closure-region.rs +++ b/src/test/compile-fail/unboxed-closure-region.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - // Test that an unboxed closure that captures a free variable by // reference cannot escape the region of that variable. fn main() { diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs index 21450856ae6c..465bddd060d7 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn f isize>(x: F) {} //~ ERROR trait `Nonexist` is not in scope type Typedef = isize; diff --git a/src/test/compile-fail/unboxed-closures-borrow-conflict.rs b/src/test/compile-fail/unboxed-closures-borrow-conflict.rs index 372f3277931e..ad7e6784a0a4 100644 --- a/src/test/compile-fail/unboxed-closures-borrow-conflict.rs +++ b/src/test/compile-fail/unboxed-closures-borrow-conflict.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - // Test that an unboxed closure that mutates a free variable will // cause borrow conflicts. diff --git a/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs b/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs index 1e2b01856e71..5436a855ee78 100644 --- a/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs +++ b/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs @@ -11,8 +11,6 @@ // That a closure whose expected argument types include two distinct // bound regions. -#![feature(unboxed_closures)] - use std::cell::Cell; fn doit(val: T, f: &F) diff --git a/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs b/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs index 226b516e09db..62f6ee56ca5d 100644 --- a/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs +++ b/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn main() { let mut zero = || {}; let () = zero.call_mut(()); diff --git a/src/test/compile-fail/unboxed-closures-type-mismatch.rs b/src/test/compile-fail/unboxed-closures-type-mismatch.rs index 91182393ac8e..dba4c8cc2e9e 100644 --- a/src/test/compile-fail/unboxed-closures-type-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-type-mismatch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::FnMut; pub fn main() { diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index cba7ad82ee16..2b0a8baf4f23 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -10,8 +10,6 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; unsafe fn square(x: &isize) -> isize { (*x) * (*x) } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index dd891bc473ce..f6ba25f43685 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -10,8 +10,6 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; extern "C" fn square(x: &isize) -> isize { (*x) * (*x) } diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index f9edd5df6739..9d907ffc17f2 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -10,8 +10,6 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; unsafe fn square(x: isize) -> isize { x * x } diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index aa269edadd8f..b415546faeac 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -40,7 +40,7 @@ // lldb-check:[...]$2 = 5 #![allow(unused_variables)] -#![feature(unboxed_closures, box_syntax)] +#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index 6def5cf28593..e60f964dd095 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -69,7 +69,7 @@ // lldb-command:print *owned // lldb-check:[...]$9 = 6 -#![feature(unboxed_closures, box_syntax)] +#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index 0ee460052c73..c364240f4ad6 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -12,9 +12,6 @@ // making method calls, but only if there aren't any matches without // it. - -#![feature(unboxed_closures)] - trait iterable { fn iterate(&self, blk: F) -> bool where F: FnMut(&A) -> bool; } diff --git a/src/test/run-pass/associated-types-impl-redirect.rs b/src/test/run-pass/associated-types-impl-redirect.rs index 4082580a123f..3e34367a2158 100644 --- a/src/test/run-pass/associated-types-impl-redirect.rs +++ b/src/test/run-pass/associated-types-impl-redirect.rs @@ -14,7 +14,7 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs index 082ad53d5593..ef1225d39a70 100644 --- a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs +++ b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs @@ -14,7 +14,7 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/src/test/run-pass/auxiliary/issue-18711.rs b/src/test/run-pass/auxiliary/issue-18711.rs index a29dcc00cddf..c247c0223fcb 100644 --- a/src/test/run-pass/auxiliary/issue-18711.rs +++ b/src/test/run-pass/auxiliary/issue-18711.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] #![crate_type = "rlib"] pub fn inner(f: F) -> F { diff --git a/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs b/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs index dac20dd2f7a7..dc9798a21016 100644 --- a/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs +++ b/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::Add; #[inline] diff --git a/src/test/run-pass/bare-fn-implements-fn-mut.rs b/src/test/run-pass/bare-fn-implements-fn-mut.rs index e8118e90a9f3..30a11ca2536d 100644 --- a/src/test/run-pass/bare-fn-implements-fn-mut.rs +++ b/src/test/run-pass/bare-fn-implements-fn-mut.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_f(mut f: F) { diff --git a/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs b/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs index bbc668f5cabf..158594df8cac 100644 --- a/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs +++ b/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs @@ -11,7 +11,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#![feature(unboxed_closures)] pub fn main() { let bar: Box<_> = box 3; diff --git a/src/test/run-pass/capture-clauses-unboxed-closures.rs b/src/test/run-pass/capture-clauses-unboxed-closures.rs index 5e7d5aacb8d0..e8a9dc7b8f36 100644 --- a/src/test/run-pass/capture-clauses-unboxed-closures.rs +++ b/src/test/run-pass/capture-clauses-unboxed-closures.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - fn each<'a,T,F:FnMut(&'a T)>(x: &'a [T], mut f: F) { for val in x { f(val) diff --git a/src/test/run-pass/closure-bounds-can-capture-chan.rs b/src/test/run-pass/closure-bounds-can-capture-chan.rs index dbbac8a16333..5268e855d5fd 100644 --- a/src/test/run-pass/closure-bounds-can-capture-chan.rs +++ b/src/test/run-pass/closure-bounds-can-capture-chan.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - use std::sync::mpsc::channel; fn foo(blk: F) { diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index 0fa67e873f89..a37733bdc2df 100644 --- a/src/test/run-pass/closure-reform.rs +++ b/src/test/run-pass/closure-reform.rs @@ -11,8 +11,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -#![feature(unboxed_closures)] - fn call_it(f: F) where F : FnOnce(String) -> String { diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 4dae1131c6d9..3f6f1aa6b5fe 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(unknown_features)] -#![feature(unboxed_closures, std_misc)] +#![feature(std_misc)] /** A somewhat reduced test case to expose some Valgrind issues. diff --git a/src/test/run-pass/hrtb-parse.rs b/src/test/run-pass/hrtb-parse.rs index ecd0bc681c31..cdffaef66eb2 100644 --- a/src/test/run-pass/hrtb-parse.rs +++ b/src/test/run-pass/hrtb-parse.rs @@ -13,7 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs b/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs index bc00a0758f45..46ea25629619 100644 --- a/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs +++ b/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - // Test that `F : Fn(isize) -> isize + Send` is interpreted as two // distinct bounds on `F`. diff --git a/src/test/run-pass/hrtb-precedence-of-plus.rs b/src/test/run-pass/hrtb-precedence-of-plus.rs index 892f2f1ae9df..d93e52a8f5fb 100644 --- a/src/test/run-pass/hrtb-precedence-of-plus.rs +++ b/src/test/run-pass/hrtb-precedence-of-plus.rs @@ -11,7 +11,6 @@ // pretty-expanded FIXME #23616 #![allow(unknown_features)] -#![feature(unboxed_closures)] // Test that `Fn(isize) -> isize + 'static` parses as `(Fn(isize) -> isize) + // 'static` and not `Fn(isize) -> (isize + 'static)`. The latter would diff --git a/src/test/run-pass/hrtb-trait-object-paren-notation.rs b/src/test/run-pass/hrtb-trait-object-paren-notation.rs index fefbd0047668..5b9d4a834d87 100644 --- a/src/test/run-pass/hrtb-trait-object-paren-notation.rs +++ b/src/test/run-pass/hrtb-trait-object-paren-notation.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - // A basic test of using a higher-ranked trait bound. trait FnLike { diff --git a/src/test/run-pass/hrtb-unboxed-closure-trait.rs b/src/test/run-pass/hrtb-unboxed-closure-trait.rs index 008e7ddbc9c5..6666b61a4a72 100644 --- a/src/test/run-pass/hrtb-unboxed-closure-trait.rs +++ b/src/test/run-pass/hrtb-unboxed-closure-trait.rs @@ -10,8 +10,6 @@ // Test HRTB used with the `Fn` trait. -#![feature(unboxed_closures)] - fn foo(f: F) { let x = 22; f(&x); diff --git a/src/test/run-pass/issue-10718.rs b/src/test/run-pass/issue-10718.rs index 0a6e454e181a..fedd94e22e7b 100644 --- a/src/test/run-pass/issue-10718.rs +++ b/src/test/run-pass/issue-10718.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn f(p: F) { p(); } diff --git a/src/test/run-pass/issue-16560.rs b/src/test/run-pass/issue-16560.rs index 596f0d20155d..e91569f8b245 100644 --- a/src/test/run-pass/issue-16560.rs +++ b/src/test/run-pass/issue-16560.rs @@ -10,8 +10,6 @@ // ignore-emscripten no threads support -#![feature(unboxed_closures)] - use std::thread; use std::mem; diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 786c701a0427..0fd996502848 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -11,7 +11,6 @@ // ignore-pretty #![allow(unknown_features)] -#![feature(unboxed_closures)] struct Parser<'a, I, O> { parse: Box Result + 'a> diff --git a/src/test/run-pass/issue-16774.rs b/src/test/run-pass/issue-16774.rs index 627717ab1cd1..9ec5910c2f67 100644 --- a/src/test/run-pass/issue-16774.rs +++ b/src/test/run-pass/issue-16774.rs @@ -12,7 +12,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] #![feature(box_patterns)] -#![feature(unboxed_closures)] use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/issue-17816.rs b/src/test/run-pass/issue-17816.rs index 8e3cb414566c..a9aa4cdd4f69 100644 --- a/src/test/run-pass/issue-17816.rs +++ b/src/test/run-pass/issue-17816.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::marker::PhantomData; fn main() { diff --git a/src/test/run-pass/issue-18652.rs b/src/test/run-pass/issue-18652.rs index 8ab645e54add..cea0beaf5f07 100644 --- a/src/test/run-pass/issue-18652.rs +++ b/src/test/run-pass/issue-18652.rs @@ -12,9 +12,6 @@ // once closure as an optimization by trans. This used to hit an // incorrect assert. - -#![feature(unboxed_closures)] - fn main() { let x = 2u8; let y = 3u8; diff --git a/src/test/run-pass/issue-18685.rs b/src/test/run-pass/issue-18685.rs index e4537e158d12..b569dbc8062e 100644 --- a/src/test/run-pass/issue-18685.rs +++ b/src/test/run-pass/issue-18685.rs @@ -13,8 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - trait Tr { fn foo(&self); diff --git a/src/test/run-pass/issue-18711.rs b/src/test/run-pass/issue-18711.rs index 277ad3260c51..8239d74d6df1 100644 --- a/src/test/run-pass/issue-18711.rs +++ b/src/test/run-pass/issue-18711.rs @@ -13,8 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - // aux-build:issue-18711.rs extern crate issue_18711 as issue; diff --git a/src/test/run-pass/issue-19127.rs b/src/test/run-pass/issue-19127.rs index c5eb50693280..8d169917cad9 100644 --- a/src/test/run-pass/issue-19127.rs +++ b/src/test/run-pass/issue-19127.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn foo T>(f: F) {} fn id<'a>(input: &'a u8) -> &'a u8 { input } diff --git a/src/test/run-pass/issue-19135.rs b/src/test/run-pass/issue-19135.rs index 5e6dd567d632..ca2098138ef0 100644 --- a/src/test/run-pass/issue-19135.rs +++ b/src/test/run-pass/issue-19135.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::marker::PhantomData; #[derive(Debug)] diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs index ca3294a87adb..7ff684a5ef39 100644 --- a/src/test/run-pass/mir_trans_calls.rs +++ b/src/test/run-pass/mir_trans_calls.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, unboxed_closures, fn_traits)] +#![feature(rustc_attrs, fn_traits)] #[rustc_mir] fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 24dc73d4a43d..0de6fbc91cc6 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -16,7 +16,6 @@ #![allow(unknown_features)] #![feature(box_syntax, std_misc)] -#![feature(unboxed_closures)] use std::sync::Arc; use std::sync::mpsc::channel; diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs index 3030833c7721..c29fb5e86f51 100644 --- a/src/test/run-pass/type-id-higher-rank.rs +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -12,7 +12,7 @@ // Also acts as a regression test for an ICE (issue #19791) -#![feature(unboxed_closures, core)] +#![feature(core)] use std::any::{Any, TypeId}; diff --git a/src/test/run-pass/unboxed-closures-all-traits.rs b/src/test/run-pass/unboxed-closures-all-traits.rs index c28d4f463e57..201500d0c628 100644 --- a/src/test/run-pass/unboxed-closures-all-traits.rs +++ b/src/test/run-pass/unboxed-closures-all-traits.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] fn a isize>(f: F) -> isize { f(1, 2) diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs index 54c92900c89b..23ec0cb5f60f 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -10,8 +10,7 @@ // Test that you can supply `&F` where `F: FnMut()`. - -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] fn a i32>(mut f: F) -> i32 { f() diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs index eb474473094a..2aa48e7d2add 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -10,8 +10,7 @@ // Test that you can supply `&F` where `F: Fn()`. - -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] fn a i32>(f: F) -> i32 { f() diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs index 5dea6a7c6db3..069f26841d2c 100644 --- a/src/test/run-pass/unboxed-closures-boxed.rs +++ b/src/test/run-pass/unboxed-closures-boxed.rs @@ -10,7 +10,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#![feature(unboxed_closures)] use std::ops::FnMut; diff --git a/src/test/run-pass/unboxed-closures-by-ref.rs b/src/test/run-pass/unboxed-closures-by-ref.rs index e3ddfdbac00f..b251215909a4 100644 --- a/src/test/run-pass/unboxed-closures-by-ref.rs +++ b/src/test/run-pass/unboxed-closures-by-ref.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - // Test by-ref capture of environment in unboxed closure types fn call_fn(f: F) { diff --git a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs index 64236ce563b0..56c53bcafced 100644 --- a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs @@ -10,9 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. - -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_with_2(x: &fn(isize) -> isize) -> isize diff --git a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs index 67ab84f0276c..63667ec11d66 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs @@ -10,9 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. - -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_with_2(x: &mut F) -> isize diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs index c82026235c2a..a92fb05306f4 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs @@ -11,7 +11,6 @@ // Test that the call operator autoderefs when calling to an object type. #![allow(unknown_features)] -#![feature(unboxed_closures)] use std::ops::FnMut; diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object.rs b/src/test/run-pass/unboxed-closures-call-sugar-object.rs index 629da1091ac5..5dd2343cfd1d 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(unknown_features)] -#![feature(unboxed_closures)] use std::ops::FnMut; diff --git a/src/test/run-pass/unboxed-closures-counter-not-moved.rs b/src/test/run-pass/unboxed-closures-counter-not-moved.rs index cb5f190bcd73..0b85916d2241 100644 --- a/src/test/run-pass/unboxed-closures-counter-not-moved.rs +++ b/src/test/run-pass/unboxed-closures-counter-not-moved.rs @@ -10,7 +10,6 @@ // Test that we mutate a counter on the stack only when we expect to. - fn call(f: F) where F : FnOnce() { f(); } diff --git a/src/test/run-pass/unboxed-closures-direct-sugary-call.rs b/src/test/run-pass/unboxed-closures-direct-sugary-call.rs index c91aa6ed0d92..c8da4a6992a1 100644 --- a/src/test/run-pass/unboxed-closures-direct-sugary-call.rs +++ b/src/test/run-pass/unboxed-closures-direct-sugary-call.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn main() { let mut unboxed = || {}; unboxed(); diff --git a/src/test/run-pass/unboxed-closures-drop.rs b/src/test/run-pass/unboxed-closures-drop.rs index 78f4905aef97..57f2f87e2469 100644 --- a/src/test/run-pass/unboxed-closures-drop.rs +++ b/src/test/run-pass/unboxed-closures-drop.rs @@ -11,9 +11,6 @@ // A battery of tests to ensure destructors of unboxed closure environments // run at the right times. - -#![feature(unboxed_closures)] - static mut DROP_COUNT: usize = 0; fn drop_count() -> usize { diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs index 57acbae4ce6d..eddb6080d17b 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -10,10 +10,6 @@ // Checks that extern fn pointers implement the full range of Fn traits. - -#![feature(unboxed_closures)] -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; fn square(x: isize) -> isize { x * x } diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 2e63c600a46c..f90aced3dbe3 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // any Fn trait to be used where Fn is implemented. - #![feature(unboxed_closures, fn_traits)] use std::ops::{Fn,FnMut,FnOnce}; diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index ce93fcafc9e7..0a977cef442e 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // FnMut or FnOnce to be used where FnMut is implemented. - #![feature(unboxed_closures, fn_traits)] struct S; diff --git a/src/test/run-pass/unboxed-closures-generic.rs b/src/test/run-pass/unboxed-closures-generic.rs index 47936ba93828..01c81ef98d50 100644 --- a/src/test/run-pass/unboxed-closures-generic.rs +++ b/src/test/run-pass/unboxed-closures-generic.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_iti32>(y: i32, mut f: F) -> i32 { diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs index 2da899ed95b5..17833033492d 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). - fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs index 32fc3433e847..794527249bff 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this `move` // closure that is just called (`FnMut`). - fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut.rs index a8469f4019ab..67f36b9a9203 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). - fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-kind.rs b/src/test/run-pass/unboxed-closures-infer-kind.rs index fa668475f587..c04df7ed5f87 100644 --- a/src/test/run-pass/unboxed-closures-infer-kind.rs +++ b/src/test/run-pass/unboxed-closures-infer-kind.rs @@ -11,9 +11,6 @@ // Test that we can infer the "kind" of an unboxed closure based on // the expected type. - -#![feature(unboxed_closures)] - // Test by-ref capture of environment in unboxed closure types fn call_fn(f: F) { diff --git a/src/test/run-pass/unboxed-closures-infer-upvar.rs b/src/test/run-pass/unboxed-closures-infer-upvar.rs index f2423145b197..1401fe7470b0 100644 --- a/src/test/run-pass/unboxed-closures-infer-upvar.rs +++ b/src/test/run-pass/unboxed-closures-infer-upvar.rs @@ -11,7 +11,6 @@ // Test that the type variable in the type(`Vec<_>`) of a closed over // variable does not interfere with type inference. - fn f(mut f: F) { f(); } diff --git a/src/test/run-pass/unboxed-closures-move-mutable.rs b/src/test/run-pass/unboxed-closures-move-mutable.rs index 1aca3174e1fe..a55b0a0185e6 100644 --- a/src/test/run-pass/unboxed-closures-move-mutable.rs +++ b/src/test/run-pass/unboxed-closures-move-mutable.rs @@ -10,7 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] #![deny(unused_mut)] // Test that mutating a mutable upvar in a capture-by-value unboxed diff --git a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs index e2b286738e76..99663646254e 100644 --- a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs +++ b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs @@ -11,7 +11,6 @@ // Test that in a by-ref once closure we move some variables even as // we capture others by mutable reference. - fn call(f: F) where F : FnOnce() { f(); } diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs index ec3419816693..429afb95248c 100644 --- a/src/test/run-pass/unboxed-closures-simple.rs +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - use std::ops::FnMut; pub fn main() { diff --git a/src/test/run-pass/unboxed-closures-single-word-env.rs b/src/test/run-pass/unboxed-closures-single-word-env.rs index 166054e88b7b..3ed055a7884e 100644 --- a/src/test/run-pass/unboxed-closures-single-word-env.rs +++ b/src/test/run-pass/unboxed-closures-single-word-env.rs @@ -11,9 +11,6 @@ // Ensures that single-word environments work right in unboxed closures. // These take a different path in codegen. - -#![feature(unboxed_closures)] - fn a isize>(f: F) -> isize { f(1, 2) } diff --git a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs index e90a3443610c..c13e9513ce33 100644 --- a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs +++ b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn main() { let onetime = |x| x; onetime(0); diff --git a/src/test/run-pass/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures-sugar-object.rs index 49b9b7f061e7..b7d367f23538 100644 --- a/src/test/run-pass/unboxed-closures-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-sugar-object.rs @@ -10,9 +10,7 @@ // Test unboxed closure sugar used in object types. - #![allow(dead_code)] -#![feature(unboxed_closures)] struct Foo { t: T, u: U diff --git a/src/test/run-pass/unboxed-closures-unique-type-id.rs b/src/test/run-pass/unboxed-closures-unique-type-id.rs index 30c45fc766a1..40071ec9754e 100644 --- a/src/test/run-pass/unboxed-closures-unique-type-id.rs +++ b/src/test/run-pass/unboxed-closures-unique-type-id.rs @@ -19,9 +19,6 @@ // // compile-flags: -g - -#![feature(unboxed_closures)] - use std::ptr; pub fn replace_map<'a, T, F>(src: &mut T, prod: F) where F: FnOnce(T) -> T { diff --git a/src/test/run-pass/unboxed-closures-zero-args.rs b/src/test/run-pass/unboxed-closures-zero-args.rs index cb3a18a18c13..9e6a7cce1fd2 100644 --- a/src/test/run-pass/unboxed-closures-zero-args.rs +++ b/src/test/run-pass/unboxed-closures-zero-args.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn main() { let mut zero = || {}; let () = zero(); diff --git a/src/test/run-pass/where-clauses-unboxed-closures.rs b/src/test/run-pass/where-clauses-unboxed-closures.rs index c509cbe2a5e9..8a775caaac6d 100644 --- a/src/test/run-pass/where-clauses-unboxed-closures.rs +++ b/src/test/run-pass/where-clauses-unboxed-closures.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - struct Bencher; // ICE From aaf8a6e108a6080cdd47983909e90a60c1d92aea Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Sat, 30 Jul 2016 09:01:13 +0200 Subject: [PATCH 245/331] tcp-stress-test: Factor out thread count as constant. --- src/test/run-pass/tcp-stress.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index dfc86497c965..e5b418bb733c 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -21,6 +21,8 @@ use std::sync::mpsc::channel; use std::time::Duration; use std::thread::{self, Builder}; +const TARGET_CNT: usize = 1000; + fn main() { // This test has a chance to time out, try to not let it time out thread::spawn(move|| -> () { @@ -42,8 +44,9 @@ fn main() { }); let (tx, rx) = channel(); + let mut spawned_cnt = 0; - for _ in 0..1000 { + for _ in 0..TARGET_CNT { let tx = tx.clone(); let res = Builder::new().stack_size(64 * 1024).spawn(move|| { match TcpStream::connect(addr) { @@ -66,6 +69,6 @@ fn main() { for _ in 0..spawned_cnt { rx.recv().unwrap(); } - assert_eq!(spawned_cnt, 1000); + assert_eq!(spawned_cnt, TARGET_CNT); process::exit(0); } From d1f341dd91f7660bd64acfbd63f4513f9a327217 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sun, 31 Jul 2016 22:17:29 +0300 Subject: [PATCH 246/331] rustc_trans: apply the debug location for the MIR Assert panic call. --- src/librustc_trans/mir/block.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 7a7f1901736c..2d1769b8637b 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -284,6 +284,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // After this point, bcx is the block for the call to panic. bcx = panic_block.build(); + debug_loc.apply_to_bcx(&bcx); // Get the location information. let loc = bcx.sess().codemap().lookup_char_pos(span.lo); From 0a128f325e47ae5c554ff1bcb76db142355a5919 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 31 Jul 2016 23:01:02 +0300 Subject: [PATCH 247/331] typeck: use a TypeVisitor in ctp Fixes #35139 --- src/librustc_typeck/collect.rs | 10 +- .../constrained_type_params.rs | 108 +++++++----------- src/test/compile-fail/issue-35139.rs | 36 ++++++ 3 files changed, 83 insertions(+), 71 deletions(-) create mode 100644 src/test/compile-fail/issue-35139.rs diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 57602b55cc96..ec95afe15bd5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2237,9 +2237,9 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // reachable from there, to start (if this is an inherent impl, // then just examine the self type). let mut input_parameters: HashSet<_> = - ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect(); + ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false)); + input_parameters.extend(ctp::parameters_for(trait_ref, false)); } ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace), @@ -2267,9 +2267,9 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); let mut input_parameters: HashSet<_> = - ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect(); + ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false)); + input_parameters.extend(ctp::parameters_for(trait_ref, false)); } ctp::identify_constrained_type_params( &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); @@ -2280,7 +2280,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None }) - .flat_map(|ty| ctp::parameters_for_type(ty, true)) + .flat_map(|ty| ctp::parameters_for(&ty, true)) .filter_map(|p| match p { ctp::Parameter::Type(_) => None, ctp::Parameter::Region(r) => Some(r), diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 08c1b5fcc82c..7909584bfabd 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::ty::{self, subst, Ty}; - +use rustc::ty::{self, Ty}; +use rustc::ty::fold::{TypeFoldable, TypeVisitor}; use std::collections::HashSet; #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -19,77 +19,53 @@ pub enum Parameter { } /// If `include_projections` is false, returns the list of parameters that are -/// constrained by the type `ty` - i.e. the value of each parameter in the list is -/// uniquely determined by `ty` (see RFC 447). If it is true, return the list +/// constrained by `t` - i.e. the value of each parameter in the list is +/// uniquely determined by `t` (see RFC 447). If it is true, return the list /// of parameters whose values are needed in order to constrain `ty` - these /// differ, with the latter being a superset, in the presence of projections. -pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>, - include_projections: bool) -> Vec { - let mut result = vec![]; - ty.maybe_walk(|t| match t.sty { - ty::TyProjection(..) if !include_projections => { +pub fn parameters_for<'tcx, T>(t: &T, + include_nonconstraining: bool) + -> Vec + where T: TypeFoldable<'tcx> +{ - false // projections are not injective. - } - _ => { - result.append(&mut parameters_for_type_shallow(t)); - // non-projection type constructors are injective. - true - } - }); - result + let mut collector = ParameterCollector { + parameters: vec![], + include_nonconstraining: include_nonconstraining + }; + t.visit_with(&mut collector); + collector.parameters } -pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>, - include_projections: bool) -> Vec { - let mut region_parameters = - parameters_for_regions_in_substs(&trait_ref.substs); - - let type_parameters = - trait_ref.substs - .types - .iter() - .flat_map(|ty| parameters_for_type(ty, include_projections)); - - region_parameters.extend(type_parameters); - - region_parameters +struct ParameterCollector { + parameters: Vec, + include_nonconstraining: bool } -fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec { - match ty.sty { - ty::TyParam(ref d) => - vec![Parameter::Type(d.clone())], - ty::TyRef(region, _) => - parameters_for_region(region).into_iter().collect(), - ty::TyStruct(_, substs) | - ty::TyEnum(_, substs) => - parameters_for_regions_in_substs(substs), - ty::TyTrait(ref data) => - parameters_for_regions_in_substs(&data.principal.skip_binder().substs), - ty::TyProjection(ref pi) => - parameters_for_regions_in_substs(&pi.trait_ref.substs), - ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr | - ty::TyArray(..) | ty::TySlice(..) | - ty::TyFnDef(..) | ty::TyFnPtr(_) | - ty::TyTuple(..) | ty::TyRawPtr(..) | - ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError => - vec![] +impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.sty { + ty::TyProjection(..) if !self.include_nonconstraining => { + // projections are not injective + return false; + } + ty::TyParam(ref d) => { + self.parameters.push(Parameter::Type(d.clone())); + } + _ => {} + } + + t.super_visit_with(self) } -} -fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec { - substs.regions - .iter() - .filter_map(|r| parameters_for_region(r)) - .collect() -} - -fn parameters_for_region(region: &ty::Region) -> Option { - match *region { - ty::ReEarlyBound(data) => Some(Parameter::Region(data)), - _ => None, + fn visit_region(&mut self, r: ty::Region) -> bool { + match r { + ty::ReEarlyBound(data) => { + self.parameters.push(Parameter::Region(data)); + } + _ => {} + } + false } } @@ -191,12 +167,12 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref, true); + let inputs = parameters_for(&projection.projection_ty.trait_ref, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; } - input_parameters.extend(parameters_for_type(projection.ty, false)); + input_parameters.extend(parameters_for(&projection.ty, false)); } else { continue; } diff --git a/src/test/compile-fail/issue-35139.rs b/src/test/compile-fail/issue-35139.rs new file mode 100644 index 000000000000..67f0e7aaf971 --- /dev/null +++ b/src/test/compile-fail/issue-35139.rs @@ -0,0 +1,36 @@ +// 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::fmt; + +pub trait MethodType { + type GetProp: ?Sized; +} + +pub struct MTFn; + +impl<'a> MethodType for MTFn { //~ ERROR E0207 + type GetProp = fmt::Debug + 'a; +} + +fn bad(a: Box<::GetProp>) -> Box { + a +} + +fn dangling(a: &str) -> Box { + bad(Box::new(a)) +} + +fn main() { + let mut s = "hello".to_string(); + let x = dangling(&s); + s = String::new(); + println!("{:?}", x); +} From 46bd5d3fa01a86925f7e7776a5567c536e6f2408 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 31 Jul 2016 20:11:38 +0000 Subject: [PATCH 248/331] Avoid emitting a unhelpful cascading resolution error. --- src/librustc_resolve/lib.rs | 2 ++ src/test/compile-fail/issue-5035.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8c8cf1da4673..23281d25c8d5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1810,6 +1810,8 @@ impl<'a> Resolver<'a> { if let Def::Trait(_) = path_res.base_def { debug!("(resolving trait) found trait def: {:?}", path_res); Ok(path_res) + } else if path_res.base_def == Def::Err { + Err(true) } else { let mut err = resolve_struct_error(self, diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index a186a399a112..61080ef60964 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -13,4 +13,8 @@ type K = I; //~^ NOTE: aliases cannot be used for traits impl K for isize {} //~ ERROR: `K` is not a trait //~| is not a trait + +use ImportError; //~ ERROR unresolved +impl ImportError for () {} // check that this is not an additional error (c.f. #35142) + fn main() {} From 93fd214d61749ecae05a9ff240d51fcf77ca086c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 31 Jul 2016 20:40:03 +0000 Subject: [PATCH 249/331] Clean up `resolve_trait_reference`. --- src/librustc_resolve/lib.rs | 65 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 23281d25c8d5..33e5282188c2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1807,41 +1807,40 @@ impl<'a> Resolver<'a> { path_depth: usize) -> Result { self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| { - if let Def::Trait(_) = path_res.base_def { - debug!("(resolving trait) found trait def: {:?}", path_res); - Ok(path_res) - } else if path_res.base_def == Def::Err { - Err(true) - } else { - let mut err = - resolve_struct_error(self, - trait_path.span, - ResolutionError::IsNotATrait(&path_names_to_string(trait_path, - path_depth))); - - // If it's a typedef, give a note - if let Def::TyAlias(..) = path_res.base_def { - let trait_name = trait_path.segments.last().unwrap().identifier.name; - err.span_label(trait_path.span, - &format!("`{}` is not a trait", trait_name)); - - let definition_site = { - let segments = &trait_path.segments; - if trait_path.global { - self.resolve_crate_relative_path(trait_path.span, segments, TypeNS) - } else { - self.resolve_module_relative_path(trait_path.span, segments, TypeNS) - }.map(|binding| binding.span).unwrap_or(syntax_pos::DUMMY_SP) - }; - - if definition_site != syntax_pos::DUMMY_SP { - err.span_label(definition_site, - &format!("type aliases cannot be used for traits")); - } + match path_res.base_def { + Def::Trait(_) => { + debug!("(resolving trait) found trait def: {:?}", path_res); + return Ok(path_res); } - err.emit(); - Err(true) + Def::Err => return Err(true), + _ => {} } + + let mut err = resolve_struct_error(self, trait_path.span, { + ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth)) + }); + + // If it's a typedef, give a note + if let Def::TyAlias(..) = path_res.base_def { + let trait_name = trait_path.segments.last().unwrap().identifier.name; + err.span_label(trait_path.span, &format!("`{}` is not a trait", trait_name)); + + let definition_site = { + let segments = &trait_path.segments; + if trait_path.global { + self.resolve_crate_relative_path(trait_path.span, segments, TypeNS) + } else { + self.resolve_module_relative_path(trait_path.span, segments, TypeNS) + }.map(|binding| binding.span).unwrap_or(syntax_pos::DUMMY_SP) + }; + + if definition_site != syntax_pos::DUMMY_SP { + err.span_label(definition_site, + &format!("type aliases cannot be used for traits")); + } + } + err.emit(); + Err(true) }).map_err(|error_reported| { if error_reported { return } From d6b10beb884bf3a2379ba694bc44b933ad5164c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 31 Jul 2016 21:29:01 +0000 Subject: [PATCH 250/331] Make "type aliases cannot be used for traits" a note instead of a span_label. --- src/librustc_resolve/lib.rs | 17 +---------------- src/test/compile-fail/issue-3907.rs | 4 ++-- src/test/compile-fail/issue-5035.rs | 3 +-- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 33e5282188c2..c1511b29c9e0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1822,22 +1822,7 @@ impl<'a> Resolver<'a> { // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { - let trait_name = trait_path.segments.last().unwrap().identifier.name; - err.span_label(trait_path.span, &format!("`{}` is not a trait", trait_name)); - - let definition_site = { - let segments = &trait_path.segments; - if trait_path.global { - self.resolve_crate_relative_path(trait_path.span, segments, TypeNS) - } else { - self.resolve_module_relative_path(trait_path.span, segments, TypeNS) - }.map(|binding| binding.span).unwrap_or(syntax_pos::DUMMY_SP) - }; - - if definition_site != syntax_pos::DUMMY_SP { - err.span_label(definition_site, - &format!("type aliases cannot be used for traits")); - } + err.note(&format!("type aliases cannot be used for traits")); } err.emit(); Err(true) diff --git a/src/test/compile-fail/issue-3907.rs b/src/test/compile-fail/issue-3907.rs index c99ff1813e0d..cbc09a028c2c 100644 --- a/src/test/compile-fail/issue-3907.rs +++ b/src/test/compile-fail/issue-3907.rs @@ -11,14 +11,14 @@ // aux-build:issue_3907.rs extern crate issue_3907; -type Foo = issue_3907::Foo; //~ NOTE: type aliases cannot be used for traits +type Foo = issue_3907::Foo; struct S { name: isize } impl Foo for S { //~ ERROR: `Foo` is not a trait - //~| `Foo` is not a trait + //~| NOTE: type aliases cannot be used for traits fn bar() { } } diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index 61080ef60964..9648d64d1fb6 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -10,9 +10,8 @@ trait I {} type K = I; -//~^ NOTE: aliases cannot be used for traits impl K for isize {} //~ ERROR: `K` is not a trait -//~| is not a trait + //~| NOTE: aliases cannot be used for traits use ImportError; //~ ERROR unresolved impl ImportError for () {} // check that this is not an additional error (c.f. #35142) From 65e3ff4df44effdfa60971cd7b66e4ce8a4c5bb9 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Thu, 16 Jun 2016 23:15:06 -0700 Subject: [PATCH 251/331] add extended information for E0529, slice pattern expects array or slice --- src/librustc_typeck/diagnostics.rs | 32 +++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 500f624ea3f7..3867ed5fa686 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3980,6 +3980,37 @@ impl SpaceLlama for i32 { ``` "##, +E0529: r##" +An array or slice pattern was matched against some other type. + +Example of erroneous code: + +```compile_fail,E0529 +#![feature(slice_patterns)] + +let r: f32 = 1.0; +match r { + [a, b] => { // error: expected an array or slice, found `f32` + println!("a={}, b={}", a, b); + } +} +``` + +Ensure that the pattern and the expression being matched on are of consistent +types: + +``` +#![feature(slice_patterns)] + +let r = [1.0, 2.0]; +match r { + [a, b] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + E0559: r##" An unknown field was specified into an enum's structure variant. @@ -4102,6 +4133,5 @@ register_diagnostics! { E0521, // redundant default implementations of trait E0527, // expected {} elements, found {} 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 } From 7093d1de8455556640578ad3d493bc9bff79b8e5 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Thu, 16 Jun 2016 23:45:44 -0700 Subject: [PATCH 252/331] add extended info for E0527, slice pattern element count expectations --- src/librustc_typeck/diagnostics.rs | 34 +++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 3867ed5fa686..cf8fd3da1f5b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3980,6 +3980,39 @@ impl SpaceLlama for i32 { ``` "##, +E0527: r##" +The number of elements in an array or slice pattern differed from the number of +elements in the array being matched. + +Example of erroneous code: + +```compile_fail,E0527 +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b] => { // error: pattern requires 2 elements but array + // has 4 + println!("a={}, b={}", a, b); + } +} +``` + +Ensure that the pattern is consistent with the size of the matched +array. Additional elements can be matched with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b, ..] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + E0529: r##" An array or slice pattern was matched against some other type. @@ -4131,7 +4164,6 @@ register_diagnostics! { E0436, // functional record update requires a struct E0513, // no type for local variable .. E0521, // redundant default implementations of trait - E0527, // expected {} elements, found {} E0528, // expected at least {} elements, found {} E0533, // `{}` does not name a unit variant, unit struct or a constant } From e960021d30faff871f98c9c463b43c4359af280d Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Fri, 17 Jun 2016 00:03:36 -0700 Subject: [PATCH 253/331] extended info for E0528, expected at least this-and-such many elements --- src/librustc_typeck/diagnostics.rs | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index cf8fd3da1f5b..4b0b616c5f64 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4013,6 +4013,40 @@ match r { ``` "##, +E0528: r##" +An array or slice pattern required more elements than were present in the +matched array. + +Example of erroneous code: + +```compile_fail,E0528 +#![feature(slice_patterns)] + +let r = &[1, 2]; +match r { + &[a, b, c, rest..] => { // error: pattern requires at least 3 + // elements but array has 2 + println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); + } +} +``` + +Ensure that the matched array has at least as many elements as the pattern +requires. You can match an arbitrary number of remaining elements with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4, 5]; +match r { + &[a, b, c, rest..] => { // ok! + // prints `a=1, b=2, c=3 rest=[4, 5]` + println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); + } +} +``` +"##, + E0529: r##" An array or slice pattern was matched against some other type. @@ -4164,6 +4198,5 @@ register_diagnostics! { E0436, // functional record update requires a struct E0513, // no type for local variable .. E0521, // redundant default implementations of trait - E0528, // expected at least {} elements, found {} E0533, // `{}` does not name a unit variant, unit struct or a constant } From e9d2c9654ac45a9c23e7811f949eabfe1f7f6841 Mon Sep 17 00:00:00 2001 From: Brendan Cully Date: Sun, 31 Jul 2016 16:15:29 -0700 Subject: [PATCH 254/331] Add libarena from local rust to stage0 This was needed at least when local rust was 1.9.0 on darwin. Fixes #35149 --- src/etc/local_stage0.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index 354be34b6a29..f5f39d264a6b 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -58,6 +58,7 @@ case "$TARG_DIR" in cp ${PREFIX}/bin/rustc${BIN_SUF} ${TARG_DIR}/stage0/bin/ cp ${PREFIX}/${LIB_DIR}/${RUSTLIBDIR}/${TARG_DIR}/${LIB_DIR}/* ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}arena*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rust*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}std*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ From 157f7c1b30698dcdb2452e687f4940550a6e6467 Mon Sep 17 00:00:00 2001 From: "Ryan Scheel (Havvy)" Date: Tue, 26 Jul 2016 05:14:37 +0000 Subject: [PATCH 255/331] Add Derive not possible question to Copy This adds a question and answer to the Q&A section of the Copy docs. Specifically, it asks the question I asked while reading the docs, and gives its answer. --- src/libcore/marker.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c18d230be31a..894982abaa93 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -144,6 +144,12 @@ pub trait Unsize { /// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's /// managing some resource besides its own `size_of::()` bytes. /// +/// ## What if I derive `Copy` on a type that can't? +/// +/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error. +/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204) +/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205). +/// /// ## When should my type be `Copy`? /// /// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing From 3ea293ddf2af66c9a2e720ce3139aed75787d890 Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Mon, 1 Aug 2016 09:43:19 +0200 Subject: [PATCH 256/331] tcp-stress-test.rs: Only spawn 200 threads. --- src/test/run-pass/tcp-stress.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index e5b418bb733c..0ba019c591c1 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -21,7 +21,7 @@ use std::sync::mpsc::channel; use std::time::Duration; use std::thread::{self, Builder}; -const TARGET_CNT: usize = 1000; +const TARGET_CNT: usize = 200; fn main() { // This test has a chance to time out, try to not let it time out From d5a5149617ff95a36405c4c9ac396a50b6ff3f17 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 26 Jul 2016 10:58:35 -0400 Subject: [PATCH 257/331] Move caching of HIR-inlining into CStore in order to avoid duplicating inlined HIR. --- src/librustc/hir/intravisit.rs | 3 +- src/librustc/hir/map/mod.rs | 62 +++++++++- src/librustc/middle/cstore.rs | 22 ++-- src/librustc_const_eval/eval.rs | 12 +- src/librustc_metadata/astencode.rs | 51 ++++++-- src/librustc_metadata/csearch.rs | 147 ++++++++++++++++++++++- src/librustc_metadata/cstore.rs | 13 +- src/librustc_metadata/decoder.rs | 8 +- src/librustc_trans/common.rs | 20 +-- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/context.rs | 17 +-- src/librustc_trans/debuginfo/metadata.rs | 15 ++- src/librustc_trans/debuginfo/mod.rs | 7 +- src/librustc_trans/debuginfo/utils.rs | 5 +- src/librustc_trans/inline.rs | 106 +--------------- src/librustc_typeck/astconv.rs | 13 ++ src/librustdoc/clean/mod.rs | 7 +- 17 files changed, 335 insertions(+), 175 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index a06fc21764de..aded220c0cdf 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -867,7 +867,7 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { } } -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)] pub struct IdRange { pub min: NodeId, pub max: NodeId, @@ -893,6 +893,7 @@ impl IdRange { self.min = cmp::min(self.min, id); self.max = cmp::max(self.max, id + 1); } + } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 960e32ae99fa..aed3613f44ed 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -32,6 +32,7 @@ use hir::print as pprust; use arena::TypedArena; use std::cell::RefCell; +use std::cmp; use std::io; use std::mem; @@ -127,7 +128,10 @@ impl<'ast> MapEntry<'ast> { EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, EntryTyParam(id, _) => id, - _ => return None + + NotPresent | + RootCrate | + RootInlinedParent(_) => return None, }) } @@ -196,6 +200,10 @@ pub struct Map<'ast> { map: RefCell>>, definitions: RefCell, + + /// All NodeIds that are numerically greater or equal to this value come + /// from inlined items. + local_node_id_watermark: NodeId, } impl<'ast> Map<'ast> { @@ -550,6 +558,13 @@ impl<'ast> Map<'ast> { } } + pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem { + match self.find_entry(id) { + Some(RootInlinedParent(inlined_item)) => inlined_item, + _ => bug!("expected inlined item, found {}", self.node_to_string(id)), + } + } + /// Returns the name associated with the given NodeId's AST. pub fn name(&self, id: NodeId) -> Name { match self.get(id) { @@ -649,6 +664,10 @@ impl<'ast> Map<'ast> { pub fn node_to_user_string(&self, id: NodeId) -> String { node_id_to_string(self, id, false) } + + pub fn is_inlined(&self, id: NodeId) -> bool { + id >= self.local_node_id_watermark + } } pub struct NodesMatchingSuffix<'a, 'ast:'a> { @@ -765,13 +784,37 @@ pub trait FoldOps { } /// A Folder that updates IDs and Span's according to fold_ops. -struct IdAndSpanUpdater { - fold_ops: F +pub struct IdAndSpanUpdater { + fold_ops: F, + min_id_assigned: NodeId, + max_id_assigned: NodeId, +} + +impl IdAndSpanUpdater { + pub fn new(fold_ops: F) -> IdAndSpanUpdater { + IdAndSpanUpdater { + fold_ops: fold_ops, + min_id_assigned: ::std::u32::MAX, + max_id_assigned: ::std::u32::MIN, + } + } + + pub fn id_range(&self) -> intravisit::IdRange { + intravisit::IdRange { + min: self.min_id_assigned, + max: self.max_id_assigned + 1, + } + } } impl Folder for IdAndSpanUpdater { fn new_id(&mut self, id: NodeId) -> NodeId { - self.fold_ops.new_id(id) + let id = self.fold_ops.new_id(id); + + self.min_id_assigned = cmp::min(self.min_id_assigned, id); + self.max_id_assigned = cmp::max(self.max_id_assigned, id); + + id } fn new_span(&mut self, span: Span) -> Span { @@ -802,11 +845,14 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest, entries, vector_length, (entries as f64 / vector_length as f64) * 100.); } + let local_node_id_watermark = map.len() as NodeId; + Map { forest: forest, dep_graph: forest.dep_graph.clone(), map: RefCell::new(map), definitions: RefCell::new(definitions), + local_node_id_watermark: local_node_id_watermark } } @@ -818,7 +864,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { - let mut fld = IdAndSpanUpdater { fold_ops: fold_ops }; + let mut fld = IdAndSpanUpdater::new(fold_ops); let ii = match ii { II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))), II::TraitItem(d, ti) => { @@ -835,6 +881,12 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, let ii = map.forest.inlined_items.alloc(ii); let ii_parent_id = fld.new_id(DUMMY_NODE_ID); + // Assert that the ii_parent_id is the last NodeId in our reserved range + assert!(ii_parent_id == fld.max_id_assigned); + // Assert that we did not violate the invariant that all inlined HIR items + // have NodeIds greater than or equal to `local_node_id_watermark` + assert!(fld.min_id_assigned >= map.local_node_id_watermark); + let defs = &mut *map.definitions.borrow_mut(); let mut def_collector = DefCollector::extend(ii_parent_id, parent_def_path.clone(), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 484aacfd9ecc..32344a7b9c8d 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -120,12 +120,6 @@ pub struct ChildItem { pub vis: ty::Visibility, } -pub enum FoundAst<'ast> { - Found(&'ast InlinedItem), - FoundParent(DefId, &'ast hir::Item), - NotFound, -} - #[derive(Copy, Clone, Debug)] pub struct ExternCrate { /// def_id of an `extern crate` in the current crate that caused @@ -250,7 +244,10 @@ pub trait CrateStore<'tcx> { // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> FoundAst<'tcx>; + -> Option<(&'tcx InlinedItem, ast::NodeId)>; + fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option; + fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option; + fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; fn is_item_mir_available(&self, def: DefId) -> bool; @@ -447,7 +444,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> FoundAst<'tcx> { bug!("maybe_get_item_ast") } + -> Option<(&'tcx InlinedItem, ast::NodeId)> { + bug!("maybe_get_item_ast") + } + fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option { + bug!("local_node_for_inlined_defid") + } + fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option { + bug!("defid_for_inlined_node") + } + fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("maybe_get_item_mir") } fn is_item_mir_available(&self, def: DefId) -> bool { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index dd21bb17a2da..d424b57c9384 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -17,7 +17,7 @@ use self::EvalHint::*; use rustc::hir::map as ast_map; use rustc::hir::map::blocks::FnLikeNode; -use rustc::middle::cstore::{self, InlinedItem}; +use rustc::middle::cstore::InlinedItem; use rustc::traits; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; @@ -142,13 +142,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let mut used_substs = false; let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { + Some((&InlinedItem::Item(ref item), _)) => match item.node { hir::ItemConst(ref ty, ref const_expr) => { Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty))) }, _ => None }, - cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node { + Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node { hir::ConstTraitItem(_, _) => { used_substs = true; if let Some(substs) = substs { @@ -163,7 +163,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } _ => None }, - cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node { + Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node { hir::ImplItemKind::Const(ref ty, ref expr) => { Some((&**expr, tcx.ast_ty_to_prim_ty(ty))) }, @@ -198,8 +198,8 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id), - cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id), + Some((&InlinedItem::Item(ref item), _)) => Some(item.id), + Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id), _ => None }; tcx.extern_const_fns.borrow_mut().insert(def_id, diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 454c805ab577..c39ad414492e 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -88,8 +88,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, rbml_w.writer.seek(SeekFrom::Current(0))); // Folding could be avoided with a smarter encoder. - let ii = simplify_ast(ii); + let (ii, expected_id_range) = simplify_ast(ii); let id_range = inlined_item_id_range(&ii); + assert_eq!(expected_id_range, id_range); rbml_w.start_tag(c::tag_ast as usize); id_range.encode(rbml_w); @@ -186,6 +187,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId { // from_id_range should be non-empty assert!(!self.from_id_range.empty()); + // Make sure that translating the NodeId will actually yield a + // meaningful result + assert!(self.from_id_range.contains(id)); + // Use wrapping arithmetic because otherwise it introduces control flow. // Maybe we should just have the control flow? -- aatch (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min)) @@ -279,9 +284,23 @@ fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) { rbml_w.end_tag(); } -struct NestedItemsDropper; +struct NestedItemsDropper { + id_range: IdRange +} impl Folder for NestedItemsDropper { + + // The unit tests below run on HIR with NodeIds not properly assigned. That + // causes an integer overflow. So we just don't track the id_range when + // building the unit tests. + #[cfg(not(test))] + fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { + // Record the range of NodeIds we are visiting, so we can do a sanity + // check later + self.id_range.add(id); + id + } + fn fold_block(&mut self, blk: P) -> P { blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| { let stmts_sans_items = stmts.into_iter().filter_map(|stmt| { @@ -322,10 +341,12 @@ impl Folder for NestedItemsDropper { // As it happens, trans relies on the fact that we do not export // nested items, as otherwise it would get confused when translating // inlined items. -fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { - let mut fld = NestedItemsDropper; +fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) { + let mut fld = NestedItemsDropper { + id_range: IdRange::max() + }; - match ii { + let ii = match ii { // HACK we're not dropping items. InlinedItemRef::Item(i) => { InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld))) @@ -339,7 +360,9 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { InlinedItemRef::Foreign(i) => { InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld))) } - } + }; + + (ii, fld.id_range) } fn decode_ast(item_doc: rbml::Doc) -> InlinedItem { @@ -361,8 +384,18 @@ impl tr for Def { match *self { Def::Fn(did) => Def::Fn(did.tr(dcx)), Def::Method(did) => Def::Method(did.tr(dcx)), - Def::SelfTy(opt_did, impl_id) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)), - impl_id.map(|id| dcx.tr_id(id))) } + Def::SelfTy(opt_did, impl_id) => { + // Since the impl_id will never lie within the reserved range of + // imported NodeIds, it does not make sense to translate it. + // The result would not make any sense within the importing crate. + // We also don't allow for impl items to be inlined (just their + // members), so even if we had a DefId here, we wouldn't be able + // to do much with it. + // So, we set the id to DUMMY_NODE_ID. That way we make it + // explicit that this is no usable NodeId. + Def::SelfTy(opt_did.map(|did| did.tr(dcx)), + impl_id.map(|_| ast::DUMMY_NODE_ID)) + } Def::Mod(did) => { Def::Mod(did.tr(dcx)) } Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) } Def::Static(did, m) => { Def::Static(did.tr(dcx), m) } @@ -1361,7 +1394,7 @@ fn test_simplification() { with_testing_context(|lcx| { let hir_item = lcx.lower_item(&item); let item_in = InlinedItemRef::Item(&hir_item); - let item_out = simplify_ast(item_in); + let (item_out, _) = simplify_ast(item_in); let item_exp = InlinedItem::Item(P(lcx.lower_item("e_item!(&cx, fn new_int_alist() -> alist { return alist {eq_fn: eq_int, data: Vec::new()}; diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 850d6c91f66e..862245b9b786 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -14,7 +14,7 @@ use decoder; use encoder; use loader; -use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst, DefLike}; +use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use rustc::hir::def; use middle::lang_items; @@ -482,12 +482,146 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> FoundAst<'tcx> + fn maybe_get_item_ast<'a>(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option<(&'tcx InlinedItem, ast::NodeId)> { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::maybe_get_item_ast(&cdata, tcx, def.index) + self.dep_graph.read(DepNode::MetaData(def_id)); + + match self.inlined_item_cache.borrow().get(&def_id) { + Some(&None) => { + return None; // Not inlinable + } + Some(&Some(ref cached_inlined_item)) => { + // Already inline + debug!("maybe_get_item_ast({}): already inline as node id {}", + tcx.item_path_str(def_id), cached_inlined_item.item_id); + return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root), + cached_inlined_item.item_id)); + } + None => { + // Not seen yet + } + } + + debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id)); + + let cdata = self.get_crate_data(def_id.krate); + let inlined = decoder::maybe_get_item_ast(&cdata, tcx, def_id.index); + + let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| { + let cache_entry = cstore::CachedInlinedItem { + inlined_root: inlined_root_node_id, + item_id: inlined_item_id, + }; + self.inlined_item_cache + .borrow_mut() + .insert(original_def_id, Some(cache_entry)); + self.defid_for_inlined_node + .borrow_mut() + .insert(inlined_item_id, original_def_id); + }; + + let find_inlined_item_root = |inlined_item_id| { + let mut node = inlined_item_id; + let mut path = Vec::with_capacity(10); + + // If we can't find the inline root after a thousand hops, we can + // be pretty sure there's something wrong with the HIR map. + for _ in 0 .. 1000 { + path.push(node); + let parent_node = tcx.map.get_parent_node(node); + if parent_node == node { + return node; + } + node = parent_node; + } + bug!("cycle in HIR map parent chain") + }; + + match inlined { + decoder::FoundAst::NotFound => { + self.inlined_item_cache + .borrow_mut() + .insert(def_id, None); + } + decoder::FoundAst::Found(&InlinedItem::Item(ref item)) => { + let inlined_root_node_id = find_inlined_item_root(item.id); + cache_inlined_item(def_id, item.id, inlined_root_node_id); + } + decoder::FoundAst::Found(&InlinedItem::Foreign(ref item)) => { + let inlined_root_node_id = find_inlined_item_root(item.id); + cache_inlined_item(def_id, item.id, inlined_root_node_id); + } + decoder::FoundAst::FoundParent(parent_did, item) => { + let inlined_root_node_id = find_inlined_item_root(item.id); + cache_inlined_item(parent_did, item.id, inlined_root_node_id); + + match item.node { + hir::ItemEnum(ref ast_def, _) => { + let ast_vs = &ast_def.variants; + let ty_vs = &tcx.lookup_adt_def(parent_did).variants; + assert_eq!(ast_vs.len(), ty_vs.len()); + for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { + cache_inlined_item(ty_v.did, + ast_v.node.data.id(), + inlined_root_node_id); + } + } + hir::ItemStruct(ref struct_def, _) => { + if struct_def.is_struct() { + bug!("instantiate_inline: called on a non-tuple struct") + } else { + cache_inlined_item(def_id, + struct_def.id(), + inlined_root_node_id); + } + } + _ => bug!("instantiate_inline: item has a \ + non-enum, non-struct parent") + } + } + decoder::FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => { + let inlined_root_node_id = find_inlined_item_root(trait_item.id); + cache_inlined_item(def_id, trait_item.id, inlined_root_node_id); + + // Associated consts already have to be evaluated in `typeck`, so + // the logic to do that already exists in `middle`. In order to + // reuse that code, it needs to be able to look up the traits for + // inlined items. + let ty_trait_item = tcx.impl_or_trait_item(def_id).clone(); + let trait_item_def_id = tcx.map.local_def_id(trait_item.id); + tcx.impl_or_trait_items.borrow_mut() + .insert(trait_item_def_id, ty_trait_item); + } + decoder::FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => { + let inlined_root_node_id = find_inlined_item_root(impl_item.id); + cache_inlined_item(def_id, impl_item.id, inlined_root_node_id); + } + } + + // We can be sure to hit the cache now + return self.maybe_get_item_ast(tcx, def_id); + } + + fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option { + assert!(!def_id.is_local()); + match self.inlined_item_cache.borrow().get(&def_id) { + Some(&Some(ref cached_inlined_item)) => { + Some(cached_inlined_item.item_id) + } + Some(&None) => { + None + } + _ => { + bug!("Trying to lookup inlined NodeId for unexpected item"); + } + } + } + + fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option { + self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x) } fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -634,3 +768,4 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { visible_parent_map } } + diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 6baa0ac23f3f..d786cc5ba0eb 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -25,7 +25,7 @@ use rustc::dep_graph::DepGraph; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; -use rustc::middle::cstore::{ExternCrate}; +use rustc::middle::cstore::ExternCrate; use rustc::session::config::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; @@ -96,6 +96,13 @@ pub struct CrateMetadata { pub explicitly_linked: Cell, } +pub struct CachedInlinedItem { + /// The NodeId of the RootInlinedParent HIR map entry + pub inlined_root: ast::NodeId, + /// The local NodeId of the inlined entity + pub item_id: ast::NodeId, +} + pub struct CStore { pub dep_graph: DepGraph, metas: RefCell>>, @@ -105,6 +112,8 @@ pub struct CStore { used_libraries: RefCell>, used_link_args: RefCell>, statically_included_foreign_items: RefCell, + pub inlined_item_cache: RefCell>>, + pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, } @@ -119,6 +128,8 @@ impl CStore { used_link_args: RefCell::new(Vec::new()), statically_included_foreign_items: RefCell::new(NodeSet()), visible_parent_map: RefCell::new(FnvHashMap()), + inlined_item_cache: RefCell::new(FnvHashMap()), + defid_for_inlined_node: RefCell::new(FnvHashMap()), } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 24e8b33f44c7..d8fd25d62774 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -30,7 +30,7 @@ use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::session::config::PanicStrategy; -use middle::cstore::{FoundAst, InlinedItem, LinkagePreference}; +use middle::cstore::{InlinedItem, LinkagePreference}; use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; @@ -755,6 +755,12 @@ pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option { maybe_item_name(cdata.lookup_item(id)) } +pub enum FoundAst<'ast> { + Found(&'ast InlinedItem), + FoundParent(DefId, &'ast hir::Item), + NotFound, +} + pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) -> FoundAst<'tcx> { debug!("Looking up item: {:?}", id); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d057f623383d..61d8a0837c1d 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1235,7 +1235,6 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, inlined_vid: ast::NodeId) -> ty::VariantDef<'tcx> { - let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid); debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty, inlined_vid); @@ -1245,13 +1244,18 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }), ..}) => ty, _ => ctor_ty }.ty_adt_def().unwrap(); - let inlined_vid_def_id = ccx.tcx().map.local_def_id(inlined_vid); - adt_def.variants.iter().find(|v| { - inlined_vid_def_id == v.did || - ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid)) - }).unwrap_or_else(|| { - bug!("no variant for {:?}::{}", adt_def, inlined_vid) - }) + let variant_def_id = if ccx.tcx().map.is_inlined(inlined_vid) { + ccx.defid_for_inlined_node(inlined_vid).unwrap() + } else { + ccx.tcx().map.local_def_id(inlined_vid) + }; + + adt_def.variants + .iter() + .find(|v| variant_def_id == v.did) + .unwrap_or_else(|| { + bug!("no variant for {:?}::{}", adt_def, inlined_vid) + }) } // To avoid UB from LLVM, these two functions mask RHS with an diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 571d2731fb21..27048994254c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1026,7 +1026,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) .get(TransItem::Static(id)) .expect("Local statics should always be in the SymbolMap"); // Make sure that this is never executed for something inlined. - assert!(!ccx.external_srcs().borrow().contains_key(&id)); + assert!(!ccx.tcx().map.is_inlined(id)); let defined_in_current_codegen_unit = ccx.codegen_unit() .items() diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a8f8474e9407..5923f407df75 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -36,7 +36,7 @@ use session::config::NoDebugInfo; use session::Session; use symbol_map::SymbolMap; use util::sha2::Sha256; -use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -101,11 +101,6 @@ pub struct LocalCrateContext<'tcx> { needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, drop_glues: RefCell, (ValueRef, FnType)>>, - /// Track mapping of external ids to local items imported for inlining - external: RefCell>>, - /// Backwards version of the `external` map (inlined items to where they - /// came from) - external_srcs: RefCell>, /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, monomorphizing: RefCell>, @@ -572,8 +567,6 @@ impl<'tcx> LocalCrateContext<'tcx> { needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()), fn_pointer_shims: RefCell::new(FnvHashMap()), drop_glues: RefCell::new(FnvHashMap()), - external: RefCell::new(DefIdMap()), - external_srcs: RefCell::new(NodeMap()), instances: RefCell::new(FnvHashMap()), monomorphizing: RefCell::new(DefIdMap()), vtables: RefCell::new(FnvHashMap()), @@ -767,12 +760,12 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().drop_glues } - pub fn external<'a>(&'a self) -> &'a RefCell>> { - &self.local().external + pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option { + self.sess().cstore.local_node_for_inlined_defid(def_id) } - pub fn external_srcs<'a>(&'a self) -> &'a RefCell> { - &self.local().external_srcs + pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option { + self.sess().cstore.defid_for_inlined_node(node_id) } pub fn instances<'a>(&'a self) -> &'a RefCell, ValueRef>> { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 46813d957dce..858dcc1bb18c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -326,13 +326,12 @@ impl<'tcx> TypeMap<'tcx> { // First, find out the 'real' def_id of the type. Items inlined from // other crates have to be mapped back to their source. let def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) { - match cx.external_srcs().borrow().get(&node_id).cloned() { - Some(source_def_id) => { - // The given def_id identifies the inlined copy of a - // type definition, let's take the source of the copy. - source_def_id - } - None => def_id + if cx.tcx().map.is_inlined(node_id) { + // The given def_id identifies the inlined copy of a + // type definition, let's take the source of the copy. + cx.defid_for_inlined_node(node_id).unwrap() + } else { + def_id } } else { def_id @@ -1842,7 +1841,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, // crate should already contain debuginfo for it. More importantly, the // global might not even exist in un-inlined form anywhere which would lead // to a linker errors. - if cx.external_srcs().borrow().contains_key(&node_id) { + if cx.tcx().map.is_inlined(node_id) { return; } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 8c5b3ed54c2f..e8a28d55a73c 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -439,10 +439,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }); // Try to get some span information, if we have an inlined item. - let definition_span = match cx.external().borrow().get(&instance.def) { - Some(&Some(node_id)) => cx.tcx().map.span(node_id), - _ => cx.tcx().map.def_id_span(instance.def, syntax_pos::DUMMY_SP) - }; + let definition_span = cx.tcx() + .map + .def_id_span(instance.def, syntax_pos::DUMMY_SP); (containing_scope, definition_span) } diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 1e0afa4534b1..facdfe73ddc8 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -86,10 +86,7 @@ pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId) }); // Try to get some span information, if we have an inlined item. - let definition_span = match cx.external().borrow().get(&def_id) { - Some(&Some(node_id)) => cx.tcx().map.span(node_id), - _ => cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP) - }; + let definition_span = cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP); (containing_scope, definition_span) } diff --git a/src/librustc_trans/inline.rs b/src/librustc_trans/inline.rs index 4077b894d62d..8581fccf10ab 100644 --- a/src/librustc_trans/inline.rs +++ b/src/librustc_trans/inline.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::cstore::{FoundAst, InlinedItem}; use rustc::hir::def_id::DefId; use base::push_ctxt; use common::*; use monomorphize::Instance; use rustc::dep_graph::DepNode; -use rustc::hir; fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { debug!("instantiate_inline({:?})", fn_id); @@ -23,104 +21,12 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { let tcx = ccx.tcx(); let _task = tcx.dep_graph.in_task(DepNode::TransInlinedItem(fn_id)); - match ccx.external().borrow().get(&fn_id) { - Some(&Some(node_id)) => { - // Already inline - debug!("instantiate_inline({}): already inline as node id {}", - tcx.item_path_str(fn_id), node_id); - let node_def_id = tcx.map.local_def_id(node_id); - return Some(node_def_id); - } - Some(&None) => { - return None; // Not inlinable - } - None => { - // Not seen yet - } - } - - let inlined = tcx.sess.cstore.maybe_get_item_ast(tcx, fn_id); - let inline_id = match inlined { - FoundAst::NotFound => { - ccx.external().borrow_mut().insert(fn_id, None); - return None; - } - FoundAst::Found(&InlinedItem::Item(ref item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(item.id)); - ccx.external_srcs().borrow_mut().insert(item.id, fn_id); - - ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); - - item.id - } - FoundAst::Found(&InlinedItem::Foreign(ref item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(item.id)); - ccx.external_srcs().borrow_mut().insert(item.id, fn_id); - item.id - } - FoundAst::FoundParent(parent_id, item) => { - ccx.external().borrow_mut().insert(parent_id, Some(item.id)); - ccx.external_srcs().borrow_mut().insert(item.id, parent_id); - - let mut my_id = 0; - match item.node { - hir::ItemEnum(ref ast_def, _) => { - let ast_vs = &ast_def.variants; - let ty_vs = &tcx.lookup_adt_def(parent_id).variants; - assert_eq!(ast_vs.len(), ty_vs.len()); - for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { - if ty_v.did == fn_id { my_id = ast_v.node.data.id(); } - ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id())); - ccx.external_srcs().borrow_mut().insert(ast_v.node.data.id(), ty_v.did); - } - } - hir::ItemStruct(ref struct_def, _) => { - if struct_def.is_struct() { - bug!("instantiate_inline: called on a \ - non-tuple struct") - } else { - ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id())); - ccx.external_srcs().borrow_mut().insert(struct_def.id(), fn_id); - my_id = struct_def.id(); - } - } - _ => bug!("instantiate_inline: item has a \ - non-enum, non-struct parent") - } - my_id - } - FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(trait_item.id)); - ccx.external_srcs().borrow_mut().insert(trait_item.id, fn_id); - - ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); - - // Associated consts already have to be evaluated in `typeck`, so - // the logic to do that already exists in `middle`. In order to - // reuse that code, it needs to be able to look up the traits for - // inlined items. - let ty_trait_item = tcx.impl_or_trait_item(fn_id).clone(); - let trait_item_def_id = tcx.map.local_def_id(trait_item.id); - tcx.impl_or_trait_items.borrow_mut() - .insert(trait_item_def_id, ty_trait_item); - - // If this is a default method, we can't look up the - // impl type. But we aren't going to translate anyways, so - // don't. - trait_item.id - } - FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(impl_item.id)); - ccx.external_srcs().borrow_mut().insert(impl_item.id, fn_id); - - ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); - - impl_item.id - } - }; - - let inline_def_id = tcx.map.local_def_id(inline_id); - Some(inline_def_id) + tcx.sess + .cstore + .maybe_get_item_ast(tcx, fn_id) + .map(|(_, inline_id)| { + tcx.map.local_def_id(inline_id) + }) } pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b642a7122194..3b2bca4ab391 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1313,6 +1313,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // item is declared. let bound = match (&ty.sty, ty_path_def) { (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => { + // For Def::SelfTy() values inlined from another crate, the + // impl_id will be DUMMY_NODE_ID, which would cause problems + // here. But we should never run into an impl from another crate + // in this pass. + assert!(impl_id != ast::DUMMY_NODE_ID); + // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap(); @@ -1518,6 +1524,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::SelfTy(_, Some(impl_id)) => { // Self in impl (we know the concrete type). + + // For Def::SelfTy() values inlined from another crate, the + // impl_id will be DUMMY_NODE_ID, which would cause problems + // here. But we should never run into an impl from another crate + // in this pass. + assert!(impl_id != ast::DUMMY_NODE_ID); + tcx.prohibit_type_params(base_segments); let ty = tcx.node_id_to_type(impl_id); if let Some(free_substs) = self.get_free_substs() { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6883c22d6752..d609ad84a838 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2691,7 +2691,12 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Static(i, _) => (i, TypeStatic), Def::Variant(i, _) => (i, TypeEnum), Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait), - Def::SelfTy(_, Some(impl_id)) => return cx.map.local_def_id(impl_id), + Def::SelfTy(_, Some(impl_id)) => { + // For Def::SelfTy() values inlined from another crate, the + // impl_id will be DUMMY_NODE_ID, which would cause problems. + // But we should never run into an impl from another crate here. + return cx.map.local_def_id(impl_id) + } _ => return def.def_id() }; if did.is_local() { return did } From 5d1d2475232d06b2a315d87481898819bb547f97 Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Mon, 1 Aug 2016 10:14:30 +0200 Subject: [PATCH 258/331] Upgrade LLVM once more to get a bugfix @tmiasko did some digging and discovered that https://reviews.llvm.org/D22858 may be relevant. --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index 327e422d9b9d..d1cc48989b13 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 327e422d9b9df5bc02d947b69d8020817b5a2bfc +Subproject commit d1cc48989b13780f21c408fef17dceb104a09c9d From 59cfe904dcfbe2c3ad5396131b3d3ba6b7179fdd Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 13 Jul 2016 17:03:02 -0400 Subject: [PATCH 259/331] trans: Avoid weak linkage for closures when linking with MinGW. --- src/librustc/session/config.rs | 6 +- src/librustc_back/target/mod.rs | 10 +++ src/librustc_back/target/windows_base.rs | 1 + src/librustc_trans/closure.rs | 77 +++++++++++++++++++++++- src/librustc_trans/mir/constant.rs | 22 +------ src/librustc_trans/mir/rvalue.rs | 22 +------ 6 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 34df476e5c82..cdde6d6f63dd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -330,6 +330,11 @@ impl Options { self.debugging_opts.dump_dep_graph || self.debugging_opts.query_dep_graph } + + pub fn single_codegen_unit(&self) -> bool { + self.incremental.is_none() || + self.cg.codegen_units == 1 + } } // The type of entry function, so @@ -655,7 +660,6 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "panic strategy to compile crate with"), } - options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, build_debugging_options, "Z", "debugging", DB_OPTIONS, db_type_desc, dbsetters, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index ecfbeaca3517..3d24fd8ab67e 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -292,6 +292,13 @@ pub struct TargetOptions { pub is_like_android: bool, /// Whether the linker support GNU-like arguments such as -O. Defaults to false. pub linker_is_gnu: bool, + /// The MinGW toolchain has a known issue that prevents it from correctly + /// handling COFF object files with more than 2^15 sections. Since each weak + /// symbol needs its own COMDAT section, weak linkage implies a large + /// number sections that easily exceeds the given limit for larger + /// codebases. Consequently we want a way to disallow weak linkage on some + /// platforms. + pub allows_weak_linkage: bool, /// Whether the linker support rpaths or not. Defaults to false. pub has_rpath: bool, /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM @@ -367,6 +374,7 @@ impl Default for TargetOptions { is_like_android: false, is_like_msvc: false, linker_is_gnu: false, + allows_weak_linkage: true, has_rpath: false, no_compiler_rt: false, no_default_libraries: true, @@ -509,6 +517,7 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_android, bool); key!(linker_is_gnu, bool); + key!(allows_weak_linkage, bool); key!(has_rpath, bool); key!(no_compiler_rt, bool); key!(no_default_libraries, bool); @@ -651,6 +660,7 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_android); target_option_val!(linker_is_gnu); + target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); target_option_val!(no_compiler_rt); target_option_val!(no_default_libraries); diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index 1e46f45bdcf4..c398ee40f2f9 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -25,6 +25,7 @@ pub fn opts() -> TargetOptions { staticlib_suffix: ".lib".to_string(), no_default_libraries: true, is_like_windows: true, + allows_weak_linkage: false, pre_link_args: vec!( // And here, we see obscure linker flags #45. On windows, it has been // found to be necessary to have this flag to compile liblibc. diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 90443d9ec4f7..6b9de4a48786 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -181,6 +181,41 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } +fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext, + closure_def_id: DefId) + -> bool { + let default_to_mir = ccx.sess().opts.debugging_opts.orbit; + let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" }; + let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert); + + !use_mir +} + +pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + closure_def_id: DefId, + closure_substs: ty::ClosureSubsts<'tcx>) { + use syntax::ast::DUMMY_NODE_ID; + use syntax_pos::DUMMY_SP; + use syntax::ptr::P; + + trans_closure_expr(Dest::Ignore(ccx), + &hir::FnDecl { + inputs: P::new(), + output: hir::NoReturn(DUMMY_SP), + variadic: false + }, + &hir::Block { + stmts: P::new(), + expr: None, + id: DUMMY_NODE_ID, + rules: hir::DefaultBlock, + span: DUMMY_SP + }, + DUMMY_NODE_ID, + closure_def_id, + closure_substs); +} + pub enum Dest<'a, 'tcx: 'a> { SaveIn(Block<'a, 'tcx>, ValueRef), Ignore(&'a CrateContext<'a, 'tcx>) @@ -213,8 +248,13 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // If we have not done so yet, translate this closure's body if !ccx.instances().borrow().contains_key(&instance) { let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); - llvm::SetLinkage(llfn, llvm::WeakODRLinkage); - llvm::SetUniqueComdat(ccx.llmod(), llfn); + + if ccx.sess().target.target.options.allows_weak_linkage { + llvm::SetLinkage(llfn, llvm::WeakODRLinkage); + llvm::SetUniqueComdat(ccx.llmod(), llfn); + } else { + llvm::SetLinkage(llfn, llvm::InternalLinkage); + } // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); @@ -296,6 +336,39 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, // If this is a closure, redirect to it. let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs); + // If weak linkage is not allowed, we have to make sure that a local, + // private copy of the closure is available in this codegen unit + if !ccx.sess().target.target.options.allows_weak_linkage && + !ccx.sess().opts.single_codegen_unit() { + + if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) { + // If the closure is defined in the local crate, we can always just + // translate it. + let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node { + hir::ExprClosure(_, ref decl, ref body, _) => (decl, body), + _ => { unreachable!() } + }; + + trans_closure_expr(Dest::Ignore(ccx), + decl, + body, + node_id, + closure_def_id, + substs); + } else { + // If the closure is defined in an upstream crate, we can only + // translate it if MIR-trans is active. + + if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) { + ccx.sess().fatal("You have run into a known limitation of the \ + MingW toolchain. Either compile with -Zorbit or \ + with -Ccodegen-units=1 to work around it."); + } + + trans_closure_body_via_mir(ccx, closure_def_id, substs); + } + } + // If the closure is a Fn closure, but a FnOnce is needed (etc), // then adapt the self type let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1f3b13203163..8dc5e5f993fb 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -530,26 +530,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { // FIXME Shouldn't need to manually trigger closure instantiations. if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use rustc::hir; - use syntax::ast::DUMMY_NODE_ID; - use syntax::ptr::P; use closure; - - closure::trans_closure_expr(closure::Dest::Ignore(self.ccx), - &hir::FnDecl { - inputs: P::new(), - output: hir::NoReturn(DUMMY_SP), - variadic: false - }, - &hir::Block { - stmts: P::new(), - expr: None, - id: DUMMY_NODE_ID, - rules: hir::DefaultBlock, - span: DUMMY_SP - }, - DUMMY_NODE_ID, def_id, - self.monomorphize(&substs)); + closure::trans_closure_body_via_mir(self.ccx, + def_id, + self.monomorphize(&substs)); } let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index c3f2c4f2c8bf..6ebc23884918 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -131,27 +131,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { _ => { // FIXME Shouldn't need to manually trigger closure instantiations. if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use rustc::hir; - use syntax::ast::DUMMY_NODE_ID; - use syntax::ptr::P; - use syntax_pos::DUMMY_SP; use closure; - closure::trans_closure_expr(closure::Dest::Ignore(bcx.ccx()), - &hir::FnDecl { - inputs: P::new(), - output: hir::NoReturn(DUMMY_SP), - variadic: false - }, - &hir::Block { - stmts: P::new(), - expr: None, - id: DUMMY_NODE_ID, - rules: hir::DefaultBlock, - span: DUMMY_SP - }, - DUMMY_NODE_ID, def_id, - bcx.monomorphize(&substs)); + closure::trans_closure_body_via_mir(bcx.ccx(), + def_id, + bcx.monomorphize(&substs)); } for (i, operand) in operands.iter().enumerate() { From eaea4ac8acbb46395f08b78452bfc758280e1421 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 12 Jul 2016 17:39:08 -0400 Subject: [PATCH 260/331] Add test case for large number of closures within one codegen unit --- src/test/run-pass/myriad-closures.rs | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/test/run-pass/myriad-closures.rs diff --git a/src/test/run-pass/myriad-closures.rs b/src/test/run-pass/myriad-closures.rs new file mode 100644 index 000000000000..d2c9a5d562b0 --- /dev/null +++ b/src/test/run-pass/myriad-closures.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test case tests whether we can handle code bases that contain a high +// number of closures, something that needs special handling in the MingGW +// toolchain. +// See https://github.com/rust-lang/rust/issues/34793 for more information. + +// Expand something exponentially +macro_rules! go_bacterial { + ($mac:ident) => ($mac!()); + ($mac:ident 1 $($t:tt)*) => ( + go_bacterial!($mac $($t)*); + go_bacterial!($mac $($t)*); + ) +} + +macro_rules! mk_closure { + () => ({ + let c = |a: u32| a + 4; + let _ = c(2); + }) +} + +macro_rules! mk_fn { + () => { + { + fn function() { + // Make 16 closures + go_bacterial!(mk_closure 1 1 1 1); + } + let _ = function(); + } + } +} + +fn main() { + // Make 2^12 functions, each containing 16 closures, + // resulting in 2^16 closures overall. + go_bacterial!(mk_fn 1 1 1 1 1 1 1 1 1 1 1 1); +} From d7a04403aed9d1e5d85b44fdd16bbfded2ebb5fe Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Mon, 1 Aug 2016 18:03:22 +0900 Subject: [PATCH 261/331] Remove CMake workaround --- src/etc/Dockerfile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/etc/Dockerfile b/src/etc/Dockerfile index 94be84a3ebd4..83d54789ff35 100644 --- a/src/etc/Dockerfile +++ b/src/etc/Dockerfile @@ -23,11 +23,5 @@ RUN apt-get update && apt-get -y install \ libedit-dev zlib1g-dev \ llvm-3.7-tools cmake -# When we compile compiler-rt we pass it the llvm-config we just installed on -# the system, but unfortunately it doesn't infer correctly where -# LLVMConfig.cmake is so we need to coerce it a bit... -RUN mkdir -p /usr/lib/llvm-3.7/build/share/llvm -RUN ln -s /usr/share/llvm-3.7/cmake /usr/lib/llvm-3.7/build/share/llvm/cmake - RUN mkdir /build WORKDIR /build From dc259de2e394a066a9e9e616890d12867b2d8a98 Mon Sep 17 00:00:00 2001 From: cgswords Date: Tue, 19 Jul 2016 15:50:34 -0700 Subject: [PATCH 262/331] Reimplemented tokenstreams as ropes and reduced the exposed TokenStream API. --- src/libsyntax/codemap.rs | 17 + src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/tokenstream.rs | 983 +++++++++++++---------------------- 3 files changed, 383 insertions(+), 619 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index a8aca90e6238..b176b8fefc61 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -71,6 +71,23 @@ pub fn dummy_spanned(t: T) -> Spanned { respan(DUMMY_SP, t) } +/// Build a span that covers the two provided spans. +pub fn combine_spans(sp1: Span, sp2: Span) -> Span { + if sp1 == DUMMY_SP && sp2 == DUMMY_SP { + DUMMY_SP + } else if sp1 == DUMMY_SP { + sp2 + } else if sp2 == DUMMY_SP { + sp1 + } else { + Span { + lo: if sp1.lo < sp2.lo { sp1.lo } else { sp2.lo }, + hi: if sp1.hi > sp2.hi { sp1.hi } else { sp2.hi }, + expn_id: if sp1.expn_id == sp2.expn_id { sp1.expn_id } else { NO_EXPANSION }, + } + } +} + #[derive(Clone, Hash, Debug)] pub struct NameAndSpan { /// The format with which the macro was invoked. diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 2147e8ec2eb1..7b28952aff6b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -237,7 +237,7 @@ pub fn new_parser_from_ts<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, ts: tokenstream::TokenStream) -> Parser<'a> { - tts_to_parser(sess, ts.tts, cfg) + tts_to_parser(sess, ts.to_tts(), cfg) } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index d38edf816880..89ead21cc10c 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -16,27 +16,27 @@ //! or a SequenceRepetition specifier (for the purpose of sequence generation during macro //! expansion). //! -//! A TokenStream also has a slice view, `TokenSlice`, that is analogous to `str` for -//! `String`: it allows the programmer to divvy up, explore, and otherwise partition a -//! TokenStream as borrowed subsequences. +//! ## Ownership +//! TokenStreams are persistant data structures construced as ropes with reference +//! counted-children. In general, this means that calling an operation on a TokenStream +//! (such as `slice`) produces an entirely new TokenStream from the borrowed reference to +//! the original. This essentially coerces TokenStreams into 'views' of their subparts, +//! and a borrowed TokenStream is sufficient to build an owned TokenStream without taking +//! ownership of the original. use ast::{self, AttrStyle, LitKind}; use syntax_pos::{Span, DUMMY_SP, NO_EXPANSION}; -use codemap::Spanned; +use codemap::{Spanned, combine_spans}; use ext::base; use ext::tt::macro_parser; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::lexer; use parse; -use parse::token::{self, Token, Lit, InternedString, Nonterminal}; -use parse::token::Lit as TokLit; +use parse::token::{self, Token, Lit, Nonterminal}; use std::fmt; -use std::mem; -use std::ops::Index; -use std::ops; use std::iter::*; - +use std::ops::{self, Index}; use std::rc::Rc; /// A delimited sequence of token trees @@ -335,27 +335,51 @@ impl TokenTree { /// struct itself shouldn't be directly manipulated; the internal structure is not stable, /// and may be changed at any time in the future. The operators will not, however (except /// for signatures, later on). -#[derive(Eq,Clone,Hash,RustcEncodable,RustcDecodable)] +#[derive(Clone, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TokenStream { - pub span: Span, - pub tts: Vec, + ts: InternalTS, +} + +// NB If Leaf access proves to be slow, inroducing a secondary Leaf without the bounds +// for unsliced Leafs may lead to some performance improvemenet. +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum InternalTS { + Empty(Span), + Leaf { + tts: Rc>, + offset: usize, + len: usize, + sp: Span, + }, + Node { + left: Rc, + right: Rc, + len: usize, + sp: Span, + }, } impl fmt::Debug for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.tts.len() == 0 { - write!(f, "([empty")?; - } else { - write!(f, "([")?; - write!(f, "{:?}", self.tts[0])?; + self.ts.fmt(f) + } +} - for tt in self.tts.iter().skip(1) { - write!(f, ",{:?}", tt)?; +impl fmt::Debug for InternalTS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InternalTS::Empty(..) => Ok(()), + InternalTS::Leaf { ref tts, offset, len, .. } => { + for t in tts.iter().skip(offset).take(len) { + try!(write!(f, "{:?}", t)); + } + Ok(()) + } + InternalTS::Node { ref left, ref right, .. } => { + try!(left.fmt(f)); + right.fmt(f) } } - write!(f, "|")?; - self.span.fmt(f)?; - write!(f, "])") } } @@ -363,7 +387,7 @@ impl fmt::Debug for TokenStream { /// equality, see `eq_unspanned`. impl PartialEq for TokenStream { fn eq(&self, other: &TokenStream) -> bool { - self.tts == other.tts + self.iter().eq(other.iter()) } } @@ -408,6 +432,59 @@ fn covering_span(trees: &[TokenTree]) -> Span { } } +impl InternalTS { + fn len(&self) -> usize { + match *self { + InternalTS::Empty(..) => 0, + InternalTS::Leaf { len, .. } => len, + InternalTS::Node { len, .. } => len, + } + } + + fn span(&self) -> Span { + match *self { + InternalTS::Empty(sp) | + InternalTS::Leaf { sp, .. } | + InternalTS::Node { sp, .. } => sp, + } + } + + fn slice(&self, range: ops::Range) -> TokenStream { + let from = range.start; + let to = range.end; + if from == to { + return TokenStream::mk_empty(); + } + if from > to { + panic!("Invalid range: {} to {}", from, to); + } + if from == 0 && to == self.len() { + return TokenStream { ts: self.clone() }; /* should be cheap */ + } + match *self { + InternalTS::Empty(..) => panic!("Invalid index"), + InternalTS::Leaf { ref tts, offset, .. } => { + let offset = offset + from; + let len = to - from; + TokenStream::mk_sub_leaf(tts.clone(), + offset, + len, + covering_span(&tts[offset..offset + len])) + } + InternalTS::Node { ref left, ref right, .. } => { + let left_len = left.len(); + if to <= left_len { + left.slice(range) + } else if from >= left_len { + right.slice(from - left_len..to - left_len) + } else { + TokenStream::concat(left.slice(from..left_len), right.slice(0..to - left_len)) + } + } + } + } +} + /// TokenStream operators include basic destructuring, boolean operations, `maybe_...` /// operations, and `maybe_..._prefix` operations. Boolean operations are straightforward, /// indicating information about the structure of the stream. The `maybe_...` operations @@ -419,129 +496,149 @@ fn covering_span(trees: &[TokenTree]) -> Span { /// /// `maybe_path_prefix("a::b::c(a,b,c).foo()") -> (a::b::c, "(a,b,c).foo()")` impl TokenStream { - /// Convert a vector of `TokenTree`s into a `TokenStream`. - pub fn from_tts(trees: Vec) -> TokenStream { - let span = covering_span(&trees); + pub fn mk_empty() -> TokenStream { + TokenStream { ts: InternalTS::Empty(DUMMY_SP) } + } + + fn mk_spanned_empty(sp: Span) -> TokenStream { + TokenStream { ts: InternalTS::Empty(sp) } + } + + fn mk_leaf(tts: Rc>, sp: Span) -> TokenStream { + let len = tts.len(); TokenStream { - tts: trees, - span: span, + ts: InternalTS::Leaf { + tts: tts, + offset: 0, + len: len, + sp: sp, + }, } } - /// Copies all of the TokenTrees from the TokenSlice, appending them to the stream. - pub fn append_stream(mut self, ts2: &TokenSlice) { - for tt in ts2.iter() { - self.tts.push(tt.clone()); + fn mk_sub_leaf(tts: Rc>, offset: usize, len: usize, sp: Span) -> TokenStream { + TokenStream { + ts: InternalTS::Leaf { + tts: tts, + offset: offset, + len: len, + sp: sp, + }, } - self.span = covering_span(&self.tts[..]); + } + + fn mk_int_node(left: Rc, + right: Rc, + len: usize, + sp: Span) + -> TokenStream { + TokenStream { + ts: InternalTS::Node { + left: left, + right: right, + len: len, + sp: sp, + }, + } + } + + /// Convert a vector of `TokenTree`s into a `TokenStream`. + pub fn from_tts(trees: Vec) -> TokenStream { + let span = covering_span(&trees[..]); + TokenStream::mk_leaf(Rc::new(trees), span) } /// Manually change a TokenStream's span. pub fn respan(self, span: Span) -> TokenStream { - TokenStream { - tts: self.tts, - span: span, - } - } - - /// Construct a TokenStream from an ast literal. - pub fn from_ast_lit_str(lit: ast::Lit) -> Option { - match lit.node { - LitKind::Str(val, _) => { - let val = TokLit::Str_(token::intern(&val)); - Some(TokenStream::from_tts(vec![TokenTree::Token(lit.span, - Token::Literal(val, None))])) + match self.ts { + InternalTS::Empty(..) => TokenStream::mk_spanned_empty(span), + InternalTS::Leaf { tts, offset, len, .. } => { + TokenStream::mk_sub_leaf(tts, offset, len, span) + } + InternalTS::Node { left, right, len, .. } => { + TokenStream::mk_int_node(left, right, len, span) } - _ => None, } - } - /// Convert a vector of TokenTrees into a parentheses-delimited TokenStream. - pub fn as_paren_delimited_stream(tts: Vec) -> TokenStream { - let new_sp = covering_span(&tts); - - let new_delim = Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: DUMMY_SP, - tts: tts, - close_span: DUMMY_SP, - }); - - TokenStream::from_tts(vec![TokenTree::Delimited(new_sp, new_delim)]) + /// Concatenates two TokenStreams into a new TokenStream + pub fn concat(left: TokenStream, right: TokenStream) -> TokenStream { + let new_len = left.len() + right.len(); + let new_span = combine_spans(left.span(), right.span()); + TokenStream::mk_int_node(Rc::new(left.ts), Rc::new(right.ts), new_len, new_span) } - /// Convert an interned string into a one-element TokenStream. - pub fn from_interned_string_as_ident(s: InternedString) -> TokenStream { - TokenStream::from_tts(vec![TokenTree::Token(DUMMY_SP, - Token::Ident(token::str_to_ident(&s[..])))]) - } -} - -/// TokenSlices are 'views' of `TokenStream's; they fit the same role as `str`s do for -/// `String`s. In general, most TokenStream manipulations will be refocusing their internal -/// contents by taking a TokenSlice and then using indexing and the provided operators. -#[derive(PartialEq, Eq, Debug)] -pub struct TokenSlice([TokenTree]); - -impl ops::Deref for TokenStream { - type Target = TokenSlice; - - fn deref(&self) -> &TokenSlice { - let tts: &[TokenTree] = &*self.tts; - unsafe { mem::transmute(tts) } - } -} - -impl TokenSlice { - /// Convert a borrowed TokenTree slice into a borrowed TokenSlice. - fn from_tts(tts: &[TokenTree]) -> &TokenSlice { - unsafe { mem::transmute(tts) } - } - - /// Indicates whether the `TokenStream` is empty. + /// Indicate if the TokenStream is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } - /// Return the `TokenSlice`'s length. + /// Return a TokenStream's length. pub fn len(&self) -> usize { - self.0.len() + self.ts.len() } - /// Check equality versus another TokenStream, ignoring span information. - pub fn eq_unspanned(&self, other: &TokenSlice) -> bool { - if self.len() != other.len() { - return false; - } - for (tt1, tt2) in self.iter().zip(other.iter()) { - if !tt1.eq_unspanned(tt2) { - return false; + /// Convert a TokenStream into a vector of borrowed TokenTrees. + pub fn to_vec(&self) -> Vec<&TokenTree> { + fn internal_to_vec(ts: &InternalTS) -> Vec<&TokenTree> { + match *ts { + InternalTS::Empty(..) => Vec::new(), + InternalTS::Leaf { ref tts, offset, len, .. } => { + tts[offset..offset + len].iter().collect() + } + InternalTS::Node { ref left, ref right, .. } => { + let mut v1 = internal_to_vec(left); + let mut v2 = internal_to_vec(right); + v1.append(&mut v2); + v1 + } } } - true + internal_to_vec(&self.ts) } - /// Compute a span that covers the entire TokenSlice (eg, one wide enough to include - /// the entire slice). If the inputs share expansion identification, it is preserved. - /// If they do not, it is discarded. - pub fn covering_span(&self) -> Span { - covering_span(&self.0) + /// Convert a TokenStream into a vector of TokenTrees (by cloning the TokenTrees). + /// (This operation is an O(n) deep copy of the underlying structure.) + pub fn to_tts(&self) -> Vec { + self.to_vec().into_iter().cloned().collect::>() } - /// Indicates where the stream is of the form `= `, where `` is a continued - /// `TokenStream`. - pub fn is_assignment(&self) -> bool { - self.maybe_assignment().is_some() + /// Return the TokenStream's span. + pub fn span(&self) -> Span { + self.ts.span() } - /// Returns the RHS of an assigment. - pub fn maybe_assignment(&self) -> Option<&TokenSlice> { - if !(self.len() > 1) { - return None; + /// Returns an iterator over a TokenStream (as a sequence of TokenTrees). + pub fn iter<'a>(&self) -> Iter { + Iter { vs: self, idx: 0 } + } + + /// Splits a TokenStream based on the provided `&TokenTree -> bool` predicate. + pub fn split

(&self, pred: P) -> Split

+ where P: FnMut(&TokenTree) -> bool + { + Split { + vs: self, + pred: pred, + finished: false, + idx: 0, } + } - Some(&self[1..]) + /// Produce a slice of the input TokenStream from the `from` index, inclusive, to the + /// `to` index, non-inclusive. + pub fn slice(&self, range: ops::Range) -> TokenStream { + self.ts.slice(range) + } + + /// Slice starting at the provided index, inclusive. + pub fn slice_from(&self, from: ops::RangeFrom) -> TokenStream { + self.slice(from.start..self.len()) + } + + /// Slice up to the provided index, non-inclusive. + pub fn slice_to(&self, to: ops::RangeTo) -> TokenStream { + self.slice(0..to.end) } /// Indicates where the stream is a single, delimited expression (e.g., `(a,b,c)` or @@ -551,50 +648,15 @@ impl TokenSlice { } /// Returns the inside of the delimited term as a new TokenStream. - pub fn maybe_delimited(&self) -> Option<&TokenSlice> { + pub fn maybe_delimited(&self) -> Option { if !(self.len() == 1) { return None; } + // FIXME It would be nice to change Delimited to move the Rc around the TokenTree + // vector directly in order to avoid the clone here. match self[0] { - TokenTree::Delimited(_, ref rc) => Some(TokenSlice::from_tts(&*rc.tts)), - _ => None, - } - } - - /// Returns a list of `TokenSlice`s if the stream is a delimited list, breaking the - /// stream on commas. - pub fn maybe_comma_list(&self) -> Option> { - let maybe_tts = self.maybe_delimited(); - - let ts: &TokenSlice; - match maybe_tts { - Some(t) => { - ts = t; - } - None => { - return None; - } - } - - let splits: Vec<&TokenSlice> = ts.split(|x| match *x { - TokenTree::Token(_, Token::Comma) => true, - _ => false, - }) - .filter(|x| x.len() > 0) - .collect(); - - Some(splits) - } - - /// Returns a Nonterminal if it is Interpolated. - pub fn maybe_interpolated_nonterminal(&self) -> Option { - if !(self.len() == 1) { - return None; - } - - match self[0] { - TokenTree::Token(_, Token::Interpolated(ref nt)) => Some(nt.clone()), + TokenTree::Delimited(_, ref rc) => Some(TokenStream::from_tts(rc.tts.clone())), _ => None, } } @@ -610,180 +672,54 @@ impl TokenSlice { return None; } - let tok = if let Some(tts) = self.maybe_delimited() { - if tts.len() != 1 { - return None; - } - &tts[0] - } else { - &self[0] - }; - - match *tok { + match self[0] { TokenTree::Token(_, Token::Ident(t)) => Some(t), _ => None, } } - /// Indicates if the stream is exactly one literal - pub fn is_lit(&self) -> bool { - self.maybe_lit().is_some() - } - - /// Returns a literal - pub fn maybe_lit(&self) -> Option { - if !(self.len() == 1) { - return None; - } - - let tok = if let Some(tts) = self.maybe_delimited() { - if tts.len() != 1 { - return None; - } - &tts[0] - } else { - &self[0] - }; - - match *tok { - TokenTree::Token(_, Token::Literal(l, _)) => Some(l), - _ => None, - } - } - - /// Returns an AST string literal if the TokenStream is either a normal ('cooked') or - /// raw string literal. - pub fn maybe_str(&self) -> Option { - if !(self.len() == 1) { - return None; - } - - match self[0] { - TokenTree::Token(sp, Token::Literal(Lit::Str_(s), _)) => { - let l = LitKind::Str(token::intern_and_get_ident(&parse::str_lit(&s.as_str())), - ast::StrStyle::Cooked); - Some(Spanned { - node: l, - span: sp, - }) - } - TokenTree::Token(sp, Token::Literal(Lit::StrRaw(s, n), _)) => { - let l = LitKind::Str(token::intern_and_get_ident(&parse::raw_str_lit(&s.as_str())), - ast::StrStyle::Raw(n)); - Some(Spanned { - node: l, - span: sp, - }) - } - _ => None, - } - } - - /// This operation extracts the path prefix , returning an AST path struct and the remainder - /// of the stream (if it finds one). To be more specific, a tokenstream that has a valid, - /// non-global path as a prefix (eg `foo(bar, baz)`, `foo::bar(bar)`, but *not* - /// `::foo::bar(baz)`) will yield the path and the remaining tokens (as a slice). The previous - /// examples will yield - /// `Some((Path { segments = vec![foo], ... }, [(bar, baz)]))`, - /// `Some((Path { segments = vec![foo, bar] }, [(baz)]))`, - /// and `None`, respectively. - pub fn maybe_path_prefix(&self) -> Option<(ast::Path, &TokenSlice)> { - let mut segments: Vec = Vec::new(); - - let path: Vec<&TokenTree> = self.iter() - .take_while(|x| x.is_ident() || x.eq_token(Token::ModSep)) - .collect::>(); - - let path_size = path.len(); - if path_size == 0 { - return None; - } - - let cov_span = self[..path_size].covering_span(); - let rst = &self[path_size..]; - - let fst_id = path[0]; - - if let Some(id) = fst_id.maybe_ident() { - segments.push(ast::PathSegment { - identifier: id, - parameters: ast::PathParameters::none(), - }); - } else { - return None; - } - - // Let's use a state machine to parse out the rest. - enum State { - Mod, // Expect a `::`, or return None otherwise. - Ident, // Expect an ident, or return None otherwise. - } - let mut state = State::Mod; - - for p in &path[1..] { - match state { - State::Mod => { - // State 0: ['::' -> state 1, else return None] - if p.eq_token(Token::ModSep) { - state = State::Ident; - } else { - return None; - } - } - State::Ident => { - // State 1: [ident -> state 0, else return None] - if let Some(id) = p.maybe_ident() { - segments.push(ast::PathSegment { - identifier: id, - parameters: ast::PathParameters::none(), - }); - state = State::Mod; - } else { - return None; - } - } + /// Compares two TokenStreams, checking equality without regarding span information. + pub fn eq_unspanned(&self, other: &TokenStream) -> bool { + for (t1, t2) in self.iter().zip(other.iter()) { + if !t1.eq_unspanned(t2) { + return false; } } - - let path = ast::Path { - span: cov_span, - global: false, - segments: segments, - }; - Some((path, rst)) + true } - /// Returns an iterator over a TokenSlice (as a sequence of TokenStreams). - fn iter(&self) -> Iter { - Iter { vs: self } - } + /// Convert a vector of TokenTrees into a parentheses-delimited TokenStream. + pub fn as_delimited_stream(tts: Vec, delim: token::DelimToken) -> TokenStream { + let new_sp = covering_span(&tts); - /// Splits a TokenSlice based on the provided `&TokenTree -> bool` predicate. - fn split

(&self, pred: P) -> Split

- where P: FnMut(&TokenTree) -> bool - { - Split { - vs: self, - pred: pred, - finished: false, - } + let new_delim = Rc::new(Delimited { + delim: delim, + open_span: DUMMY_SP, + tts: tts, + close_span: DUMMY_SP, + }); + + TokenStream::from_tts(vec![TokenTree::Delimited(new_sp, new_delim)]) } } +// FIXME Reimplement this iterator to hold onto a slice iterator for a leaf, getting the +// next leaf's iterator when the current one is exhausted. pub struct Iter<'a> { - vs: &'a TokenSlice, + vs: &'a TokenStream, + idx: usize, } impl<'a> Iterator for Iter<'a> { type Item = &'a TokenTree; fn next(&mut self) -> Option<&'a TokenTree> { - if self.vs.is_empty() { + if self.vs.is_empty() || self.idx >= self.vs.len() { return None; } - let ret = Some(&self.vs[0]); - self.vs = &self.vs[1..]; + let ret = Some(&self.vs[self.idx]); + self.idx = self.idx + 1; ret } } @@ -791,29 +727,35 @@ impl<'a> Iterator for Iter<'a> { pub struct Split<'a, P> where P: FnMut(&TokenTree) -> bool { - vs: &'a TokenSlice, + vs: &'a TokenStream, pred: P, finished: bool, + idx: usize, } impl<'a, P> Iterator for Split<'a, P> where P: FnMut(&TokenTree) -> bool { - type Item = &'a TokenSlice; + type Item = TokenStream; - fn next(&mut self) -> Option<&'a TokenSlice> { + fn next(&mut self) -> Option { if self.finished { return None; } + if self.idx >= self.vs.len() { + self.finished = true; + return None; + } - match self.vs.iter().position(|x| (self.pred)(x)) { + let mut lookup = self.vs.iter().skip(self.idx); + match lookup.position(|x| (self.pred)(&x)) { None => { self.finished = true; - Some(&self.vs[..]) + Some(self.vs.slice_from(self.idx..)) } - Some(idx) => { - let ret = Some(&self.vs[..idx]); - self.vs = &self.vs[idx + 1..]; + Some(edx) => { + let ret = Some(self.vs.slice(self.idx..self.idx + edx)); + self.idx += edx + 1; ret } } @@ -824,79 +766,29 @@ impl Index for TokenStream { type Output = TokenTree; fn index(&self, index: usize) -> &TokenTree { - Index::index(&**self, index) + &self.ts[index] } } -impl ops::Index> for TokenStream { - type Output = TokenSlice; - - fn index(&self, index: ops::Range) -> &TokenSlice { - Index::index(&**self, index) - } -} - -impl ops::Index> for TokenStream { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeTo) -> &TokenSlice { - Index::index(&**self, index) - } -} - -impl ops::Index> for TokenStream { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeFrom) -> &TokenSlice { - Index::index(&**self, index) - } -} - -impl ops::Index for TokenStream { - type Output = TokenSlice; - - fn index(&self, _index: ops::RangeFull) -> &TokenSlice { - Index::index(&**self, _index) - } -} - -impl Index for TokenSlice { +impl Index for InternalTS { type Output = TokenTree; fn index(&self, index: usize) -> &TokenTree { - &self.0[index] - } -} - -impl ops::Index> for TokenSlice { - type Output = TokenSlice; - - fn index(&self, index: ops::Range) -> &TokenSlice { - TokenSlice::from_tts(&self.0[index]) - } -} - -impl ops::Index> for TokenSlice { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeTo) -> &TokenSlice { - TokenSlice::from_tts(&self.0[index]) - } -} - -impl ops::Index> for TokenSlice { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeFrom) -> &TokenSlice { - TokenSlice::from_tts(&self.0[index]) - } -} - -impl ops::Index for TokenSlice { - type Output = TokenSlice; - - fn index(&self, _index: ops::RangeFull) -> &TokenSlice { - TokenSlice::from_tts(&self.0[_index]) + if self.len() <= index { + panic!("Index {} too large for {:?}", index, self); + } + match *self { + InternalTS::Empty(..) => panic!("Invalid index"), + InternalTS::Leaf { ref tts, offset, .. } => tts.get(index + offset).unwrap(), + InternalTS::Node { ref left, ref right, .. } => { + let left_len = left.len(); + if index < left_len { + Index::index(&**left, index) + } else { + Index::index(&**right, index - left_len) + } + } + } } } @@ -904,9 +796,8 @@ impl ops::Index for TokenSlice { #[cfg(test)] mod tests { use super::*; - use ast; use syntax_pos::{Span, BytePos, NO_EXPANSION, DUMMY_SP}; - use parse::token::{self, str_to_ident, Token, Lit}; + use parse::token::{self, str_to_ident, Token}; use util::parser_testing::string_to_tts; use std::rc::Rc; @@ -918,6 +809,93 @@ mod tests { } } + fn as_paren_delimited_stream(tts: Vec) -> TokenStream { + TokenStream::as_delimited_stream(tts, token::DelimToken::Paren) + } + + #[test] + fn test_concat() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())); + let test_fst = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); + let test_snd = TokenStream::from_tts(string_to_tts("::baz".to_string())); + let eq_res = TokenStream::concat(test_fst, test_snd); + assert_eq!(test_res.len(), 5); + assert_eq!(eq_res.len(), 5); + assert_eq!(test_res.eq_unspanned(&eq_res), true); + } + + #[test] + fn test_from_to_bijection() { + let test_start = string_to_tts("foo::bar(baz)".to_string()); + let test_end = TokenStream::from_tts(string_to_tts("foo::bar(baz)".to_string())).to_tts(); + assert_eq!(test_start, test_end) + } + + #[test] + fn test_to_from_bijection() { + let test_start = TokenStream::from_tts(string_to_tts("foo::bar(baz)".to_string())); + let test_end = TokenStream::from_tts(test_start.clone().to_tts()); + assert_eq!(test_start, test_end) + } + + #[test] + fn test_eq_0() { + let test_res = TokenStream::from_tts(string_to_tts("foo".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("foo".to_string())); + assert_eq!(test_res, test_eqs) + } + + #[test] + fn test_eq_1() { + let test_res = TokenStream::from_tts(string_to_tts("::bar::baz".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("::bar::baz".to_string())); + assert_eq!(test_res, test_eqs) + } + + #[test] + fn test_eq_2() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())); + assert_eq!(test_res, test_eqs.slice(0..3)) + } + + #[test] + fn test_eq_3() { + let test_res = TokenStream::from_tts(string_to_tts("".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("".to_string())); + assert_eq!(test_res, test_eqs) + } + + #[test] + fn test_diseq_0() { + let test_res = TokenStream::from_tts(string_to_tts("::bar::baz".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("bar::baz".to_string())); + assert_eq!(test_res == test_eqs, false) + } + + #[test] + fn test_diseq_1() { + let test_res = TokenStream::from_tts(string_to_tts("(bar,baz)".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("bar,baz".to_string())); + assert_eq!(test_res == test_eqs, false) + } + + #[test] + fn test_slice_0() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())); + assert_eq!(test_res, test_eqs.slice(0..3)) + } + + #[test] + fn test_slice_1() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())) + .slice(2..3); + let test_eqs = TokenStream::from_tts(vec![TokenTree::Token(sp(5,8), + token::Ident(str_to_ident("bar")))]); + assert_eq!(test_res, test_eqs) + } + #[test] fn test_is_empty() { let test0 = TokenStream::from_tts(Vec::new()); @@ -947,38 +925,6 @@ mod tests { assert_eq!(test5.is_delimited(), false); } - #[test] - fn test_is_assign() { - let test0 = TokenStream::from_tts(string_to_tts("= bar::baz".to_string())); - let test1 = TokenStream::from_tts(string_to_tts("= \"5\"".to_string())); - let test2 = TokenStream::from_tts(string_to_tts("= 5".to_string())); - let test3 = TokenStream::from_tts(string_to_tts("(foo = 10)".to_string())); - let test4 = TokenStream::from_tts(string_to_tts("= (foo,bar,baz)".to_string())); - let test5 = TokenStream::from_tts(string_to_tts("".to_string())); - - assert_eq!(test0.is_assignment(), true); - assert_eq!(test1.is_assignment(), true); - assert_eq!(test2.is_assignment(), true); - assert_eq!(test3.is_assignment(), false); - assert_eq!(test4.is_assignment(), true); - assert_eq!(test5.is_assignment(), false); - } - - #[test] - fn test_is_lit() { - let test0 = TokenStream::from_tts(string_to_tts("\"foo\"".to_string())); - let test1 = TokenStream::from_tts(string_to_tts("5".to_string())); - let test2 = TokenStream::from_tts(string_to_tts("foo".to_string())); - let test3 = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); - let test4 = TokenStream::from_tts(string_to_tts("foo(bar)".to_string())); - - assert_eq!(test0.is_lit(), true); - assert_eq!(test1.is_lit(), true); - assert_eq!(test2.is_lit(), false); - assert_eq!(test3.is_lit(), false); - assert_eq!(test4.is_lit(), false); - } - #[test] fn test_is_ident() { let test0 = TokenStream::from_tts(string_to_tts("\"foo\"".to_string())); @@ -994,62 +940,6 @@ mod tests { assert_eq!(test4.is_ident(), false); } - #[test] - fn test_maybe_assignment() { - let test0_input = TokenStream::from_tts(string_to_tts("= bar::baz".to_string())); - let test1_input = TokenStream::from_tts(string_to_tts("= \"5\"".to_string())); - let test2_input = TokenStream::from_tts(string_to_tts("= 5".to_string())); - let test3_input = TokenStream::from_tts(string_to_tts("(foo = 10)".to_string())); - let test4_input = TokenStream::from_tts(string_to_tts("= (foo,bar,baz)".to_string())); - let test5_input = TokenStream::from_tts(string_to_tts("".to_string())); - - let test0 = test0_input.maybe_assignment(); - let test1 = test1_input.maybe_assignment(); - let test2 = test2_input.maybe_assignment(); - let test3 = test3_input.maybe_assignment(); - let test4 = test4_input.maybe_assignment(); - let test5 = test5_input.maybe_assignment(); - - let test0_expected = TokenStream::from_tts(vec![TokenTree::Token(sp(2, 5), - token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(5, 7), token::ModSep), - TokenTree::Token(sp(7, 10), - token::Ident(str_to_ident("baz")))]); - assert_eq!(test0, Some(&test0_expected[..])); - - let test1_expected = TokenStream::from_tts(vec![TokenTree::Token(sp(2, 5), - token::Literal(Lit::Str_(token::intern("5")), None))]); - assert_eq!(test1, Some(&test1_expected[..])); - - let test2_expected = TokenStream::from_tts(vec![TokenTree::Token( sp(2,3) - , token::Literal( - Lit::Integer( - token::intern(&(5.to_string()))), - None))]); - assert_eq!(test2, Some(&test2_expected[..])); - - assert_eq!(test3, None); - - - let test4_tts = vec![TokenTree::Token(sp(3, 6), token::Ident(str_to_ident("foo"))), - TokenTree::Token(sp(6, 7), token::Comma), - TokenTree::Token(sp(7, 10), token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(10, 11), token::Comma), - TokenTree::Token(sp(11, 14), token::Ident(str_to_ident("baz")))]; - - let test4_expected = TokenStream::from_tts(vec![TokenTree::Delimited(sp(2, 15), - Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: sp(2, 3), - tts: test4_tts, - close_span: sp(14, 15), - }))]); - assert_eq!(test4, Some(&test4_expected[..])); - - assert_eq!(test5, None); - - } - #[test] fn test_maybe_delimited() { let test0_input = TokenStream::from_tts(string_to_tts("foo(bar::baz)".to_string())); @@ -1074,7 +964,7 @@ mod tests { TokenTree::Token(sp(4, 6), token::ModSep), TokenTree::Token(sp(6, 9), token::Ident(str_to_ident("baz")))]); - assert_eq!(test1, Some(&test1_expected[..])); + assert_eq!(test1, Some(test1_expected)); let test2_expected = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), token::Ident(str_to_ident("foo"))), @@ -1084,7 +974,7 @@ mod tests { TokenTree::Token(sp(8, 9), token::Comma), TokenTree::Token(sp(9, 12), token::Ident(str_to_ident("baz")))]); - assert_eq!(test2, Some(&test2_expected[..])); + assert_eq!(test2, Some(test2_expected)); assert_eq!(test3, None); @@ -1093,72 +983,6 @@ mod tests { assert_eq!(test5, None); } - #[test] - fn test_maybe_comma_list() { - let test0_input = TokenStream::from_tts(string_to_tts("foo(bar::baz)".to_string())); - let test1_input = TokenStream::from_tts(string_to_tts("(bar::baz)".to_string())); - let test2_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)".to_string())); - let test3_input = TokenStream::from_tts(string_to_tts("(foo::bar,bar,baz)".to_string())); - let test4_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)(zab,rab)" - .to_string())); - let test5_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)foo".to_string())); - let test6_input = TokenStream::from_tts(string_to_tts("".to_string())); - // The following is supported behavior! - let test7_input = TokenStream::from_tts(string_to_tts("(foo,bar,)".to_string())); - - let test0 = test0_input.maybe_comma_list(); - let test1 = test1_input.maybe_comma_list(); - let test2 = test2_input.maybe_comma_list(); - let test3 = test3_input.maybe_comma_list(); - let test4 = test4_input.maybe_comma_list(); - let test5 = test5_input.maybe_comma_list(); - let test6 = test6_input.maybe_comma_list(); - let test7 = test7_input.maybe_comma_list(); - - assert_eq!(test0, None); - - let test1_stream = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), - token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(4, 6), token::ModSep), - TokenTree::Token(sp(6, 9), - token::Ident(str_to_ident("baz")))]); - - let test1_expected: Vec<&TokenSlice> = vec![&test1_stream[..]]; - assert_eq!(test1, Some(test1_expected)); - - let test2_foo = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), - token::Ident(str_to_ident("foo")))]); - let test2_bar = TokenStream::from_tts(vec![TokenTree::Token(sp(5, 8), - token::Ident(str_to_ident("bar")))]); - let test2_baz = TokenStream::from_tts(vec![TokenTree::Token(sp(9, 12), - token::Ident(str_to_ident("baz")))]); - let test2_expected: Vec<&TokenSlice> = vec![&test2_foo[..], &test2_bar[..], &test2_baz[..]]; - assert_eq!(test2, Some(test2_expected)); - - let test3_path = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), - token::Ident(str_to_ident("foo"))), - TokenTree::Token(sp(4, 6), token::ModSep), - TokenTree::Token(sp(6, 9), - token::Ident(str_to_ident("bar")))]); - let test3_bar = TokenStream::from_tts(vec![TokenTree::Token(sp(10, 13), - token::Ident(str_to_ident("bar")))]); - let test3_baz = TokenStream::from_tts(vec![TokenTree::Token(sp(14, 17), - token::Ident(str_to_ident("baz")))]); - let test3_expected: Vec<&TokenSlice> = - vec![&test3_path[..], &test3_bar[..], &test3_baz[..]]; - assert_eq!(test3, Some(test3_expected)); - - assert_eq!(test4, None); - - assert_eq!(test5, None); - - assert_eq!(test6, None); - - - let test7_expected: Vec<&TokenSlice> = vec![&test2_foo[..], &test2_bar[..]]; - assert_eq!(test7, Some(test7_expected)); - } - // pub fn maybe_ident(&self) -> Option #[test] fn test_maybe_ident() { @@ -1175,86 +999,10 @@ mod tests { assert_eq!(test4, None); } - // pub fn maybe_lit(&self) -> Option #[test] - fn test_maybe_lit() { - let test0 = TokenStream::from_tts(string_to_tts("\"foo\"".to_string())).maybe_lit(); - let test1 = TokenStream::from_tts(string_to_tts("5".to_string())).maybe_lit(); - let test2 = TokenStream::from_tts(string_to_tts("foo".to_string())).maybe_lit(); - let test3 = TokenStream::from_tts(string_to_tts("foo::bar".to_string())).maybe_lit(); - let test4 = TokenStream::from_tts(string_to_tts("foo(bar)".to_string())).maybe_lit(); - - assert_eq!(test0, Some(Lit::Str_(token::intern("foo")))); - assert_eq!(test1, Some(Lit::Integer(token::intern(&(5.to_string()))))); - assert_eq!(test2, None); - assert_eq!(test3, None); - assert_eq!(test4, None); - } - - #[test] - fn test_maybe_path_prefix() { - let test0_input = TokenStream::from_tts(string_to_tts("foo(bar::baz)".to_string())); - let test1_input = TokenStream::from_tts(string_to_tts("(bar::baz)".to_string())); - let test2_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)".to_string())); - let test3_input = TokenStream::from_tts(string_to_tts("foo::bar(bar,baz)".to_string())); - - let test0 = test0_input.maybe_path_prefix(); - let test1 = test1_input.maybe_path_prefix(); - let test2 = test2_input.maybe_path_prefix(); - let test3 = test3_input.maybe_path_prefix(); - - let test0_tts = vec![TokenTree::Token(sp(4, 7), token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(7, 9), token::ModSep), - TokenTree::Token(sp(9, 12), token::Ident(str_to_ident("baz")))]; - - let test0_stream = TokenStream::from_tts(vec![TokenTree::Delimited(sp(3, 13), - Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: sp(3, 4), - tts: test0_tts, - close_span: sp(12, 13), - }))]); - - let test0_expected = Some((ast::Path::from_ident(sp(0, 3), str_to_ident("foo")), - &test0_stream[..])); - assert_eq!(test0, test0_expected); - - assert_eq!(test1, None); - assert_eq!(test2, None); - - let test3_path = ast::Path { - span: sp(0, 8), - global: false, - segments: vec![ast::PathSegment { - identifier: str_to_ident("foo"), - parameters: ast::PathParameters::none(), - }, - ast::PathSegment { - identifier: str_to_ident("bar"), - parameters: ast::PathParameters::none(), - }], - }; - - let test3_tts = vec![TokenTree::Token(sp(9, 12), token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(12, 13), token::Comma), - TokenTree::Token(sp(13, 16), token::Ident(str_to_ident("baz")))]; - - let test3_stream = TokenStream::from_tts(vec![TokenTree::Delimited(sp(8, 17), - Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: sp(8, 9), - tts: test3_tts, - close_span: sp(16, 17), - }))]); - let test3_expected = Some((test3_path, &test3_stream[..])); - assert_eq!(test3, test3_expected); - } - - #[test] - fn test_as_paren_delimited_stream() { - let test0 = TokenStream::as_paren_delimited_stream(string_to_tts("foo,bar,".to_string())); - let test1 = TokenStream::as_paren_delimited_stream(string_to_tts("baz(foo,bar)" - .to_string())); + fn test_as_delimited_stream() { + let test0 = as_paren_delimited_stream(string_to_tts("foo,bar,".to_string())); + let test1 = as_paren_delimited_stream(string_to_tts("baz(foo,bar)".to_string())); let test0_tts = vec![TokenTree::Token(sp(0, 3), token::Ident(str_to_ident("foo"))), TokenTree::Token(sp(3, 4), token::Comma), @@ -1294,5 +1042,4 @@ mod tests { assert_eq!(test1, test1_stream); } - } From 6656a30ca161d3ea46add7e6538f74ed1e671e4e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 1 Aug 2016 18:42:16 +0000 Subject: [PATCH 263/331] Fix fallout in `ui/codemap_tests`. --- src/test/ui/codemap_tests/two_files.stderr | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index 6c388cd69395..cf3f187af933 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -2,12 +2,9 @@ error[E0404]: `Bar` is not a trait --> $DIR/two_files.rs:16:6 | 16 | impl Bar for Baz { } - | ^^^ `Bar` is not a trait - | - ::: $DIR/two_files_data.rs + | ^^^ | -15 | type Bar = Foo; - | --------------- type aliases cannot be used for traits + = note: type aliases cannot be used for traits error: cannot continue compilation due to previous error From 62cdbea8c92ab525a1d546ce010485d10a1fb7b9 Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Wed, 27 Jul 2016 17:46:54 -0700 Subject: [PATCH 264/331] deaggregate structs to enable further optimization --- src/librustc_driver/driver.rs | 2 + src/librustc_mir/transform/deaggregator.rs | 111 +++++++++++++++++++++ src/librustc_mir/transform/mod.rs | 1 + 3 files changed, 114 insertions(+) create mode 100644 src/librustc_mir/transform/deaggregator.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9a94cc16bfe8..657fc6c2c5b1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -994,6 +994,8 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + passes.push_pass(box mir::transform::deaggregator::Deaggregator); + passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs new file mode 100644 index 000000000000..b1c8a0994038 --- /dev/null +++ b/src/librustc_mir/transform/deaggregator.rs @@ -0,0 +1,111 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use rustc::mir::repr::*; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc_data_structures::indexed_vec::Idx; +use rustc::ty::VariantKind; + +pub struct Deaggregator; + +impl Pass for Deaggregator {} + +impl<'tcx> MirPass<'tcx> for Deaggregator { + fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, mir: &mut Mir<'tcx>) { + let node_id = source.item_id(); + let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id)); + debug!("running on: {:?}", node_path); + // we only run when mir_opt_level > 1 + match tcx.sess.opts.debugging_opts.mir_opt_level { + Some(0) | + Some(1) | + None => { return; }, + _ => {} + }; + if let MirSource::Fn(_) = source {} else { return; } + + let mut curr: usize = 0; + for bb in mir.basic_blocks_mut() { + while let Some(idx) = get_aggregate_statement(curr, &bb.statements) { + // do the replacement + debug!("removing statement {:?}", idx); + let src_info = bb.statements[idx].source_info; + let mut suffix_stmts = bb.statements.split_off(idx); + let orig_stmt = suffix_stmts.remove(0); + let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind; + if let &Rvalue::Aggregate(ref agg_kind, ref operands) = rhs { + if let &AggregateKind::Adt(adt_def, variant, substs) = agg_kind { + let n = bb.statements.len(); + bb.statements.reserve(n + operands.len() + suffix_stmts.len()); + for (i, op) in operands.iter().enumerate() { + let ref variant_def = adt_def.variants[variant]; + let ty = variant_def.fields[variant].ty(tcx, substs); + let rhs = Rvalue::Use(op.clone()); + + // since we don't handle enums, we don't need a cast + let lhs_cast = lhs.clone(); + + // if we handled enums: + // let lhs_cast = if adt_def.variants.len() > 1 { + // Lvalue::Projection(Box::new(LvalueProjection { + // base: ai.lhs.clone(), + // elem: ProjectionElem::Downcast(ai.adt_def, ai.variant), + // })) + // } else { + // lhs_cast + // }; + + let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { + base: lhs_cast, + elem: ProjectionElem::Field(Field::new(i), ty), + })); + let new_statement = Statement { + source_info: src_info, + kind: StatementKind::Assign(lhs_proj, rhs), + }; + debug!("inserting: {:?} @ {:?}", new_statement, idx + i); + bb.statements.push(new_statement); + } + curr = bb.statements.len(); + bb.statements.extend(suffix_stmts); + } + } + } + } + } +} + +fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize, + statements: &Vec>) + -> Option { + for i in curr..statements.len() { + let ref statement = statements[i]; + let StatementKind::Assign(_, ref rhs) = statement.kind; + if let &Rvalue::Aggregate(ref kind, ref operands) = rhs { + if let &AggregateKind::Adt(adt_def, variant, _) = kind { + if operands.len() > 0 { // don't deaggregate () + if adt_def.variants.len() > 1 { + // only deaggrate structs for now + continue; + } + debug!("getting variant {:?}", variant); + debug!("for adt_def {:?}", adt_def); + let variant_def = &adt_def.variants[variant]; + if variant_def.kind == VariantKind::Struct { + return Some(i); + } + } + } + } + }; + None +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 7b707b4adb69..c3485b8256da 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -17,3 +17,4 @@ pub mod add_call_guards; pub mod promote_consts; pub mod qualify_consts; pub mod dump_mir; +pub mod deaggregator; From 57e3b9eb713f44a9dce97be5840c536bd7a86069 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 1 Aug 2016 20:16:56 -0400 Subject: [PATCH 265/331] Indicate where the `std::net::Incoming` struct is created. --- src/libstd/net/tcp.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 5ab0d5a0877b..76617f159707 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -77,6 +77,11 @@ pub struct TcpListener(net_imp::TcpListener); /// /// This iterator will infinitely yield `Some` of the accepted connections. It /// is equivalent to calling `accept` in a loop. +/// +/// This `struct` is created by the [`incoming`] method on [`TcpListener`]. +/// +/// [`incoming`]: struct.TcpListener.html#method.incoming +/// [`TcpListener`]: struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Incoming<'a> { listener: &'a TcpListener } From f2d8db15dfe9b715f0e0a957440d79945270a20f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 1 Aug 2016 20:21:08 -0400 Subject: [PATCH 266/331] Link to relevant method/struct for `std::net::Shutdown` docs. --- src/libstd/net/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index ac13b23ebee5..11a16b271133 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -35,7 +35,11 @@ mod udp; mod parser; #[cfg(test)] mod test; -/// Possible values which can be passed to the `shutdown` method of `TcpStream`. +/// Possible values which can be passed to the [`shutdown`] method of +/// [`TcpStream`]. +/// +/// [`shutdown`]: struct.TcpStream.html#method.shutdown +/// [`TcpStream`]: struct.TcpStream.html #[derive(Copy, Clone, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Shutdown { From a9e291c3c681ebba49ab3516f9304a5b74626a3e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 4 Jun 2016 19:55:20 +0300 Subject: [PATCH 267/331] Turn -Z orbit on by default. --- src/librustc/session/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index cdde6d6f63dd..b92fd440a22c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -756,7 +756,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "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, + orbit: bool = (true, parse_bool, "get MIR where it belongs - everywhere; most importantly, in orbit"), } From 90ba77a7a9807a3a463f2820a4e652052e32efa0 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 8 Jun 2016 15:18:51 +0300 Subject: [PATCH 268/331] Make --enable-orbit the default in ./configure. --- configure | 4 ++-- mk/main.mk | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configure b/configure index d4bd16167d35..29f16da05812 100755 --- a/configure +++ b/configure @@ -609,7 +609,7 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt rustbuild 0 "use the rust and cargo based build system" -opt orbit 0 "get MIR where it belongs - everywhere; most importantly, in orbit" +opt orbit 1 "get MIR where it belongs - everywhere; most importantly, in orbit" opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" @@ -733,7 +733,7 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi -if [ -n "$CFG_ENABLE_ORBIT" ]; then putvar CFG_ENABLE_ORBIT; fi +if [ -n "$CFG_DISABLE_ORBIT" ]; then putvar CFG_DISABLE_ORBIT; fi step_msg "looking for build programs" diff --git a/mk/main.mk b/mk/main.mk index fd12bf26dfc7..9a3a59ded35a 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -162,9 +162,9 @@ ifdef CFG_ENABLE_DEBUGINFO CFG_RUSTC_FLAGS += -g endif -ifdef CFG_ENABLE_ORBIT - $(info cfg: launching MIR (CFG_ENABLE_ORBIT)) - CFG_RUSTC_FLAGS += -Z orbit +ifdef CFG_DISABLE_ORBIT + $(info cfg: HOLD HOLD HOLD (CFG_DISABLE_ORBIT)) + CFG_RUSTC_FLAGS += -Z orbit=off endif ifdef SAVE_TEMPS From 5d00b8aa065b2da826613d9beda75657cec3f87d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 2 Aug 2016 03:28:50 +0300 Subject: [PATCH 269/331] rustc_trans: load C-like enums larger than usize from memory with -Zorbit. --- src/librustc_trans/mir/rvalue.rs | 58 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 6ebc23884918..97d65ce9c536 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -244,18 +244,46 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } } - mir::CastKind::Misc if common::type_is_immediate(bcx.ccx(), operand.ty) => { + mir::CastKind::Misc if common::type_is_fat_ptr(bcx.tcx(), operand.ty) => { + let ll_cast_ty = type_of::immediate_type_of(bcx.ccx(), cast_ty); + let ll_from_ty = type_of::immediate_type_of(bcx.ccx(), operand.ty); + if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val { + if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { + let ll_cft = ll_cast_ty.field_types(); + let ll_fft = ll_from_ty.field_types(); + let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); + assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); + OperandValue::Pair(data_cast, meta_ptr) + } else { // cast to thin-ptr + // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and + // pointer-cast of that pointer to desired pointer type. + let llval = bcx.pointercast(data_ptr, ll_cast_ty); + OperandValue::Immediate(llval) + } + } else { + bug!("Unexpected non-Pair operand") + } + } + mir::CastKind::Misc => { debug_assert!(common::type_is_immediate(bcx.ccx(), cast_ty)); let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast"); let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); let ll_t_in = type_of::immediate_type_of(bcx.ccx(), operand.ty); let ll_t_out = type_of::immediate_type_of(bcx.ccx(), cast_ty); - let llval = operand.immediate(); - let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in { + let (llval, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in { let repr = adt::represent_type(bcx.ccx(), operand.ty); - adt::is_discr_signed(&repr) + let discr = match operand.val { + OperandValue::Immediate(llval) => llval, + OperandValue::Ref(llptr) => { + bcx.with_block(|bcx| { + adt::trans_get_discr(bcx, &repr, llptr, None, true) + }) + } + OperandValue::Pair(..) => bug!("Unexpected Pair operand") + }; + (discr, adt::is_discr_signed(&repr)) } else { - operand.ty.is_signed() + (operand.immediate(), operand.ty.is_signed()) }; let newval = match (r_t_in, r_t_out) { @@ -304,26 +332,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }; OperandValue::Immediate(newval) } - mir::CastKind::Misc => { // Casts from a fat-ptr. - let ll_cast_ty = type_of::immediate_type_of(bcx.ccx(), cast_ty); - let ll_from_ty = type_of::immediate_type_of(bcx.ccx(), operand.ty); - if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val { - if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { - let ll_cft = ll_cast_ty.field_types(); - let ll_fft = ll_from_ty.field_types(); - let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); - assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); - OperandValue::Pair(data_cast, meta_ptr) - } else { // cast to thin-ptr - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and - // pointer-cast of that pointer to desired pointer type. - let llval = bcx.pointercast(data_ptr, ll_cast_ty); - OperandValue::Immediate(llval) - } - } else { - bug!("Unexpected non-Pair operand") - } - } }; let operand = OperandRef { val: val, From b197a375c000a8d66dbeb1b511bd39fe8186f50b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 2 Aug 2016 03:45:01 +0300 Subject: [PATCH 270/331] tests: don't use -Zorbit on run-pass/issue-28950, it stack overflows. --- src/test/run-pass/issue-28950.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/run-pass/issue-28950.rs b/src/test/run-pass/issue-28950.rs index f01ce46a891d..efce148ea51d 100644 --- a/src/test/run-pass/issue-28950.rs +++ b/src/test/run-pass/issue-28950.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z orbit=off +// (blows the stack with MIR trans and no optimizations) + // Tests that the `vec!` macro does not overflow the stack when it is // given data larger than the stack. From 98a516274a7f512b051c5725fdfee641281ebe0d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 2 Aug 2016 05:18:23 +0300 Subject: [PATCH 271/331] rustc: parse -Z orbit=off. --- src/librustc/session/config.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index b92fd440a22c..1d839be9f537 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -463,6 +463,8 @@ macro_rules! options { pub const parse_bool: Option<&'static str> = None; pub const parse_opt_bool: Option<&'static str> = Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); + pub const parse_all_bool: Option<&'static str> = + Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); pub const parse_string: Option<&'static str> = Some("a string"); pub const parse_opt_string: Option<&'static str> = Some("a string"); pub const parse_list: Option<&'static str> = Some("a space-separated list of strings"); @@ -512,6 +514,25 @@ macro_rules! options { } } + fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool { + match v { + Some(s) => { + match s { + "n" | "no" | "off" => { + *slot = false; + } + "y" | "yes" | "on" => { + *slot = true; + } + _ => { return false; } + } + + true + }, + None => { *slot = true; true } + } + } + fn parse_opt_string(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = Some(s.to_string()); true }, @@ -756,7 +777,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "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 = (true, parse_bool, + orbit: bool = (true, parse_all_bool, "get MIR where it belongs - everywhere; most importantly, in orbit"), } From dbc3391a23df8ec0ebb130ee9f06511abddac24f Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 2 Aug 2016 08:14:58 +0300 Subject: [PATCH 272/331] tests: mark the inline asm in run-pass/issue-14936 as volatile. --- src/test/run-pass/issue-14936.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 5f8e7cb8145e..428d4e4dbb12 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -28,7 +28,8 @@ macro_rules! demo { unsafe { asm!("mov ($1), $0" : $output_constraint (*wrap(&mut x, "out", &mut history)) - : "r"(&wrap(y, "in", &mut history))); + : "r"(&wrap(y, "in", &mut history)) + :: "volatile"); } assert_eq!((x,y), (1,1)); let b: &[_] = &["out", "in"]; From b583711ff965db3b113ad6f468f32ad6ec1330a3 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 2 Aug 2016 09:02:19 +0300 Subject: [PATCH 273/331] Ignore the lang-items example in the book. --- src/doc/book/lang-items.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index b948567ac5b7..72a3c08225d0 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -15,7 +15,7 @@ For example, `Box` pointers require two lang items, one for allocation and one for deallocation. A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: -```rust +```rust,ignore #![feature(lang_items, box_syntax, start, libc)] #![no_std] From 884b969f2ac14f95b00a287eeb98c474cc330732 Mon Sep 17 00:00:00 2001 From: m4b Date: Mon, 1 Aug 2016 23:42:15 -0700 Subject: [PATCH 274/331] Add -mrelax-relocations=no hacks to fix musl build --- mk/cfg/x86_64-unknown-linux-musl.mk | 4 ++-- src/bootstrap/lib.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mk/cfg/x86_64-unknown-linux-musl.mk b/mk/cfg/x86_64-unknown-linux-musl.mk index 3a03b2accd54..6f707ac3b3fb 100644 --- a/mk/cfg/x86_64-unknown-linux-musl.mk +++ b/mk/cfg/x86_64-unknown-linux-musl.mk @@ -7,8 +7,8 @@ CFG_INSTALL_ONLY_RLIB_x86_64-unknown-linux-musl = 1 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 := -g -fPIC -m64 +CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64 -Wa,-mrelax-relocations=no +CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -g -fPIC -m64 -Wa,-mrelax-relocations=no 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/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 25356b86221c..ac444e5fcc29 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -855,6 +855,12 @@ impl Build { base.push("-stdlib=libc++".into()); base.push("-mmacosx-version-min=10.7".into()); } + // This is a hack, because newer binutils broke things + // on some vms/distros (i.e., linking against unknown relocs disabled by the following flag) + // See: https://github.com/rust-lang/rust/issues/34978 + if target == "x86_64-unknown-linux-musl" { + base.push("-Wa,-mrelax-relocations=no".into()); + } return base } From 3081dd863718f941e283ec954f36a23bbe58ffeb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 2 Aug 2016 08:49:05 -0400 Subject: [PATCH 275/331] Add doc example for `std::ffi::NulError::nul_position`. --- src/libstd/ffi/c_str.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 0d3e18f9b966..f800a6e228e9 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -356,6 +356,18 @@ impl Borrow for CString { impl NulError { /// Returns the position of the nul byte in the slice that was provided to /// `CString::new`. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let nul_error = CString::new("foo\0bar").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 3); + /// + /// let nul_error = CString::new("foo bar\0").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 7); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn nul_position(&self) -> usize { self.0 } From 727d9293e47b349c500d34f887e43051d865de4d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 25 Jul 2016 23:25:12 -0400 Subject: [PATCH 276/331] Add doc examples for `range::RangeArgument::{start,end}`. --- src/libcollections/range.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 4e39191b472e..1badc72aed07 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -23,6 +23,22 @@ pub trait RangeArgument { /// Start index (inclusive) /// /// Return start value if present, else `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections)] + /// #![feature(collections_range)] + /// + /// extern crate collections; + /// + /// # fn main() { + /// use collections::range::RangeArgument; + /// + /// assert_eq!((..10).start(), None); + /// assert_eq!((3..10).start(), Some(&3)); + /// # } + /// ``` fn start(&self) -> Option<&T> { None } @@ -30,6 +46,22 @@ pub trait RangeArgument { /// End index (exclusive) /// /// Return end value if present, else `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections)] + /// #![feature(collections_range)] + /// + /// extern crate collections; + /// + /// # fn main() { + /// use collections::range::RangeArgument; + /// + /// assert_eq!((3..).end(), None); + /// assert_eq!((3..10).end(), Some(&10)); + /// # } + /// ``` fn end(&self) -> Option<&T> { None } From 5383cd7163a4334095d6d956508bd0f8911ac6c7 Mon Sep 17 00:00:00 2001 From: m4b Date: Tue, 2 Aug 2016 09:54:05 -0700 Subject: [PATCH 277/331] Fix style issues --- src/bootstrap/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index ac444e5fcc29..acb7e0fadd90 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -855,8 +855,8 @@ impl Build { base.push("-stdlib=libc++".into()); base.push("-mmacosx-version-min=10.7".into()); } - // This is a hack, because newer binutils broke things - // on some vms/distros (i.e., linking against unknown relocs disabled by the following flag) + // This is a hack, because newer binutils broke things on some vms/distros + // (i.e., linking against unknown relocs disabled by the following flag) // See: https://github.com/rust-lang/rust/issues/34978 if target == "x86_64-unknown-linux-musl" { base.push("-Wa,-mrelax-relocations=no".into()); From bda46c21fe30377b9587b584c64ffe99da6c14ce Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Tue, 2 Aug 2016 10:46:26 -0700 Subject: [PATCH 278/331] reduce rightward drift, add fixme --- src/librustc_mir/transform/deaggregator.rs | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index b1c8a0994038..3d8e013c5a7d 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -31,55 +31,55 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { None => { return; }, _ => {} }; + + // Do not trigger on constants. Could be revised in future if let MirSource::Fn(_) = source {} else { return; } let mut curr: usize = 0; for bb in mir.basic_blocks_mut() { - while let Some(idx) = get_aggregate_statement(curr, &bb.statements) { - // do the replacement - debug!("removing statement {:?}", idx); - let src_info = bb.statements[idx].source_info; - let mut suffix_stmts = bb.statements.split_off(idx); - let orig_stmt = suffix_stmts.remove(0); - let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind; - if let &Rvalue::Aggregate(ref agg_kind, ref operands) = rhs { - if let &AggregateKind::Adt(adt_def, variant, substs) = agg_kind { - let n = bb.statements.len(); - bb.statements.reserve(n + operands.len() + suffix_stmts.len()); - for (i, op) in operands.iter().enumerate() { - let ref variant_def = adt_def.variants[variant]; - let ty = variant_def.fields[variant].ty(tcx, substs); - let rhs = Rvalue::Use(op.clone()); + let idx = match get_aggregate_statement(curr, &bb.statements) { + Some(idx) => idx, + None => continue, + }; + // do the replacement + debug!("removing statement {:?}", idx); + let src_info = bb.statements[idx].source_info; + let suffix_stmts = bb.statements.split_off(idx+1); + let orig_stmt = bb.statements.pop().unwrap(); + let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind; + let (agg_kind, operands) = match rhs { + &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands), + _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs), + }; + let (adt_def, variant, substs) = match agg_kind { + &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs), + _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs), + }; + let n = bb.statements.len(); + bb.statements.reserve(n + operands.len() + suffix_stmts.len()); + for (i, op) in operands.iter().enumerate() { + let ref variant_def = adt_def.variants[variant]; + let ty = variant_def.fields[variant].ty(tcx, substs); + let rhs = Rvalue::Use(op.clone()); - // since we don't handle enums, we don't need a cast - let lhs_cast = lhs.clone(); + // since we don't handle enums, we don't need a cast + let lhs_cast = lhs.clone(); - // if we handled enums: - // let lhs_cast = if adt_def.variants.len() > 1 { - // Lvalue::Projection(Box::new(LvalueProjection { - // base: ai.lhs.clone(), - // elem: ProjectionElem::Downcast(ai.adt_def, ai.variant), - // })) - // } else { - // lhs_cast - // }; + // FIXME we cannot deaggregate enums issue: 35186 - let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { - base: lhs_cast, - elem: ProjectionElem::Field(Field::new(i), ty), - })); - let new_statement = Statement { - source_info: src_info, - kind: StatementKind::Assign(lhs_proj, rhs), - }; - debug!("inserting: {:?} @ {:?}", new_statement, idx + i); - bb.statements.push(new_statement); - } - curr = bb.statements.len(); - bb.statements.extend(suffix_stmts); - } - } + let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { + base: lhs_cast, + elem: ProjectionElem::Field(Field::new(i), ty), + })); + let new_statement = Statement { + source_info: src_info, + kind: StatementKind::Assign(lhs_proj, rhs), + }; + debug!("inserting: {:?} @ {:?}", new_statement, idx + i); + bb.statements.push(new_statement); } + curr = bb.statements.len(); + bb.statements.extend(suffix_stmts); } } } From e8bfba7dc8a484a3241055eeeaf7ecb733b54fa6 Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Tue, 2 Aug 2016 11:24:55 -0700 Subject: [PATCH 279/331] fix field type, add test --- src/librustc_mir/transform/deaggregator.rs | 2 +- src/test/mir-opt/deaggregator_test.rs | 41 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/test/mir-opt/deaggregator_test.rs diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 3d8e013c5a7d..05bdefab40b3 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -59,7 +59,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { bb.statements.reserve(n + operands.len() + suffix_stmts.len()); for (i, op) in operands.iter().enumerate() { let ref variant_def = adt_def.variants[variant]; - let ty = variant_def.fields[variant].ty(tcx, substs); + let ty = variant_def.fields[i].ty(tcx, substs); let rhs = Rvalue::Use(op.clone()); // since we don't handle enums, we don't need a cast diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs new file mode 100644 index 000000000000..e57a9674cf68 --- /dev/null +++ b/src/test/mir-opt/deaggregator_test.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Baz { + x: usize, + y: f32, + z: bool, +} + +fn bar(a: usize) -> Baz { + Baz { x: a, y: 0.0, z: false } +} + +fn main() {} + +// END RUST SOURCE +// START rustc.node13.Deaggregator.before.mir +// bb0: { +// var0 = arg0; // scope 0 at main.rs:8:8: 8:9 +// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15 +// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ... +// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// } +// END rustc.node13.Deaggregator.before.mir +// START rustc.node13.Deaggregator.after.mir +// bb0: { +// var0 = arg0; // scope 0 at main.rs:8:8: 8:9 +// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15 +// (return.0: usize) = tmp0; // scope 1 at main.rs:9:5: 9:34 +// (return.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34 +// (return.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34 +// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// } +// END rustc.node13.Deaggregator.after.mir \ No newline at end of file From 1fa9b8dc96f95ec5d6c95746d58e96f507ab85fd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Aug 2016 03:28:13 +0200 Subject: [PATCH 280/331] Add doc example for Vec --- src/libcollections/vec.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 275f38b2f787..8b4fce158de4 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -476,6 +476,25 @@ impl Vec { /// Note that this will drop any excess capacity. Calling this and /// converting back to a vector with `into_vec()` is equivalent to calling /// `shrink_to_fit()`. + /// + /// # Examples + /// + /// ``` + /// let v = vec![1, 2, 3]; + /// + /// let slice = v.into_boxed_slice(); + /// ``` + /// + /// Any excess capacity is removed: + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3].iter().cloned()); + /// + /// assert_eq!(vec.capacity(), 10); + /// let slice = vec.into_boxed_slice(); + /// assert_eq!(slice.into_vec().capacity(), 3); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_boxed_slice(mut self) -> Box<[T]> { unsafe { From d918c990de1e6d0f2a8b3b4a0535de1981029679 Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Tue, 2 Aug 2016 12:30:57 -0700 Subject: [PATCH 281/331] add hashtag to emphasis its a gh issue --- src/librustc_mir/transform/deaggregator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 05bdefab40b3..ae91123c6926 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -65,7 +65,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { // since we don't handle enums, we don't need a cast let lhs_cast = lhs.clone(); - // FIXME we cannot deaggregate enums issue: 35186 + // FIXME we cannot deaggregate enums issue: #35186 let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { base: lhs_cast, From 5f8010443153036c887c917e1580e6af2d296361 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 2 Aug 2016 01:40:18 -0500 Subject: [PATCH 282/331] core: fix `cargo build` for targets with "max-atomic-width": 0 This crate was failing to compile due to dead_code/unused_imports warnings. This commits disables these two lints for these targets. --- src/libcore/sync/atomic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 47d9deb62ff6..2a7a0b623293 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -74,6 +74,8 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] +#![cfg_attr(not(target_has_atomic = "8"), allow(dead_code))] +#![cfg_attr(not(target_has_atomic = "8"), allow(unused_imports))] use self::Ordering::*; From 2fd8044ceff8a42b09254ac7d5288e497d9b3778 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Aug 2016 13:06:43 -0700 Subject: [PATCH 283/331] mk: Only pass -Zorbit=off in stage1/2 The stage0 compiler doesn't understand this option. --- mk/main.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index 9a3a59ded35a..c6c3e70abc37 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -164,7 +164,8 @@ endif ifdef CFG_DISABLE_ORBIT $(info cfg: HOLD HOLD HOLD (CFG_DISABLE_ORBIT)) - CFG_RUSTC_FLAGS += -Z orbit=off + RUSTFLAGS_STAGE1 += -Z orbit=off + RUSTFLAGS_STAGE2 += -Z orbit=off endif ifdef SAVE_TEMPS From 44dbc4907d9249349582518109792fd1beb34593 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 1 Aug 2016 05:56:51 -0400 Subject: [PATCH 284/331] Automatically enable -Zorbit if -Zincremental is specified. --- src/librustc/session/config.rs | 10 +++++++++- .../enable-orbit-for-incr-comp.rs | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/enable-orbit-for-incr-comp.rs diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 34df476e5c82..8f25c597b2dc 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1143,7 +1143,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }) }); - let debugging_opts = build_debugging_options(matches, error_format); + let mut debugging_opts = build_debugging_options(matches, error_format); + + // Incremental compilation only works reliably when translation is done via + // MIR, so let's enable -Z orbit if necessary (see #34973). + if debugging_opts.incremental.is_some() && !debugging_opts.orbit { + early_warn(error_format, "Automatically enabling `-Z orbit` because \ + `-Z incremental` was specified"); + debugging_opts.orbit = true; + } let parse_only = debugging_opts.parse_only; let no_trans = debugging_opts.no_trans; diff --git a/src/test/compile-fail/enable-orbit-for-incr-comp.rs b/src/test/compile-fail/enable-orbit-for-incr-comp.rs new file mode 100644 index 000000000000..eec6bad731e3 --- /dev/null +++ b/src/test/compile-fail/enable-orbit-for-incr-comp.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. + +// ignore-pretty +// compile-flags:-Zincremental=tmp/cfail-tests/enable-orbit-for-incr-comp -Zorbit=off +// error-pattern:Automatically enabling `-Z orbit` because `-Z incremental` was specified + +#![deny(warnings)] + +fn main() { + FAIL! // We just need some compilation error. What we really care about is + // that the error pattern above is checked. +} From d90c16625f932a4e08a56c1f2f131d8c5ce1214c Mon Sep 17 00:00:00 2001 From: mLuby Date: Tue, 2 Aug 2016 14:08:19 -0700 Subject: [PATCH 285/331] Update the-stack-and-the-heap.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was surprised to learn that heaps were used in this way, then realized upon reading [the linked paper](http://www.cs.cmu.edu/afs/cs/academic/class/15213-f98/doc/dsa.pdf) that it's a totally different type of heap—an important distinction. --- src/doc/book/the-stack-and-the-heap.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/book/the-stack-and-the-heap.md b/src/doc/book/the-stack-and-the-heap.md index a1f6a065a252..aee45299cf22 100644 --- a/src/doc/book/the-stack-and-the-heap.md +++ b/src/doc/book/the-stack-and-the-heap.md @@ -26,6 +26,8 @@ The stack is very fast, and is where memory is allocated in Rust by default. But the allocation is local to a function call, and is limited in size. The heap, on the other hand, is slower, and is explicitly allocated by your program. But it’s effectively unlimited in size, and is globally accessible. +Note this meaning of heap, which allocates arbitrary-sized blocks of memory in arbitrary +order, is quite different from the heap data structure. # The Stack From e5cc04665924c73c94e1de071135247102d76865 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Jul 2016 00:15:15 +0300 Subject: [PATCH 286/331] Move the E0130 check to AST validation pass --- src/librustc_passes/ast_validation.rs | 17 ++++++++++++++ src/librustc_passes/diagnostics.rs | 33 +++++++++++++++++++++++++++ src/librustc_typeck/collect.rs | 17 +++----------- src/librustc_typeck/diagnostics.rs | 33 --------------------------- 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index a90b563515ea..300750a625d5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -135,6 +135,23 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_item(self, item) } + fn visit_foreign_item(&mut self, fi: &ForeignItem) { + match fi.node { + ForeignItemKind::Fn(ref decl, _) => { + for arg in &decl.inputs { + match arg.pat.node { + PatKind::Ident(..) | PatKind::Wild => {} + _ => span_err!(self.session, arg.pat.span, E0130, + "patterns aren't allowed in foreign function declarations") + } + } + } + ForeignItemKind::Static(..) => {} + } + + visit::walk_foreign_item(self, fi) + } + fn visit_variant_data(&mut self, vdata: &VariantData, _: Ident, _: &Generics, _: NodeId, span: Span) { if vdata.fields().is_empty() { diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index a616b95ef720..d6865ba13fc2 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -49,6 +49,39 @@ match 5u32 { ``` "##, +E0130: r##" +You declared a pattern as an argument in a foreign function declaration. +Erroneous code example: + +```compile_fail +extern { + fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign + // function declarations +} +``` + +Please replace the pattern argument with a regular one. Example: + +``` +struct SomeStruct { + a: u32, + b: u32, +} + +extern { + fn foo(s: SomeStruct); // ok! +} +``` + +Or: + +``` +extern { + fn foo(a: (u32, u32)); // ok! +} +``` +"##, + E0161: r##" A value was moved. However, its size was not known at compile time, and only values of a known size can be moved. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ec95afe15bd5..4486748a1f05 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -60,8 +60,6 @@ There are some shortcomings in this design: use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds}; use lint; -use hir::def::Def; -use hir::def_id::DefId; use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; @@ -74,7 +72,6 @@ use rustc::ty::{VariantKind}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; -use rustc::hir::map as hir_map; use util::common::{ErrorReported, MemoizationMap}; use util::nodemap::{NodeMap, FnvHashMap}; use {CrateCtxt, write_ty_to_tcx}; @@ -91,9 +88,9 @@ use syntax::parse::token::keywords; use syntax::ptr::P; use syntax_pos::Span; -use rustc::hir::{self, PatKind}; -use rustc::hir::intravisit; -use rustc::hir::print as pprust; +use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; +use rustc::hir::def::Def; +use rustc::hir::def_id::DefId; /////////////////////////////////////////////////////////////////////////// // Main entry point @@ -2144,14 +2141,6 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( abi: abi::Abi) -> ty::TypeScheme<'tcx> { - for i in &decl.inputs { - match i.pat.node { - PatKind::Binding(..) | PatKind::Wild => {} - _ => span_err!(ccx.tcx.sess, i.pat.span, E0130, - "patterns aren't allowed in foreign function declarations") - } - } - let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty()); let rb = BindingRscope::new(); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index cd2259a28346..b655d955429f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1800,39 +1800,6 @@ Please also verify that this wasn't because of a name-clash and rename the type parameter if so. "##, -E0130: r##" -You declared a pattern as an argument in a foreign function declaration. -Erroneous code example: - -```compile_fail -extern { - fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign - // function declarations -} -``` - -Please replace the pattern argument with a regular one. Example: - -``` -struct SomeStruct { - a: u32, - b: u32, -} - -extern { - fn foo(s: SomeStruct); // ok! -} -``` - -Or: - -``` -extern { - fn foo(a: (u32, u32)); // ok! -} -``` -"##, - E0131: r##" It is not possible to define `main` with type parameters, or even with function parameters. When `main` is present, it must take no arguments and return `()`. From d5908a32509ccbbc552179cd75d22c8ea20d4092 Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Tue, 2 Aug 2016 14:47:53 -0700 Subject: [PATCH 287/331] run mir opt test with mir-opt-level=3 so they fire --- src/tools/compiletest/src/runtest.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f2acfa517ced..6647a1a0a933 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1340,6 +1340,8 @@ actual:\n\ MirOpt => { args.extend(["-Z", "dump-mir=all", + "-Z", + "mir-opt-level=3", "-Z"] .iter() .map(|s| s.to_string())); From ee977e715f7714b728d2d1603b2f6e1b3f1a1e5f Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 3 Aug 2016 01:25:34 +0300 Subject: [PATCH 288/331] rustc_trans: don't lose the cross-crate DefId, MIR trans needs it. --- src/librustc_trans/base.rs | 6 +++--- src/librustc_trans/debuginfo/mod.rs | 2 ++ src/test/run-pass/mir_cross_crate.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/mir_cross_crate.rs diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5a19ddff7462..6d9ae4deb718 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1918,9 +1918,9 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let instance = inline::maybe_inline_instance(ccx, instance); + let local_instance = inline::maybe_inline_instance(ccx, instance); - let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); + let fn_node_id = ccx.tcx().map.as_local_node_id(local_instance.def).unwrap(); let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(fn_node_id)); debug!("trans_instance(instance={:?})", instance); @@ -1936,7 +1936,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let sig = ccx.tcx().normalize_associated_type(&sig); let abi = fn_ty.fn_abi(); - let lldecl = match ccx.instances().borrow().get(&instance) { + let lldecl = match ccx.instances().borrow().get(&local_instance) { Some(&val) => val, None => bug!("Instance `{:?}` not already declared", instance) }; diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 0cb52c8768b0..918935988a92 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -32,6 +32,7 @@ use rustc::hir; use abi::Abi; use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder}; +use inline; use monomorphize::{self, Instance}; use rustc::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; @@ -238,6 +239,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Do this here already, in case we do an early exit from this function. source_loc::set_debug_location(cx, None, UnknownLocation); + let instance = inline::maybe_inline_instance(cx, instance); let (containing_scope, span) = get_containing_scope_and_span(cx, instance); // This can be the case for functions inlined from another crate diff --git a/src/test/run-pass/mir_cross_crate.rs b/src/test/run-pass/mir_cross_crate.rs new file mode 100644 index 000000000000..cc239d9f68b1 --- /dev/null +++ b/src/test/run-pass/mir_cross_crate.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z orbit +// Tests that -Z orbit affects functions from other crates. + +#![feature(unsafe_no_drop_flag)] + +#[unsafe_no_drop_flag] +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + panic!("MIR trans is not enabled for mem::forget"); + } +} + +fn main() { + let x = Foo; + std::mem::forget(x); +} From 5c88efc0da9d5222965fe8eaeb1bf48897da7ec1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Jul 2016 00:15:15 +0300 Subject: [PATCH 289/331] Properly enforce the "patterns aren't allowed in foreign functions" check Apply the same check to function pointer types --- src/librustc_passes/ast_validation.rs | 42 +++++++++++++++++--- src/librustc_passes/diagnostics.rs | 1 + src/test/compile-fail/no-patterns-in-args.rs | 30 ++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/no-patterns-in-args.rs diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 300750a625d5..d2cf48eddeba 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -55,6 +55,17 @@ impl<'a> AstValidator<'a> { err.emit(); } } + + fn check_decl_no_pat(&self, decl: &FnDecl, report_err: ReportFn) { + for arg in &decl.inputs { + match arg.pat.node { + PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) | + PatKind::Wild => {} + PatKind::Ident(..) => report_err(arg.pat.span, true), + _ => report_err(arg.pat.span, false), + } + } + } } impl<'a> Visitor for AstValidator<'a> { @@ -82,6 +93,23 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_expr(self, expr) } + fn visit_ty(&mut self, ty: &Ty) { + match ty.node { + TyKind::BareFn(ref bfty) => { + self.check_decl_no_pat(&bfty.decl, |span, _| { + let mut err = struct_span_err!(self.session, span, E0561, + "patterns aren't allowed in function pointer types"); + err.span_note(span, "this is a recent error, see \ + issue #35203 for more details"); + err.emit(); + }); + } + _ => {} + } + + visit::walk_ty(self, ty) + } + fn visit_path(&mut self, path: &Path, id: NodeId) { if path.global && path.segments.len() > 0 { let ident = path.segments[0].identifier; @@ -138,13 +166,15 @@ impl<'a> Visitor for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &ForeignItem) { match fi.node { ForeignItemKind::Fn(ref decl, _) => { - for arg in &decl.inputs { - match arg.pat.node { - PatKind::Ident(..) | PatKind::Wild => {} - _ => span_err!(self.session, arg.pat.span, E0130, - "patterns aren't allowed in foreign function declarations") + self.check_decl_no_pat(decl, |span, is_recent| { + let mut err = struct_span_err!(self.session, span, E0130, + "patterns aren't allowed in foreign function declarations"); + if is_recent { + err.span_note(span, "this is a recent error, see \ + issue #35203 for more details"); } - } + err.emit(); + }); } ForeignItemKind::Static(..) => {} } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index d6865ba13fc2..3e2dd477bccf 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -220,4 +220,5 @@ pub impl Foo for Bar { register_diagnostics! { E0472, // asm! is unsupported on this target + E0561, // patterns aren't allowed in function pointer types } diff --git a/src/test/compile-fail/no-patterns-in-args.rs b/src/test/compile-fail/no-patterns-in-args.rs new file mode 100644 index 000000000000..3edbdf4ebc95 --- /dev/null +++ b/src/test/compile-fail/no-patterns-in-args.rs @@ -0,0 +1,30 @@ +// 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. + +extern { + fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations + //~^ NOTE this is a recent error + fn f2(&arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations + fn f3(arg @ _: u8); //~ ERROR patterns aren't allowed in foreign function declarations + //~^ NOTE this is a recent error + fn g1(arg: u8); // OK + fn g2(_: u8); // OK + // fn g3(u8); // Not yet +} + +type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types + //~^ NOTE this is a recent error +type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types + //~^ NOTE this is a recent error +type B1 = fn(arg: u8); // OK +type B2 = fn(_: u8); // OK +type B3 = fn(u8); // OK + +fn main() {} From 3e46c9dfcc60733be20cc8de1361e809669e5096 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 27 Jul 2016 20:55:14 +0200 Subject: [PATCH 290/331] Add doc examples for FileType struct --- src/libstd/fs.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 48753ccf1c35..2b2f21522d4b 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -156,7 +156,10 @@ pub struct OpenOptions(fs_imp::OpenOptions); #[stable(feature = "rust1", since = "1.0.0")] pub struct Permissions(fs_imp::FilePermissions); -/// An structure representing a type of file with accessors for each file type. +/// A structure representing a type of file with accessors for each file type. +/// It is returned by [`Metadata::file_type`] method. +/// +/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type #[stable(feature = "file_type", since = "1.1.0")] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType(fs_imp::FileType); @@ -610,6 +613,19 @@ impl AsInnerMut for OpenOptions { impl Metadata { /// Returns the file type for this metadata. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// println!("{:?}", metadata.file_type()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn file_type(&self) -> FileType { FileType(self.0.file_type()) @@ -788,14 +804,56 @@ impl Permissions { impl FileType { /// Test whether this file type represents a directory. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// let file_type = metadata.file_type(); + /// + /// assert_eq!(file_type.is_dir(), false); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_dir(&self) -> bool { self.0.is_dir() } /// Test whether this file type represents a regular file. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// let file_type = metadata.file_type(); + /// + /// assert_eq!(file_type.is_file(), true); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_file(&self) -> bool { self.0.is_file() } /// Test whether this file type represents a symbolic link. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// let file_type = metadata.file_type(); + /// + /// assert_eq!(file_type.is_symlink(), false); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_symlink(&self) -> bool { self.0.is_symlink() } } From 81df89fc2d6ba1b55ab20b0615b8523a6e90963f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 1 Aug 2016 21:43:57 +0300 Subject: [PATCH 291/331] remove the ExecutionEngine binding the code has no tests and will just bitrot by itself. this is a [breaking-change] --- mk/rustllvm.mk | 2 +- src/librustc_llvm/build.rs | 3 +- src/librustc_llvm/lib.rs | 9 -- src/rustllvm/ExecutionEngineWrapper.cpp | 111 ------------------------ 4 files changed, 2 insertions(+), 123 deletions(-) delete mode 100644 src/rustllvm/ExecutionEngineWrapper.cpp diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk index 834a11d37fa4..b50dbd01ad0c 100644 --- a/mk/rustllvm.mk +++ b/mk/rustllvm.mk @@ -24,7 +24,7 @@ LLVM_EXTRA_INCDIRS_$(1)= $$(call CFG_CC_INCLUDE_$(1),$(S)src/llvm/include) \ endif RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \ - ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp \ + RustWrapper.cpp PassWrapper.cpp \ ArchiveWrapper.cpp) RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \ diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 085ea240a505..b8548aaec5bd 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -112,8 +112,7 @@ fn main() { cfg.flag(&flag); } - cfg.file("../rustllvm/ExecutionEngineWrapper.cpp") - .file("../rustllvm/PassWrapper.cpp") + cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") .cpp(true) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 6905abc29024..de82778bc5e3 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -1099,15 +1099,6 @@ extern { Name: *const c_char); pub fn LLVMDisposeBuilder(Builder: BuilderRef); - /* Execution engine */ - pub fn LLVMBuildExecutionEngine(Mod: ModuleRef) -> ExecutionEngineRef; - pub fn LLVMDisposeExecutionEngine(EE: ExecutionEngineRef); - pub fn LLVMExecutionEngineFinalizeObject(EE: ExecutionEngineRef); - pub fn LLVMRustLoadDynamicLibrary(path: *const c_char) -> Bool; - pub fn LLVMExecutionEngineAddModule(EE: ExecutionEngineRef, M: ModuleRef); - pub fn LLVMExecutionEngineRemoveModule(EE: ExecutionEngineRef, M: ModuleRef) - -> Bool; - /* Metadata */ pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; diff --git a/src/rustllvm/ExecutionEngineWrapper.cpp b/src/rustllvm/ExecutionEngineWrapper.cpp deleted file mode 100644 index b26ab4460199..000000000000 --- a/src/rustllvm/ExecutionEngineWrapper.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include "rustllvm.h" - -#include "llvm/ExecutionEngine/SectionMemoryManager.h" - -using namespace llvm; -using namespace llvm::sys; -using namespace llvm::object; - -class RustJITMemoryManager : public SectionMemoryManager -{ - typedef SectionMemoryManager Base; - - public: - - RustJITMemoryManager() {} - - uint64_t getSymbolAddress(const std::string &Name) override - { - return Base::getSymbolAddress(Name); - } -}; - -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RustJITMemoryManager, LLVMRustJITMemoryManagerRef) - -extern "C" LLVMBool LLVMRustLoadDynamicLibrary(const char *path) -{ - std::string err; - DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(path, &err); - - if (!lib.isValid()) - LLVMRustSetLastError(err.c_str()); - - return lib.isValid(); -} - -// Calls LLVMAddModule; -// exists for consistency with LLVMExecutionEngineRemoveModule -extern "C" void LLVMExecutionEngineAddModule( - LLVMExecutionEngineRef eeref, LLVMModuleRef mref) -{ -#ifdef _WIN32 - // On Windows, MCJIT must generate ELF objects - std::string target = getProcessTriple(); - target += "-elf"; - target = Triple::normalize(target); - unwrap(mref)->setTargetTriple(target); -#endif - LLVMAddModule(eeref, mref); -} - -// LLVMRemoveModule exists in LLVM's C bindings, -// but it requires pointless parameters -extern "C" LLVMBool LLVMExecutionEngineRemoveModule( - LLVMExecutionEngineRef eeref, LLVMModuleRef mref) -{ - ExecutionEngine *ee = unwrap(eeref); - Module *m = unwrap(mref); - - return ee->removeModule(m); -} - -extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(LLVMModuleRef mod) -{ - // These are necessary for code generation to work properly. - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - -#ifdef _WIN32 - // On Windows, MCJIT must generate ELF objects - std::string target = getProcessTriple(); - target += "-elf"; - target = Triple::normalize(target); - unwrap(mod)->setTargetTriple(target); -#endif - - std::string error_str; - TargetOptions options; - - RustJITMemoryManager *mm = new RustJITMemoryManager; - - ExecutionEngine *ee = - EngineBuilder(std::unique_ptr(unwrap(mod))) - .setMCJITMemoryManager(std::unique_ptr(mm)) - .setEngineKind(EngineKind::JIT) - .setErrorStr(&error_str) - .setTargetOptions(options) - .create(); - - if (!ee) - LLVMRustSetLastError(error_str.c_str()); - - return wrap(ee); -} - -extern "C" void LLVMExecutionEngineFinalizeObject(LLVMExecutionEngineRef eeref) -{ - ExecutionEngine *ee = unwrap(eeref); - - ee->finalizeObject(); -} From 696691e3c4f2b3aa02fbd1cc76dc2f7e8a401db8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 2 Aug 2016 00:16:16 +0300 Subject: [PATCH 292/331] audit LLVM C++ types in ArchiveWrapper and PassWrapper --- src/librustc_llvm/lib.rs | 76 ++++++++++------ src/librustc_trans/back/archive.rs | 2 +- src/librustc_trans/back/write.rs | 46 +++++----- src/librustc_trans/context.rs | 10 +-- src/rustllvm/ArchiveWrapper.cpp | 98 +++++++++++++------- src/rustllvm/PassWrapper.cpp | 138 +++++++++++++++++++++++------ src/rustllvm/README | 14 +++ src/rustllvm/rustllvm.h | 5 ++ 8 files changed, 275 insertions(+), 114 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index de82778bc5e3..4019732221fe 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -40,13 +40,9 @@ pub use self::TypeKind::*; pub use self::AtomicBinOp::*; pub use self::AtomicOrdering::*; pub use self::SynchronizationScope::*; -pub use self::FileType::*; pub use self::MetadataType::*; pub use self::AsmDialect::*; -pub use self::CodeGenOptLevel::*; pub use self::CodeGenOptSize::*; -pub use self::RelocMode::*; -pub use self::CodeGenModel::*; pub use self::DiagnosticKind::*; pub use self::CallConv::*; pub use self::Visibility::*; @@ -75,9 +71,26 @@ pub type Bool = c_uint; pub const True: Bool = 1 as Bool; pub const False: Bool = 0 as Bool; +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +pub enum LLVMRustResult { + Success = 0, + Failure = 1 +} + +impl LLVMRustResult { + pub fn into_result(self) -> Result<(), ()> { + match self { + LLVMRustResult::Success => Ok(()), + LLVMRustResult::Failure => Err(()), + } + } +} + // Consts for the LLVM CallConv type, pre-cast to usize. #[derive(Copy, Clone, PartialEq)] +#[repr(C)] pub enum CallConv { CCallConv = 0, FastCallConv = 8, @@ -89,6 +102,7 @@ pub enum CallConv { } #[derive(Copy, Clone)] +#[repr(C)] pub enum Visibility { LLVMDefaultVisibility = 0, HiddenVisibility = 1, @@ -100,6 +114,7 @@ pub enum Visibility { // LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; // they've been removed in upstream LLVM commit r203866. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[repr(C)] pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, @@ -337,12 +352,12 @@ pub enum SynchronizationScope { CrossThread = 1 } -// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h) #[repr(C)] #[derive(Copy, Clone)] pub enum FileType { - AssemblyFileType = 0, - ObjectFileType = 1 + Other, + AssemblyFile, + ObjectFile, } #[derive(Copy, Clone)] @@ -371,10 +386,11 @@ pub enum AsmDialect { #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum CodeGenOptLevel { - CodeGenLevelNone = 0, - CodeGenLevelLess = 1, - CodeGenLevelDefault = 2, - CodeGenLevelAggressive = 3, + Other, + None, + Less, + Default, + Aggressive, } #[derive(Copy, Clone, PartialEq)] @@ -388,21 +404,22 @@ pub enum CodeGenOptSize { #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum RelocMode { - RelocDefault = 0, - RelocStatic = 1, - RelocPIC = 2, - RelocDynamicNoPic = 3, + Default = 0, + Static = 1, + PIC = 2, + DynamicNoPic = 3, } #[repr(C)] #[derive(Copy, Clone)] -pub enum CodeGenModel { - CodeModelDefault = 0, - CodeModelJITDefault = 1, - CodeModelSmall = 2, - CodeModelKernel = 3, - CodeModelMedium = 4, - CodeModelLarge = 5, +pub enum CodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, } #[repr(C)] @@ -421,6 +438,7 @@ pub enum DiagnosticKind { #[repr(C)] #[derive(Copy, Clone)] pub enum ArchiveKind { + Other, K_GNU, K_MIPS64, K_BSD, @@ -444,10 +462,10 @@ impl FromStr for ArchiveKind { /// Represents the different LLVM passes Rust supports #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] -pub enum SupportedPassKind { +pub enum PassKind { + Other, Function, Module, - Unsupported, } // Opaque pointer types @@ -2021,7 +2039,7 @@ extern { pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; - pub fn LLVMRustPassKind(Pass: PassRef) -> SupportedPassKind; + pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind; pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); @@ -2031,7 +2049,7 @@ extern { pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, CPU: *const c_char, Features: *const c_char, - Model: CodeGenModel, + Model: CodeModel, Reloc: RelocMode, Level: CodeGenOptLevel, UseSoftFP: bool, @@ -2057,7 +2075,8 @@ extern { PM: PassManagerRef, M: ModuleRef, Output: *const c_char, - FileType: FileType) -> bool; + FileType: FileType) + -> LLVMRustResult; pub fn LLVMRustPrintModule(PM: PassManagerRef, M: ModuleRef, Output: *const c_char); @@ -2123,7 +2142,8 @@ extern { NumMembers: size_t, Members: *const RustArchiveMemberRef, WriteSymbtab: bool, - Kind: ArchiveKind) -> c_int; + Kind: ArchiveKind) -> + LLVMRustResult; pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, Name: *const c_char, Child: ArchiveChildRef) -> RustArchiveMemberRef; diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 29019f3683de..e063209799f1 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -293,7 +293,7 @@ impl<'a> ArchiveBuilder<'a> { members.as_ptr(), self.should_update_symbols, kind); - let ret = if r != 0 { + let ret = if r.into_result().is_err() { let err = llvm::LLVMRustGetLastError(); let msg = if err.is_null() { "failed to write archive".to_string() diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 87815c63f799..0f3a45a7cff7 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -54,7 +54,7 @@ pub fn write_output_file( let output_c = path2cstr(output); let result = llvm::LLVMRustWriteOutputFile( target, pm, m, output_c.as_ptr(), file_type); - if !result { + if result.into_result().is_err() { llvm_err(handler, format!("could not write output to {}", output.display())); } } @@ -138,11 +138,11 @@ fn target_feature(sess: &Session) -> String { fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { match optimize { - config::OptLevel::No => llvm::CodeGenLevelNone, - config::OptLevel::Less => llvm::CodeGenLevelLess, - config::OptLevel::Default => llvm::CodeGenLevelDefault, - config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive, - _ => llvm::CodeGenLevelDefault, + config::OptLevel::No => llvm::CodeGenOptLevel::None, + config::OptLevel::Less => llvm::CodeGenOptLevel::Less, + config::OptLevel::Default => llvm::CodeGenOptLevel::Default, + config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, + _ => llvm::CodeGenOptLevel::Default, } } @@ -169,11 +169,11 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { }; let code_model = match code_model_arg { - "default" => llvm::CodeModelDefault, - "small" => llvm::CodeModelSmall, - "kernel" => llvm::CodeModelKernel, - "medium" => llvm::CodeModelMedium, - "large" => llvm::CodeModelLarge, + "default" => llvm::CodeModel::Default, + "small" => llvm::CodeModel::Small, + "kernel" => llvm::CodeModel::Kernel, + "medium" => llvm::CodeModel::Medium, + "large" => llvm::CodeModel::Large, _ => { sess.err(&format!("{:?} is not a valid code model", sess.opts @@ -449,9 +449,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, return false; } let pass_manager = match llvm::LLVMRustPassKind(pass) { - llvm::SupportedPassKind::Function => fpm, - llvm::SupportedPassKind::Module => mpm, - llvm::SupportedPassKind::Unsupported => { + llvm::PassKind::Function => fpm, + llvm::PassKind::Module => mpm, + llvm::PassKind::Other => { cgcx.handler.err("Encountered LLVM pass kind we can't handle"); return true }, @@ -579,7 +579,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }; with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &path, - llvm::AssemblyFileType); + llvm::FileType::AssemblyFile); }); if config.emit_obj { llvm::LLVMDisposeModule(llmod); @@ -588,7 +588,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, llvm::ObjectFileType); + write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, + llvm::FileType::ObjectFile); }); } }); @@ -1078,7 +1079,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_level = config.opt_level.unwrap_or(llvm::CodeGenLevelNone); + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; @@ -1102,7 +1103,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, (_, _, Some(t)) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); } - (llvm::CodeGenLevelAggressive, _, _) => { + (llvm::CodeGenOptLevel::Aggressive, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); } (_, llvm::CodeGenOptSizeDefault, _) => { @@ -1111,15 +1112,18 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, (_, llvm::CodeGenOptSizeAggressive, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); } - (llvm::CodeGenLevelNone, _, _) => { + (llvm::CodeGenOptLevel::None, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, false); } - (llvm::CodeGenLevelLess, _, _) => { + (llvm::CodeGenOptLevel::Less, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, true); } - (llvm::CodeGenLevelDefault, _, _) => { + (llvm::CodeGenOptLevel::Default, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } + (llvm::CodeGenOptLevel::Other, _, _) => { + bug!("CodeGenOptLevel::Other selected") + } } f(builder); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 5a3c1c8512ad..166ce990fddf 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -325,10 +325,10 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { }; match reloc_model_arg { - "pic" => llvm::RelocPIC, - "static" => llvm::RelocStatic, - "default" => llvm::RelocDefault, - "dynamic-no-pic" => llvm::RelocDynamicNoPic, + "pic" => llvm::RelocMode::PIC, + "static" => llvm::RelocMode::Static, + "default" => llvm::RelocMode::Default, + "dynamic-no-pic" => llvm::RelocMode::DynamicNoPic, _ => { sess.err(&format!("{:?} is not a valid relocation mode", sess.opts @@ -347,7 +347,7 @@ fn is_any_library(sess: &Session) -> bool { } pub fn is_pie_binary(sess: &Session) -> bool { - !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocPIC + !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC } unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 3d48024c8798..059cc40d5114 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -16,24 +16,62 @@ using namespace llvm; using namespace llvm::object; -struct LLVMRustArchiveMember { +struct RustArchiveMember { const char *filename; const char *name; Archive::Child child; - LLVMRustArchiveMember(): filename(NULL), name(NULL), + RustArchiveMember(): filename(NULL), name(NULL), #if LLVM_VERSION_MINOR >= 8 child(NULL, NULL, NULL) #else child(NULL, NULL) #endif {} - ~LLVMRustArchiveMember() {} + ~RustArchiveMember() {} }; -typedef OwningBinary RustArchive; -extern "C" void* +struct RustArchiveIterator { + Archive::child_iterator cur; + Archive::child_iterator end; +#if LLVM_VERSION_MINOR >= 9 + Error err; +#endif +}; + +enum class LLVMRustArchiveKind { + Other, + GNU, + MIPS64, + BSD, + COFF, +}; + +static Archive::Kind +from_rust(LLVMRustArchiveKind kind) +{ + switch (kind) { + case LLVMRustArchiveKind::GNU: + return Archive::K_GNU; + case LLVMRustArchiveKind::MIPS64: + return Archive::K_MIPS64; + case LLVMRustArchiveKind::BSD: + return Archive::K_BSD; + case LLVMRustArchiveKind::COFF: + return Archive::K_COFF; + default: + abort(); + } +} + +typedef OwningBinary *LLVMRustArchiveRef; +typedef RustArchiveMember *LLVMRustArchiveMemberRef; +typedef Archive::Child *LLVMRustArchiveChildRef; +typedef Archive::Child const *LLVMRustArchiveChildConstRef; +typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; + +extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *path) { ErrorOr> buf_or = MemoryBuffer::getFile(path, -1, @@ -66,20 +104,12 @@ LLVMRustOpenArchive(char *path) { } extern "C" void -LLVMRustDestroyArchive(RustArchive *ar) { +LLVMRustDestroyArchive(LLVMRustArchiveRef ar) { delete ar; } -struct RustArchiveIterator { - Archive::child_iterator cur; - Archive::child_iterator end; -#if LLVM_VERSION_MINOR >= 9 - Error err; -#endif -}; - -extern "C" RustArchiveIterator* -LLVMRustArchiveIteratorNew(RustArchive *ra) { +extern "C" LLVMRustArchiveIteratorRef +LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) { Archive *ar = ra->getBinary(); RustArchiveIterator *rai = new RustArchiveIterator(); #if LLVM_VERSION_MINOR <= 8 @@ -95,8 +125,8 @@ LLVMRustArchiveIteratorNew(RustArchive *ra) { return rai; } -extern "C" const Archive::Child* -LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { +extern "C" LLVMRustArchiveChildConstRef +LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) { #if LLVM_VERSION_MINOR >= 9 if (rai->err) { LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); @@ -122,17 +152,17 @@ LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { } extern "C" void -LLVMRustArchiveChildFree(Archive::Child *child) { +LLVMRustArchiveChildFree(LLVMRustArchiveChildRef child) { delete child; } extern "C" void -LLVMRustArchiveIteratorFree(RustArchiveIterator *rai) { +LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef rai) { delete rai; } extern "C" const char* -LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { +LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef child, size_t *size) { ErrorOr name_or_err = child->getName(); if (name_or_err.getError()) return NULL; @@ -142,7 +172,7 @@ LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { } extern "C" const char* -LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { +LLVMRustArchiveChildData(LLVMRustArchiveChildRef child, size_t *size) { StringRef buf; ErrorOr buf_or_err = child->getBuffer(); if (buf_or_err.getError()) { @@ -154,9 +184,10 @@ LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { return buf.data(); } -extern "C" LLVMRustArchiveMember* -LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { - LLVMRustArchiveMember *Member = new LLVMRustArchiveMember; +extern "C" LLVMRustArchiveMemberRef +LLVMRustArchiveMemberNew(char *Filename, char *Name, + LLVMRustArchiveChildRef child) { + RustArchiveMember *Member = new RustArchiveMember; Member->filename = Filename; Member->name = Name; if (child) @@ -165,22 +196,23 @@ LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { } extern "C" void -LLVMRustArchiveMemberFree(LLVMRustArchiveMember *Member) { +LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) { delete Member; } -extern "C" int +extern "C" LLVMRustResult LLVMRustWriteArchive(char *Dst, size_t NumMembers, - const LLVMRustArchiveMember **NewMembers, + const LLVMRustArchiveMemberRef *NewMembers, bool WriteSymbtab, - Archive::Kind Kind) { + LLVMRustArchiveKind rust_kind) { #if LLVM_VERSION_MINOR <= 8 std::vector Members; #else std::vector Members; #endif + auto Kind = from_rust(rust_kind); for (size_t i = 0; i < NumMembers; i++) { auto Member = NewMembers[i]; @@ -190,7 +222,7 @@ LLVMRustWriteArchive(char *Dst, Expected MOrErr = NewArchiveMember::getFile(Member->filename, true); if (!MOrErr) { LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); - return -1; + return LLVMRustResult::Failure; } Members.push_back(std::move(*MOrErr)); #elif LLVM_VERSION_MINOR == 8 @@ -205,7 +237,7 @@ LLVMRustWriteArchive(char *Dst, Expected MOrErr = NewArchiveMember::getOldMember(Member->child, true); if (!MOrErr) { LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); - return -1; + return LLVMRustResult::Failure; } Members.push_back(std::move(*MOrErr)); #endif @@ -217,7 +249,7 @@ LLVMRustWriteArchive(char *Dst, auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true); #endif if (!pair.second) - return 0; + return LLVMRustResult::Success; LLVMRustSetLastError(pair.second.message().c_str()); - return -1; + return LLVMRustResult::Failure; } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a1276060271b..9e72724d8ab7 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -54,41 +54,48 @@ LLVMInitializePasses() { initializeTarget(Registry); } - -enum class SupportedPassKind { +enum class LLVMRustPassKind { + Other, Function, Module, - Unsupported }; -extern "C" Pass* +static LLVMRustPassKind +to_rust(PassKind kind) +{ + switch (kind) { + case PT_Function: + return LLVMRustPassKind::Function; + case PT_Module: + return LLVMRustPassKind::Module; + default: + return LLVMRustPassKind::Other; + } +} + +extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) { StringRef SR(PassName); PassRegistry *PR = PassRegistry::getPassRegistry(); const PassInfo *PI = PR->getPassInfo(SR); if (PI) { - return PI->createPass(); + return wrap(PI->createPass()); } return NULL; } -extern "C" SupportedPassKind -LLVMRustPassKind(Pass *pass) { - assert(pass); - PassKind passKind = pass->getPassKind(); - if (passKind == PT_Module) { - return SupportedPassKind::Module; - } else if (passKind == PT_Function) { - return SupportedPassKind::Function; - } else { - return SupportedPassKind::Unsupported; - } +extern "C" LLVMRustPassKind +LLVMRustPassKind(LLVMPassRef rust_pass) { + assert(rust_pass); + Pass *pass = unwrap(rust_pass); + return to_rust(pass->getPassKind()); } extern "C" void -LLVMRustAddPass(LLVMPassManagerRef PM, Pass *pass) { - assert(pass); +LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { + assert(rust_pass); + Pass *pass = unwrap(rust_pass); PassManagerBase *pm = unwrap(PM); pm->add(pass); } @@ -162,13 +169,69 @@ LLVMRustHasFeature(LLVMTargetMachineRef TM, return (Bits & FeatureEntry->Value) == FeatureEntry->Value; } +enum class LLVMRustCodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, +}; + +static CodeModel::Model +from_rust(LLVMRustCodeModel model) +{ + switch (model) { + case LLVMRustCodeModel::Default: + return CodeModel::Default; + case LLVMRustCodeModel::JITDefault: + return CodeModel::JITDefault; + case LLVMRustCodeModel::Small: + return CodeModel::Small; + case LLVMRustCodeModel::Kernel: + return CodeModel::Kernel; + case LLVMRustCodeModel::Medium: + return CodeModel::Medium; + case LLVMRustCodeModel::Large: + return CodeModel::Large; + default: + abort(); + } +} + +enum class LLVMRustCodeGenOptLevel { + Other, + None, + Less, + Default, + Aggressive, +}; + +static CodeGenOpt::Level +from_rust(LLVMRustCodeGenOptLevel level) +{ + switch (level) { + case LLVMRustCodeGenOptLevel::None: + return CodeGenOpt::None; + case LLVMRustCodeGenOptLevel::Less: + return CodeGenOpt::Less; + case LLVMRustCodeGenOptLevel::Default: + return CodeGenOpt::Default; + case LLVMRustCodeGenOptLevel::Aggressive: + return CodeGenOpt::Aggressive; + default: + abort(); + } +} + extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(const char *triple, const char *cpu, const char *feature, - CodeModel::Model CM, + LLVMRustCodeModel rust_CM, LLVMRelocMode Reloc, - CodeGenOpt::Level OptLevel, + LLVMRustCodeGenOptLevel rust_OptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, @@ -179,6 +242,9 @@ LLVMRustCreateTargetMachine(const char *triple, #else Optional RM; #endif + auto CM = from_rust(rust_CM); + auto OptLevel = from_rust(rust_OptLevel); + switch (Reloc){ case LLVMRelocStatic: RM = Reloc::Static; @@ -251,14 +317,14 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, extern "C" void LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB, - CodeGenOpt::Level OptLevel, + LLVMRustCodeGenOptLevel OptLevel, bool MergeFunctions, bool SLPVectorize, bool LoopVectorize) { // Ignore mergefunc for now as enabling it causes crashes. //unwrap(PMB)->MergeFunctions = MergeFunctions; unwrap(PMB)->SLPVectorize = SLPVectorize; - unwrap(PMB)->OptLevel = OptLevel; + unwrap(PMB)->OptLevel = from_rust(OptLevel); unwrap(PMB)->LoopVectorize = LoopVectorize; } @@ -314,13 +380,33 @@ LLVMRustSetLLVMOptions(int Argc, char **Argv) { cl::ParseCommandLineOptions(Argc, Argv); } -extern "C" bool +enum class LLVMRustFileType { + Other, + AssemblyFile, + ObjectFile, +}; + +static TargetMachine::CodeGenFileType +from_rust(LLVMRustFileType type) +{ + switch (type) { + case LLVMRustFileType::AssemblyFile: + return TargetMachine::CGFT_AssemblyFile; + case LLVMRustFileType::ObjectFile: + return TargetMachine::CGFT_ObjectFile; + default: + abort(); + } +} + +extern "C" LLVMRustResult LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, LLVMModuleRef M, const char *path, - TargetMachine::CodeGenFileType FileType) { + LLVMRustFileType rust_FileType) { llvm::legacy::PassManager *PM = unwrap(PMR); + auto FileType = from_rust(rust_FileType); std::string ErrorInfo; std::error_code EC; @@ -329,7 +415,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, ErrorInfo = EC.message(); if (ErrorInfo != "") { LLVMRustSetLastError(ErrorInfo.c_str()); - return false; + return LLVMRustResult::Failure; } unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false); @@ -339,7 +425,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, // stream (OS), so the only real safe place to delete this is here? Don't we // wish this was written in Rust? delete PM; - return true; + return LLVMRustResult::Success; } extern "C" void diff --git a/src/rustllvm/README b/src/rustllvm/README index c0db3f68a762..e1c6dd07d2b3 100644 --- a/src/rustllvm/README +++ b/src/rustllvm/README @@ -1,2 +1,16 @@ This directory currently contains some LLVM support code. This will generally be sent upstream to LLVM in time; for now it lives here. + +NOTE: the LLVM C++ ABI is subject to between-version breakage and must *never* +be exposed to Rust. To allow for easy auditing of that, all Rust-exposed types +must be typedef-ed as "LLVMXyz", or "LLVMRustXyz" if they were defined here. + +Functions that return a failure status and leave the error in +the LLVM last error should return an LLVMRustResult rather than an +int or anything to avoid confusion. + +When translating enums, add a single `Other` variant as the first +one to allow for new variants to be added. It should abort when used +as an input. + +All other types must not be typedef-ed as such. diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 2a47e8b08954..5aae11fb456b 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -58,6 +58,11 @@ void LLVMRustSetLastError(const char*); +enum class LLVMRustResult { + Success, + Failure +}; + typedef struct OpaqueRustString *RustStringRef; typedef struct LLVMOpaqueTwine *LLVMTwineRef; typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef; From d091ef802f5aa6d5b81e711ecd7e5f66a76b01a9 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 2 Aug 2016 02:35:09 +0300 Subject: [PATCH 293/331] begin auditing the C++ types in RustWrapper --- src/librustc_driver/lib.rs | 2 +- src/librustc_llvm/diagnostic.rs | 55 +- src/librustc_llvm/lib.rs | 600 +++++++++--------- src/librustc_trans/attributes.rs | 8 +- src/librustc_trans/back/write.rs | 4 +- src/librustc_trans/base.rs | 3 +- src/librustc_trans/builder.rs | 10 +- src/librustc_trans/consts.rs | 4 +- .../debuginfo/create_scope_map.rs | 6 +- src/librustc_trans/debuginfo/metadata.rs | 67 +- src/librustc_trans/debuginfo/mod.rs | 16 +- src/librustc_trans/debuginfo/namespace.rs | 2 +- src/librustc_trans/debuginfo/source_loc.rs | 2 +- src/librustc_trans/debuginfo/utils.rs | 2 +- src/librustc_trans/declare.rs | 6 +- src/librustc_trans/intrinsic.rs | 26 +- src/librustc_trans/mir/mod.rs | 10 +- src/librustc_trans/type_.rs | 4 +- src/librustc_trans/value.rs | 2 +- src/rustllvm/RustWrapper.cpp | 516 +++++++++------ 20 files changed, 757 insertions(+), 588 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f49d47fb0815..772c59b34dd0 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -186,7 +186,7 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], let sopts = config::build_session_options(&matches); if sopts.debugging_opts.debug_llvm { - unsafe { llvm::LLVMSetDebug(1); } + unsafe { llvm::LLVMRustSetDebug(1); } } let descriptions = diagnostics_registry(); diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index 44e015614640..4938a0216ee4 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -23,15 +23,21 @@ pub enum OptimizationDiagnosticKind { OptimizationRemark, OptimizationMissed, OptimizationAnalysis, + OptimizationAnalysisFPCommute, + OptimizationAnalysisAliasing, OptimizationFailure, + OptimizationRemarkOther, } impl OptimizationDiagnosticKind { pub fn describe(self) -> &'static str { match self { - OptimizationRemark => "remark", + OptimizationRemark | + OptimizationRemarkOther => "remark", OptimizationMissed => "missed", OptimizationAnalysis => "analysis", + OptimizationAnalysisFPCommute => "floating-point", + OptimizationAnalysisAliasing => "aliasing", OptimizationFailure => "failure", } } @@ -58,11 +64,11 @@ impl OptimizationDiagnostic { message: ptr::null_mut(), }; - super::LLVMUnpackOptimizationDiagnostic(di, - &mut opt.pass_name, - &mut opt.function, - &mut opt.debug_loc, - &mut opt.message); + super::LLVMRustUnpackOptimizationDiagnostic(di, + &mut opt.pass_name, + &mut opt.function, + &mut opt.debug_loc, + &mut opt.message); opt } @@ -84,10 +90,10 @@ impl InlineAsmDiagnostic { instruction: ptr::null_mut(), }; - super::LLVMUnpackInlineAsmDiagnostic(di, - &mut opt.cookie, - &mut opt.message, - &mut opt.instruction); + super::LLVMRustUnpackInlineAsmDiagnostic(di, + &mut opt.cookie, + &mut opt.message, + &mut opt.instruction); opt } @@ -103,24 +109,39 @@ pub enum Diagnostic { impl Diagnostic { pub unsafe fn unpack(di: DiagnosticInfoRef) -> Diagnostic { - let kind = super::LLVMGetDiagInfoKind(di); + use super::DiagnosticKind as Dk; + let kind = super::LLVMRustGetDiagInfoKind(di); match kind { - super::DK_InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)), + Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)), - super::DK_OptimizationRemark => { + Dk::OptimizationRemark => { Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) } - - super::DK_OptimizationRemarkMissed => { + Dk::OptimizationRemarkOther => { + Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) + } + Dk::OptimizationRemarkMissed => { Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) } - super::DK_OptimizationRemarkAnalysis => { + Dk::OptimizationRemarkAnalysis => { Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) } - super::DK_OptimizationFailure => { + + Dk::OptimizationRemarkAnalysisFPCommute => { + Optimization(OptimizationDiagnostic::unpack( + OptimizationAnalysisFPCommute, di)) + } + + Dk::OptimizationRemarkAnalysisAliasing => { + Optimization(OptimizationDiagnostic::unpack( + OptimizationAnalysisAliasing, di)) + } + + + Dk::OptimizationFailure => { Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 4019732221fe..622e7923d8fb 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -38,8 +38,6 @@ pub use self::IntPredicate::*; pub use self::RealPredicate::*; pub use self::TypeKind::*; pub use self::AtomicBinOp::*; -pub use self::AtomicOrdering::*; -pub use self::SynchronizationScope::*; pub use self::MetadataType::*; pub use self::AsmDialect::*; pub use self::CodeGenOptSize::*; @@ -48,7 +46,6 @@ pub use self::CallConv::*; pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -pub use self::DLLStorageClassTypes::*; use std::str::FromStr; use std::ffi::{CString, CStr}; @@ -132,19 +129,20 @@ pub enum Linkage { #[repr(C)] #[derive(Copy, Clone, Debug)] pub enum DiagnosticSeverity { - Error, - Warning, - Remark, - Note, + Error = 0, + Warning = 1, + Remark = 2, + Note = 3, } #[repr(C)] #[derive(Copy, Clone)] pub enum DLLStorageClassTypes { - DefaultStorageClass = 0, - DLLImportStorageClass = 1, - DLLExportStorageClass = 2, + Other, + Default, + DllImport, + DllExport, } bitflags! { @@ -231,10 +229,10 @@ impl Attributes { pub fn apply_llfn(&self, idx: usize, llfn: ValueRef) { unsafe { - LLVMAddFunctionAttribute(llfn, idx as c_uint, self.regular.bits()); + LLVMRustAddFunctionAttribute(llfn, idx as c_uint, self.regular.bits()); if self.dereferenceable_bytes != 0 { - LLVMAddDereferenceableAttr(llfn, idx as c_uint, - self.dereferenceable_bytes); + LLVMRustAddDereferenceableAttr(llfn, idx as c_uint, + self.dereferenceable_bytes); } } } @@ -243,8 +241,8 @@ impl Attributes { unsafe { LLVMRustAddCallSiteAttribute(callsite, idx as c_uint, self.regular.bits()); if self.dereferenceable_bytes != 0 { - LLVMAddDereferenceableCallSiteAttr(callsite, idx as c_uint, - self.dereferenceable_bytes); + LLVMRustAddDereferenceableCallSiteAttr(callsite, idx as c_uint, + self.dereferenceable_bytes); } } } @@ -348,8 +346,9 @@ pub enum AtomicOrdering { #[repr(C)] #[derive(Copy, Clone)] pub enum SynchronizationScope { - SingleThread = 0, - CrossThread = 1 + Other, + SingleThread, + CrossThread, } #[repr(C)] @@ -425,14 +424,18 @@ pub enum CodeModel { #[repr(C)] #[derive(Copy, Clone)] pub enum DiagnosticKind { - DK_InlineAsm = 0, - DK_StackSize, - DK_DebugMetadataVersion, - DK_SampleProfile, - DK_OptimizationRemark, - DK_OptimizationRemarkMissed, - DK_OptimizationRemarkAnalysis, - DK_OptimizationFailure, + Other, + InlineAsm, + StackSize, + DebugMetadataVersion, + SampleProfile, + OptimizationRemark, + OptimizationRemarkMissed, + OptimizationRemarkAnalysis, + OptimizationRemarkAnalysisFPCommute, + OptimizationRemarkAnalysisAliasing, + OptimizationRemarkOther, + OptimizationFailure, } #[repr(C)] @@ -705,7 +708,7 @@ extern { /* Operations on other types */ pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef; /* Operations on all values */ pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef; @@ -957,8 +960,13 @@ extern { Name: *const c_char, AddressSpace: c_uint) -> ValueRef; - pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef; - pub fn LLVMGetOrInsertGlobal(M: ModuleRef, Name: *const c_char, T: TypeRef) -> ValueRef; + pub fn LLVMGetNamedGlobal(M: ModuleRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustGetOrInsertGlobal(M: ModuleRef, + Name: *const c_char, + T: TypeRef) + -> ValueRef; pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; @@ -971,7 +979,7 @@ extern { pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); - pub fn LLVMGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; /* Operations on aliases */ pub fn LLVMAddAlias(M: ModuleRef, @@ -991,23 +999,27 @@ extern { pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; pub fn LLVMDeleteFunction(Fn: ValueRef); - pub fn LLVMGetOrInsertFunction(M: ModuleRef, - Name: *const c_char, - FunctionTy: TypeRef) - -> ValueRef; + pub fn LLVMRustGetOrInsertFunction(M: ModuleRef, + Name: *const c_char, + FunctionTy: TypeRef) + -> ValueRef; pub fn LLVMGetIntrinsicID(Fn: ValueRef) -> c_uint; pub fn LLVMGetFunctionCallConv(Fn: ValueRef) -> c_uint; pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); - pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); - pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); - pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, - Name: *const c_char, - Value: *const c_char); - pub fn LLVMRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: uint64_t); - pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); + pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); + pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, + Name: *const c_char, + Value: *const c_char); + pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, + index: c_uint, + attr: uint64_t); + pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, + index: c_uint, + Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); @@ -1077,9 +1089,9 @@ extern { pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: uint64_t); - pub fn LLVMAddDereferenceableCallSiteAttr(Instr: ValueRef, - index: c_uint, - bytes: uint64_t); + pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, + index: c_uint, + bytes: uint64_t); /* Operations on call instructions (only) */ pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; @@ -1556,28 +1568,29 @@ extern { -> ValueRef; /* Atomic Operations */ - pub fn LLVMBuildAtomicLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *const c_char, - Order: AtomicOrdering, - Alignment: c_uint) - -> ValueRef; + pub fn LLVMRustBuildAtomicLoad(B: BuilderRef, + PointerVal: ValueRef, + Name: *const c_char, + Order: AtomicOrdering, + Alignment: c_uint) + -> ValueRef; - pub fn LLVMBuildAtomicStore(B: BuilderRef, - Val: ValueRef, - Ptr: ValueRef, - Order: AtomicOrdering, - Alignment: c_uint) - -> ValueRef; + pub fn LLVMRustBuildAtomicStore(B: BuilderRef, + Val: ValueRef, + Ptr: ValueRef, + Order: AtomicOrdering, + Alignment: c_uint) + -> ValueRef; pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef, - LHS: ValueRef, - CMP: ValueRef, - RHS: ValueRef, - Order: AtomicOrdering, - FailureOrder: AtomicOrdering, - Weak: Bool) - -> ValueRef; + LHS: ValueRef, + CMP: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering, + FailureOrder: AtomicOrdering, + Weak: Bool) + -> ValueRef; + pub fn LLVMBuildAtomicRMW(B: BuilderRef, Op: AtomicBinOp, LHS: ValueRef, @@ -1586,9 +1599,9 @@ extern { SingleThreaded: Bool) -> ValueRef; - pub fn LLVMBuildAtomicFence(B: BuilderRef, - Order: AtomicOrdering, - Scope: SynchronizationScope); + pub fn LLVMRustBuildAtomicFence(B: BuilderRef, + Order: AtomicOrdering, + Scope: SynchronizationScope); /* Selected entries from the downcasts. */ @@ -1791,248 +1804,248 @@ extern { -> ValueRef; /// Enables LLVM debug output. - pub fn LLVMSetDebug(Enabled: c_int); + pub fn LLVMRustSetDebug(Enabled: c_int); /// Prepares inline assembly. - pub fn LLVMInlineAsm(Ty: TypeRef, - AsmString: *const c_char, - Constraints: *const c_char, - SideEffects: Bool, - AlignStack: Bool, - Dialect: c_uint) - -> ValueRef; + pub fn LLVMRustInlineAsm(Ty: TypeRef, + AsmString: *const c_char, + Constraints: *const c_char, + SideEffects: Bool, + AlignStack: Bool, + Dialect: c_uint) + -> ValueRef; pub fn LLVMRustDebugMetadataVersion() -> u32; - pub fn LLVMVersionMajor() -> u32; - pub fn LLVMVersionMinor() -> u32; + pub fn LLVMRustVersionMajor() -> u32; + pub fn LLVMRustVersionMinor() -> u32; pub fn LLVMRustAddModuleFlag(M: ModuleRef, name: *const c_char, value: u32); - pub fn LLVMDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; + pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; - pub fn LLVMDIBuilderDispose(Builder: DIBuilderRef); + pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef); - pub fn LLVMDIBuilderFinalize(Builder: DIBuilderRef); + pub fn LLVMRustDIBuilderFinalize(Builder: DIBuilderRef); - pub fn LLVMDIBuilderCreateCompileUnit(Builder: DIBuilderRef, - Lang: c_uint, - File: *const c_char, - Dir: *const c_char, - Producer: *const c_char, - isOptimized: bool, - Flags: *const c_char, - RuntimeVer: c_uint, - SplitName: *const c_char) - -> DIDescriptor; + pub fn LLVMRustDIBuilderCreateCompileUnit(Builder: DIBuilderRef, + Lang: c_uint, + File: *const c_char, + Dir: *const c_char, + Producer: *const c_char, + isOptimized: bool, + Flags: *const c_char, + RuntimeVer: c_uint, + SplitName: *const c_char) + -> DIDescriptor; - pub fn LLVMDIBuilderCreateFile(Builder: DIBuilderRef, - Filename: *const c_char, - Directory: *const c_char) - -> DIFile; + pub fn LLVMRustDIBuilderCreateFile(Builder: DIBuilderRef, + Filename: *const c_char, + Directory: *const c_char) + -> DIFile; - pub fn LLVMDIBuilderCreateSubroutineType(Builder: DIBuilderRef, - File: DIFile, - ParameterTypes: DIArray) - -> DICompositeType; + pub fn LLVMRustDIBuilderCreateSubroutineType(Builder: DIBuilderRef, + File: DIFile, + ParameterTypes: DIArray) + -> DICompositeType; - pub fn LLVMDIBuilderCreateFunction(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - LinkageName: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - isLocalToUnit: bool, - isDefinition: bool, - ScopeLine: c_uint, - Flags: c_uint, - isOptimized: bool, - Fn: ValueRef, - TParam: DIArray, - Decl: DIDescriptor) - -> DISubprogram; + pub fn LLVMRustDIBuilderCreateFunction(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + LinkageName: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + isDefinition: bool, + ScopeLine: c_uint, + Flags: c_uint, + isOptimized: bool, + Fn: ValueRef, + TParam: DIArray, + Decl: DIDescriptor) + -> DISubprogram; - pub fn LLVMDIBuilderCreateBasicType(Builder: DIBuilderRef, - Name: *const c_char, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Encoding: c_uint) - -> DIBasicType; + pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef, + Name: *const c_char, + SizeInBits: u64, + AlignInBits: u64, + Encoding: c_uint) + -> DIBasicType; - pub fn LLVMDIBuilderCreatePointerType(Builder: DIBuilderRef, + pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef, PointeeTy: DIType, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, + SizeInBits: u64, + AlignInBits: u64, Name: *const c_char) -> DIDerivedType; - pub fn LLVMDIBuilderCreateStructType(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Flags: c_uint, - DerivedFrom: DIType, - Elements: DIArray, - RunTimeLang: c_uint, - VTableHolder: DIType, - UniqueId: *const c_char) - -> DICompositeType; - - pub fn LLVMDIBuilderCreateMemberType(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNo: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - OffsetInBits: c_ulonglong, - Flags: c_uint, - Ty: DIType) - -> DIDerivedType; - - pub fn LLVMDIBuilderCreateLexicalBlock(Builder: DIBuilderRef, - Scope: DIScope, - File: DIFile, - Line: c_uint, - Col: c_uint) - -> DILexicalBlock; - - pub fn LLVMDIBuilderCreateStaticVariable(Builder: DIBuilderRef, - Context: DIScope, + pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Flags: c_uint, + DerivedFrom: DIType, + Elements: DIArray, + RunTimeLang: c_uint, + VTableHolder: DIType, + UniqueId: *const c_char) + -> DICompositeType; + + pub fn LLVMRustDIBuilderCreateMemberType(Builder: DIBuilderRef, + Scope: DIDescriptor, Name: *const c_char, - LinkageName: *const c_char, File: DIFile, LineNo: c_uint, - Ty: DIType, - isLocalToUnit: bool, - Val: ValueRef, - Decl: DIDescriptor) - -> DIGlobalVariable; + SizeInBits: u64, + AlignInBits: u64, + OffsetInBits: u64, + Flags: c_uint, + Ty: DIType) + -> DIDerivedType; - pub fn LLVMDIBuilderCreateVariable(Builder: DIBuilderRef, - Tag: c_uint, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - AlwaysPreserve: bool, - Flags: c_uint, - AddrOps: *const i64, - AddrOpsCount: c_uint, - ArgNo: c_uint) - -> DIVariable; + pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: DIBuilderRef, + Scope: DIScope, + File: DIFile, + Line: c_uint, + Col: c_uint) + -> DILexicalBlock; - pub fn LLVMDIBuilderCreateArrayType(Builder: DIBuilderRef, - Size: c_ulonglong, - AlignInBits: c_ulonglong, - Ty: DIType, - Subscripts: DIArray) - -> DIType; + pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef, + Context: DIScope, + Name: *const c_char, + LinkageName: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + Val: ValueRef, + Decl: DIDescriptor) + -> DIGlobalVariable; - pub fn LLVMDIBuilderCreateVectorType(Builder: DIBuilderRef, - Size: c_ulonglong, - AlignInBits: c_ulonglong, - Ty: DIType, - Subscripts: DIArray) - -> DIType; - - pub fn LLVMDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef, - Lo: c_longlong, - Count: c_longlong) - -> DISubrange; - - pub fn LLVMDIBuilderGetOrCreateArray(Builder: DIBuilderRef, - Ptr: *const DIDescriptor, - Count: c_uint) - -> DIArray; - - pub fn LLVMDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, + pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef, + Tag: c_uint, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + AlwaysPreserve: bool, + Flags: c_uint, AddrOps: *const i64, AddrOpsCount: c_uint, - DL: ValueRef, - InsertAtEnd: BasicBlockRef) - -> ValueRef; + ArgNo: c_uint) + -> DIVariable; - pub fn LLVMDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, - AddrOps: *const i64, - AddrOpsCount: c_uint, - DL: ValueRef, - InsertBefore: ValueRef) - -> ValueRef; + pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef, + Size: u64, + AlignInBits: u64, + Ty: DIType, + Subscripts: DIArray) + -> DIType; - pub fn LLVMDIBuilderCreateEnumerator(Builder: DIBuilderRef, - Name: *const c_char, - Val: c_ulonglong) - -> DIEnumerator; + pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef, + Size: u64, + AlignInBits: u64, + Ty: DIType, + Subscripts: DIArray) + -> DIType; - pub fn LLVMDIBuilderCreateEnumerationType(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Elements: DIArray, - ClassType: DIType) - -> DIType; + pub fn LLVMRustDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef, + Lo: i64, + Count: i64) + -> DISubrange; - pub fn LLVMDIBuilderCreateUnionType(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Flags: c_uint, - Elements: DIArray, - RunTimeLang: c_uint, - UniqueId: *const c_char) - -> DIType; + pub fn LLVMRustDIBuilderGetOrCreateArray(Builder: DIBuilderRef, + Ptr: *const DIDescriptor, + Count: c_uint) + -> DIArray; + + pub fn LLVMRustDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + AddrOps: *const i64, + AddrOpsCount: c_uint, + DL: ValueRef, + InsertAtEnd: BasicBlockRef) + -> ValueRef; + + pub fn LLVMRustDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + AddrOps: *const i64, + AddrOpsCount: c_uint, + DL: ValueRef, + InsertBefore: ValueRef) + -> ValueRef; + + pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef, + Name: *const c_char, + Val: u64) + -> DIEnumerator; + + pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Elements: DIArray, + ClassType: DIType) + -> DIType; + + pub fn LLVMRustDIBuilderCreateUnionType(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Flags: c_uint, + Elements: DIArray, + RunTimeLang: c_uint, + UniqueId: *const c_char) + -> DIType; pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool); - pub fn LLVMDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - Ty: DIType, - File: DIFile, - LineNo: c_uint, - ColumnNo: c_uint) - -> DITemplateTypeParameter; + pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + Ty: DIType, + File: DIFile, + LineNo: c_uint, + ColumnNo: c_uint) + -> DITemplateTypeParameter; - pub fn LLVMDIBuilderCreateOpDeref() -> i64; - pub fn LLVMDIBuilderCreateOpPlus() -> i64; - - pub fn LLVMDIBuilderCreateNameSpace(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNo: c_uint) - -> DINameSpace; - - pub fn LLVMDIBuilderCreateDebugLocation(Context: ContextRef, - Line: c_uint, - Column: c_uint, + pub fn LLVMRustDIBuilderCreateNameSpace(Builder: DIBuilderRef, Scope: DIScope, - InlinedAt: MetadataRef) - -> ValueRef; + Name: *const c_char, + File: DIFile, + LineNo: c_uint) + -> DINameSpace; + pub fn LLVMRustDICompositeTypeSetTypeArray(Builder: DIBuilderRef, + CompositeType: DIType, + TypeArray: DIArray); - pub fn LLVMDICompositeTypeSetTypeArray(Builder: DIBuilderRef, - CompositeType: DIType, - TypeArray: DIArray); - pub fn LLVMWriteTypeToString(Type: TypeRef, s: RustStringRef); - pub fn LLVMWriteValueToString(value_ref: ValueRef, s: RustStringRef); + + pub fn LLVMRustDIBuilderCreateDebugLocation(Context: ContextRef, + Line: c_uint, + Column: c_uint, + Scope: DIScope, + InlinedAt: MetadataRef) + -> ValueRef; + pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; + pub fn LLVMRustDIBuilderCreateOpPlus() -> i64; + + pub fn LLVMRustWriteTypeToString(Type: TypeRef, s: RustStringRef); + pub fn LLVMRustWriteValueToString(value_ref: ValueRef, s: RustStringRef); pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; @@ -2108,35 +2121,38 @@ extern { C: DLLStorageClassTypes); pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, - data: *mut *const c_char) -> c_int; + data: *mut *const c_char) -> size_t; - pub fn LLVMWriteTwineToString(T: TwineRef, s: RustStringRef); + pub fn LLVMRustWriteTwineToString(T: TwineRef, s: RustStringRef); pub fn LLVMContextSetDiagnosticHandler(C: ContextRef, Handler: DiagnosticHandler, DiagnosticContext: *mut c_void); - pub fn LLVMUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, - pass_name_out: *mut *const c_char, - function_out: *mut ValueRef, - debugloc_out: *mut DebugLocRef, - message_out: *mut TwineRef); - pub fn LLVMUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, - cookie_out: *mut c_uint, - message_out: *mut TwineRef, - instruction_out: *mut ValueRef); + pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, + pass_name_out: *mut *const c_char, + function_out: *mut ValueRef, + debugloc_out: *mut DebugLocRef, + message_out: *mut TwineRef); + pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, + cookie_out: *mut c_uint, + message_out: *mut TwineRef, + instruction_out: *mut ValueRef); - pub fn LLVMWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, s: RustStringRef); + pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, + s: RustStringRef); pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity; - pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; + pub fn LLVMRustGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; - pub fn LLVMWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef); + pub fn LLVMRustWriteDebugLocToString(C: ContextRef, + DL: DebugLocRef, + s: RustStringRef); - pub fn LLVMSetInlineAsmDiagnosticHandler(C: ContextRef, - H: InlineAsmDiagHandler, - CX: *mut c_void); + pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: ContextRef, + H: InlineAsmDiagHandler, + CX: *mut c_void); - pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); + pub fn LLVMRustWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); pub fn LLVMRustWriteArchive(Dst: *const c_char, NumMembers: size_t, @@ -2237,15 +2253,15 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { unsafe { - LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, - attr.bits() as uint64_t) + LLVMRustAddFunctionAttribute(fn_, FunctionIndex as c_uint, + attr.bits() as uint64_t) } } pub fn RemoveFunctionAttributes(fn_: ValueRef, attr: Attribute) { unsafe { - LLVMRemoveFunctionAttributes(fn_, FunctionIndex as c_uint, - attr.bits() as uint64_t) + LLVMRustRemoveFunctionAttributes(fn_, FunctionIndex as c_uint, + attr.bits() as uint64_t) } } @@ -2366,12 +2382,12 @@ pub fn build_string(f: F) -> Option where F: FnOnce(RustStringRef){ } pub unsafe fn twine_to_string(tr: TwineRef) -> String { - build_string(|s| LLVMWriteTwineToString(tr, s)) + build_string(|s| LLVMRustWriteTwineToString(tr, s)) .expect("got a non-UTF8 Twine from LLVM") } pub unsafe fn debug_loc_to_string(c: ContextRef, tr: DebugLocRef) -> String { - build_string(|s| LLVMWriteDebugLocToString(c, tr, s)) + build_string(|s| LLVMRustWriteDebugLocToString(c, tr, s)) .expect("got a non-UTF8 DebugLoc from LLVM") } diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 01e9970dc76c..9c121ae9bfc6 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -80,10 +80,10 @@ pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) { unsafe { let attr = "no-frame-pointer-elim\0".as_ptr() as *const _; let val = "true\0".as_ptr() as *const _; - llvm::LLVMAddFunctionAttrStringValue(llfn, - llvm::FunctionIndex as c_uint, - attr, - val); + llvm::LLVMRustAddFunctionAttrStringValue(llfn, + llvm::FunctionIndex as c_uint, + attr, + val); } } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 0f3a45a7cff7..8ce2fa762f9e 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -365,7 +365,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, cookie: c_uint) { let HandlerFreeVars { cgcx, .. } = *(user as *const HandlerFreeVars); - let msg = llvm::build_string(|s| llvm::LLVMWriteSMDiagnosticToString(diag, s)) + let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) .expect("non-UTF8 SMDiagnostic"); report_inline_asm(cgcx, &msg[..], cookie); @@ -421,7 +421,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }; let fv = &fv as *const HandlerFreeVars as *mut c_void; - llvm::LLVMSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv); + llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv); llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv); let module_name = Some(&mtrans.name[..]); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5a19ddff7462..3e66f6de242f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2348,7 +2348,8 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { llvm::SetLinkage(val, llvm::InternalLinkage); - llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass); + llvm::SetDLLStorageClass(val, + llvm::DLLStorageClassTypes::Default); llvm::UnsetComdat(val); } } diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 7495f2b753b8..12809ab26841 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -503,8 +503,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(ptr)); let align = llalign_of_pref(self.ccx, ty.element_type()); - llvm::LLVMBuildAtomicLoad(self.llbuilder, ptr, noname(), order, - align as c_uint) + llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order, + align as c_uint) } } @@ -565,7 +565,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(ptr)); let align = llalign_of_pref(self.ccx, ty.element_type()); - llvm::LLVMBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint); + llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint); } } @@ -840,7 +840,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("Asm Output Type: {:?}", output); let fty = Type::func(&argtys[..], &output); unsafe { - let v = llvm::LLVMInlineAsm( + let v = llvm::LLVMRustInlineAsm( fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint); self.call(v, inputs, None) } @@ -1097,7 +1097,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn atomic_fence(&self, order: AtomicOrdering, scope: SynchronizationScope) { unsafe { - llvm::LLVMBuildAtomicFence(self.llbuilder, order, scope); + llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope); } } } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 27048994254c..996efc9c1132 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1126,7 +1126,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } } if ccx.use_dll_storage_attrs() { - llvm::SetDLLStorageClass(g, llvm::DLLImportStorageClass); + llvm::SetDLLStorageClass(g, llvm::DLLStorageClassTypes::DllImport); } g }; @@ -1182,7 +1182,7 @@ pub fn trans_static(ccx: &CrateContext, let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(datum.val)); let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); llvm::LLVMSetValueName(datum.val, empty_string.as_ptr()); - let new_g = llvm::LLVMGetOrInsertGlobal( + let new_g = llvm::LLVMRustGetOrInsertGlobal( ccx.llmod(), name_string.as_ptr(), val_llty.to_ref()); // To avoid breaking any invariants, we leave around the old // global for the moment; we'll replace all references to it diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 0b7540248681..fe6a48d4c559 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -133,7 +133,7 @@ fn make_mir_scope(ccx: &CrateContext, let loc = span_start(ccx, scope_data.span); scopes[scope] = unsafe { let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path); - llvm::LLVMDIBuilderCreateLexicalBlock( + llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(ccx), parent_scope, file_metadata, @@ -156,7 +156,7 @@ fn with_new_scope(cx: &CrateContext, let parent_scope = scope_stack.last().unwrap().scope_metadata; let scope_metadata = unsafe { - llvm::LLVMDIBuilderCreateLexicalBlock( + llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(cx), parent_scope, file_metadata, @@ -272,7 +272,7 @@ fn walk_pattern(cx: &CrateContext, let parent_scope = scope_stack.last().unwrap().scope_metadata; let scope_metadata = unsafe { - llvm::LLVMDIBuilderCreateLexicalBlock( + llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(cx), parent_scope, file_metadata, diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 1d718d4b57a6..8011347d3eb1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -504,12 +504,12 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; let subrange = unsafe { - llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) + llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; let subscripts = create_DIArray(DIB(cx), &[subrange]); let metadata = unsafe { - llvm::LLVMDIBuilderCreateArrayType( + llvm::LLVMRustDIBuilderCreateArrayType( DIB(cx), bytes_to_bits(array_size_in_bytes), bytes_to_bits(element_type_align), @@ -612,7 +612,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return MetadataCreationResult::new( unsafe { - llvm::LLVMDIBuilderCreateSubroutineType( + llvm::LLVMRustDIBuilderCreateSubroutineType( DIB(cx), unknown_file_metadata(cx), create_DIArray(DIB(cx), &signature_metadata[..])) @@ -885,8 +885,8 @@ fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str) let file_name = CString::new(file_name).unwrap(); let work_dir = CString::new(work_dir).unwrap(); let file_metadata = unsafe { - llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), - work_dir.as_ptr()) + llvm::LLVMRustDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), + work_dir.as_ptr()) }; let mut created_files = debug_context(cx).created_files.borrow_mut(); @@ -916,7 +916,7 @@ pub fn scope_metadata(fcx: &FunctionContext, pub fn diverging_type_metadata(cx: &CrateContext) -> DIType { unsafe { - llvm::LLVMDIBuilderCreateBasicType( + llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), "!\0".as_ptr() as *const _, bytes_to_bits(0), @@ -951,7 +951,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (size, align) = size_and_align_of(cx, llvm_type); let name = CString::new(name).unwrap(); let ty_metadata = unsafe { - llvm::LLVMDIBuilderCreateBasicType( + llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), name.as_ptr(), bytes_to_bits(size), @@ -971,7 +971,7 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let name = compute_debuginfo_type_name(cx, pointer_type, false); let name = CString::new(name).unwrap(); let ptr_metadata = unsafe { - llvm::LLVMDIBuilderCreatePointerType( + llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_metadata, bytes_to_bits(pointer_size), @@ -1017,7 +1017,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, let flags = "\0"; let split_name = "\0"; return unsafe { - llvm::LLVMDIBuilderCreateCompileUnit( + llvm::LLVMRustDIBuilderCreateCompileUnit( debug_context.builder, DW_LANG_RUST, compile_unit_name, @@ -1596,7 +1596,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let token = v.name.as_str(); let name = CString::new(token.as_bytes()).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateEnumerator( + llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), name.as_ptr(), v.disr_val.to_u64_unchecked()) @@ -1623,7 +1623,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let name = CString::new(discriminant_name.as_bytes()).unwrap(); let discriminant_type_metadata = unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( + llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, name.as_ptr(), @@ -1667,7 +1667,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let enum_name = CString::new(enum_name).unwrap(); let unique_type_id_str = CString::new(unique_type_id_str.as_bytes()).unwrap(); let enum_metadata = unsafe { - llvm::LLVMDIBuilderCreateUnionType( + llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, enum_name.as_ptr(), @@ -1769,7 +1769,7 @@ fn set_members_of_composite_type(cx: &CrateContext, let member_name = member_description.name.as_bytes(); let member_name = CString::new(member_name).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateMemberType( + llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), composite_type_metadata, member_name.as_ptr(), @@ -1786,13 +1786,14 @@ fn set_members_of_composite_type(cx: &CrateContext, unsafe { let type_array = create_DIArray(DIB(cx), &member_metadata[..]); - llvm::LLVMDICompositeTypeSetTypeArray(DIB(cx), composite_type_metadata, type_array); + llvm::LLVMRustDICompositeTypeSetTypeArray( + DIB(cx), composite_type_metadata, type_array); } } -// A convenience wrapper around LLVMDIBuilderCreateStructType(). Does not do any -// caching, does not add any fields to the struct. This can be done later with -// set_members_of_composite_type(). +// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do +// any caching, does not add any fields to the struct. This can be done later +// with set_members_of_composite_type(). fn create_struct_stub(cx: &CrateContext, struct_llvm_type: Type, struct_type_name: &str, @@ -1807,12 +1808,12 @@ fn create_struct_stub(cx: &CrateContext, let name = CString::new(struct_type_name).unwrap(); let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap(); let metadata_stub = unsafe { - // LLVMDIBuilderCreateStructType() wants an empty array. A null + // LLVMRustDIBuilderCreateStructType() wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions // later on in llvm/lib/IR/Value.cpp. let empty_array = create_DIArray(DIB(cx), &[]); - llvm::LLVMDIBuilderCreateStructType( + llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, name.as_ptr(), @@ -1868,16 +1869,16 @@ pub fn create_global_var_metadata(cx: &CrateContext, let var_name = CString::new(var_name).unwrap(); let linkage_name = CString::new(linkage_name).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name.as_ptr(), - linkage_name.as_ptr(), - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut()); + llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut()); } } @@ -1980,10 +1981,10 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, env_index); let address_operations = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref(), - llvm::LLVMDIBuilderCreateOpPlus(), + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlus(), byte_offset_of_var_in_env as i64, - llvm::LLVMDIBuilderCreateOpDeref()] + llvm::LLVMRustDIBuilderCreateOpDeref()] }; let address_op_count = if captured_by_ref { @@ -2021,7 +2022,7 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span); let aops = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref()] + [llvm::LLVMRustDIBuilderCreateOpDeref()] }; // Regardless of the actual type (`T`) we're always passed the stack slot // (alloca) for the binding. For ByRef bindings that's a `T*` but for ByMove diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 0cb52c8768b0..915999f07a1d 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -88,7 +88,7 @@ pub struct CrateDebugContext<'tcx> { impl<'tcx> CrateDebugContext<'tcx> { pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> { debug!("CrateDebugContext::new"); - let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) }; + let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) }; // DIBuilder inherits context from the module, so we'd better use the same one let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; return CrateDebugContext { @@ -178,8 +178,8 @@ pub fn finalize(cx: &CrateContext) { } unsafe { - llvm::LLVMDIBuilderFinalize(DIB(cx)); - llvm::LLVMDIBuilderDispose(DIB(cx)); + llvm::LLVMRustDIBuilderFinalize(DIB(cx)); + llvm::LLVMRustDIBuilderDispose(DIB(cx)); // Debuginfo generation in LLVM by default uses a higher // version of dwarf than OS X currently understands. We can // instruct LLVM to emit an older version of dwarf, however, @@ -250,7 +250,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let function_type_metadata = unsafe { let fn_signature = get_function_signature(cx, sig, abi); - llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) + llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) }; // Find the enclosing function, in case this is a closure. @@ -284,7 +284,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let linkage_name = CString::new(linkage_name).unwrap(); let fn_metadata = unsafe { - llvm::LLVMDIBuilderCreateFunction( + llvm::LLVMRustDIBuilderCreateFunction( DIB(cx), containing_scope, function_name.as_ptr(), @@ -388,7 +388,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); let name = CString::new(param.name.as_str().as_bytes()).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), ptr::null_mut(), name.as_ptr(), @@ -492,7 +492,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (DirectVariable { alloca }, address_operations) | (IndirectVariable {alloca, address_operations}, _) => { let metadata = unsafe { - llvm::LLVMDIBuilderCreateVariable( + llvm::LLVMRustDIBuilderCreateVariable( DIB(cx), dwarf_tag, scope_metadata, @@ -510,7 +510,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); unsafe { let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder()); - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( + let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( DIB(cx), alloca, metadata, diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 736a8c1c7d70..5953ec4aaedf 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -78,7 +78,7 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope { }; let scope = unsafe { - llvm::LLVMDIBuilderCreateNameSpace( + llvm::LLVMRustDIBuilderCreateNameSpace( DIB(ccx), parent_scope, namespace_name.as_ptr(), diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_trans/debuginfo/source_loc.rs index 9726001b4d42..d288b9dcef70 100644 --- a/src/librustc_trans/debuginfo/source_loc.rs +++ b/src/librustc_trans/debuginfo/source_loc.rs @@ -206,7 +206,7 @@ pub fn set_debug_location(cx: &CrateContext, debug!("setting debug location to {} {}", line, col); unsafe { - llvm::LLVMDIBuilderCreateDebugLocation( + llvm::LLVMRustDIBuilderCreateDebugLocation( debug_context(cx).llcontext, line as c_uint, col as c_uint, diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index facdfe73ddc8..5734a1239411 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -40,7 +40,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool #[allow(non_snake_case)] pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { return unsafe { - llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) + llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }; } diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 2746d3fb6b0b..15d90504ee7f 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -40,7 +40,7 @@ pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRe bug!("name {:?} contains an interior null byte", name) }); unsafe { - llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + llvm::LLVMRustGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) } } @@ -55,7 +55,7 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: bug!("name {:?} contains an interior null byte", name) }); let llfn = unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + llvm::LLVMRustGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) }; llvm::SetFunctionCallConv(llfn, callconv); @@ -173,7 +173,7 @@ pub fn get_declared_value(ccx: &CrateContext, name: &str) -> Option { let namebuf = CString::new(name).unwrap_or_else(|_|{ bug!("name {:?} contains an interior null byte", name) }); - let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; + let val = unsafe { llvm::LLVMRustGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; if val.is_null() { debug!("get_declared_value: {:?} value is null", name); None diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 1e4a27481827..2f27aed065d8 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -640,28 +640,30 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst (_, name) if name.starts_with("atomic_") => { + use llvm::AtomicOrdering::*; + let split: Vec<&str> = name.split('_').collect(); let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; let (order, failorder) = match split.len() { - 2 => (llvm::SequentiallyConsistent, llvm::SequentiallyConsistent), + 2 => (SequentiallyConsistent, SequentiallyConsistent), 3 => match split[2] { - "unordered" => (llvm::Unordered, llvm::Unordered), - "relaxed" => (llvm::Monotonic, llvm::Monotonic), - "acq" => (llvm::Acquire, llvm::Acquire), - "rel" => (llvm::Release, llvm::Monotonic), - "acqrel" => (llvm::AcquireRelease, llvm::Acquire), + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), "failrelaxed" if is_cxchg => - (llvm::SequentiallyConsistent, llvm::Monotonic), + (SequentiallyConsistent, Monotonic), "failacq" if is_cxchg => - (llvm::SequentiallyConsistent, llvm::Acquire), + (SequentiallyConsistent, Acquire), _ => ccx.sess().fatal("unknown ordering in atomic intrinsic") }, 4 => match (split[2], split[3]) { ("acq", "failrelaxed") if is_cxchg => - (llvm::Acquire, llvm::Monotonic), + (Acquire, Monotonic), ("acqrel", "failrelaxed") if is_cxchg => - (llvm::AcquireRelease, llvm::Monotonic), + (AcquireRelease, Monotonic), _ => ccx.sess().fatal("unknown ordering in atomic intrinsic") }, _ => ccx.sess().fatal("Atomic intrinsic not in correct format"), @@ -714,12 +716,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "fence" => { - AtomicFence(bcx, order, llvm::CrossThread); + AtomicFence(bcx, order, llvm::SynchronizationScope::CrossThread); C_nil(ccx) } "singlethreadfence" => { - AtomicFence(bcx, order, llvm::SingleThread); + AtomicFence(bcx, order, llvm::SynchronizationScope::SingleThread); C_nil(ccx) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 0221232a77df..8f723d288c9e 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -324,8 +324,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, machine::llelement_offset(bcx.ccx(), lltuplety, i); let ops = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref(), - llvm::LLVMDIBuilderCreateOpPlus(), + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlus(), byte_offset_of_var_in_tuple as i64] }; @@ -450,10 +450,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, machine::llelement_offset(bcx.ccx(), llclosurety, i); let ops = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref(), - llvm::LLVMDIBuilderCreateOpPlus(), + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlus(), byte_offset_of_var_in_env as i64, - llvm::LLVMDIBuilderCreateOpDeref()] + llvm::LLVMRustDIBuilderCreateOpDeref()] }; // The environment and the capture can each be indirect. diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 001cd197e60b..c09515a51389 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -36,7 +36,7 @@ pub struct Type { impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&llvm::build_string(|s| unsafe { - llvm::LLVMWriteTypeToString(self.to_ref(), s); + llvm::LLVMRustWriteTypeToString(self.to_ref(), s); }).expect("non-UTF8 type description from LLVM")) } } @@ -72,7 +72,7 @@ impl Type { } pub fn metadata(ccx: &CrateContext) -> Type { - ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx())) + ty!(llvm::LLVMRustMetadataTypeInContext(ccx.llcx())) } pub fn i1(ccx: &CrateContext) -> Type { diff --git a/src/librustc_trans/value.rs b/src/librustc_trans/value.rs index 00b316cc420e..79e0c11515fc 100644 --- a/src/librustc_trans/value.rs +++ b/src/librustc_trans/value.rs @@ -23,7 +23,7 @@ pub struct Value(pub ValueRef); impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&llvm::build_string(|s| unsafe { - llvm::LLVMWriteValueToString(self.0, s); + llvm::LLVMRustWriteValueToString(self.0, s); }).expect("nun-UTF8 value description from LLVM")) } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index bc38245d3512..a9c31bc33e07 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -13,6 +13,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/CallSite.h" @@ -27,6 +28,30 @@ using namespace llvm; using namespace llvm::sys; using namespace llvm::object; +// LLVMAtomicOrdering is already an enum - don't create another +// one. +static AtomicOrdering from_rust(LLVMAtomicOrdering Ordering) { + switch (Ordering) { + case LLVMAtomicOrderingNotAtomic: + return AtomicOrdering::NotAtomic; + case LLVMAtomicOrderingUnordered: + return AtomicOrdering::Unordered; + case LLVMAtomicOrderingMonotonic: + return AtomicOrdering::Monotonic; + case LLVMAtomicOrderingAcquire: + return AtomicOrdering::Acquire; + case LLVMAtomicOrderingRelease: + return AtomicOrdering::Release; + case LLVMAtomicOrderingAcquireRelease: + return AtomicOrdering::AcquireRelease; + case LLVMAtomicOrderingSequentiallyConsistent: + return AtomicOrdering::SequentiallyConsistent; + } + + llvm_unreachable("Invalid LLVMAtomicOrdering value!"); +} + + static char *LastError; extern "C" LLVMMemoryBufferRef @@ -57,45 +82,30 @@ LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) { unwrap(M)->setTargetTriple(Triple::normalize(triple)); } -extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N, - LLVMBool SignExtend) { - return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend); -} - -extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy, - unsigned N_hi, - unsigned N_lo, - LLVMBool SignExtend) { - unsigned long long N = N_hi; - N <<= 32; - N |= N_lo; - return LLVMConstInt(IntTy, N, SignExtend); -} - extern "C" void LLVMRustPrintPassTimings() { raw_fd_ostream OS (2, false); // stderr. TimerGroup::printAll(OS); } -extern "C" LLVMValueRef LLVMGetNamedValue(LLVMModuleRef M, - const char* Name) { +extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, + const char* Name) { return wrap(unwrap(M)->getNamedValue(Name)); } -extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, - const char* Name, - LLVMTypeRef FunctionTy) { +extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, + const char* Name, + LLVMTypeRef FunctionTy) { return wrap(unwrap(M)->getOrInsertFunction(Name, unwrap(FunctionTy))); } -extern "C" LLVMValueRef LLVMGetOrInsertGlobal(LLVMModuleRef M, - const char* Name, - LLVMTypeRef Ty) { +extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, + const char* Name, + LLVMTypeRef Ty) { return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); } -extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { +extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } @@ -110,7 +120,10 @@ extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, } -extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) { +extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, + unsigned idx, + uint64_t b) +{ CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addDereferenceableAttr(b); @@ -120,38 +133,50 @@ extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, B))); } -extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, - uint64_t Val) { +extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, + unsigned index, + uint64_t Val) +{ Function *A = unwrap(Fn); AttrBuilder B; B.addRawValue(Val); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } -extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef Fn, unsigned index, uint64_t bytes) { +extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, + unsigned index, + uint64_t bytes) +{ Function *A = unwrap(Fn); AttrBuilder B; B.addDereferenceableAttr(bytes); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } -extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) { +extern "C" void LLVMRustAddFunctionAttrString(LLVMValueRef Fn, + unsigned index, + const char *Name) +{ Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } -extern "C" void LLVMAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, - const char *Name, - const char *Value) { +extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, + unsigned index, + const char *Name, + const char *Value) { Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name, Value); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } -extern "C" void LLVMRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, uint64_t Val) { +extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, + unsigned index, + uint64_t Val) +{ Function *A = unwrap(Fn); const AttributeSet PAL = A->getAttributes(); AttrBuilder B(Val); @@ -161,7 +186,10 @@ extern "C" void LLVMRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, ui A->setAttributes(PALnew); } -extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { +extern "C" void LLVMRustRemoveFunctionAttrString(LLVMValueRef fn, + unsigned index, + const char *Name) +{ Function *f = unwrap(fn); LLVMContext &C = f->getContext(); AttrBuilder B; @@ -181,24 +209,24 @@ extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) { } } -extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, - LLVMValueRef source, - const char* Name, - AtomicOrdering order, - unsigned alignment) { +extern "C" LLVMValueRef LLVMRustBuildAtomicLoad(LLVMBuilderRef B, + LLVMValueRef source, + const char* Name, + LLVMAtomicOrdering order, + unsigned alignment) { LoadInst* li = new LoadInst(unwrap(source),0); - li->setAtomic(order); + li->setAtomic(from_rust(order)); li->setAlignment(alignment); return wrap(unwrap(B)->Insert(li, Name)); } -extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, - LLVMValueRef val, - LLVMValueRef target, - AtomicOrdering order, - unsigned alignment) { +extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B, + LLVMValueRef val, + LLVMValueRef target, + LLVMAtomicOrdering order, + unsigned alignment) { StoreInst* si = new StoreInst(unwrap(val),unwrap(target)); - si->setAtomic(order); + si->setAtomic(from_rust(order)); si->setAlignment(alignment); return wrap(unwrap(B)->Insert(si)); } @@ -207,54 +235,77 @@ extern "C" LLVMValueRef LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef target, LLVMValueRef old, LLVMValueRef source, - AtomicOrdering order, - AtomicOrdering failure_order, + LLVMAtomicOrdering order, + LLVMAtomicOrdering failure_order, LLVMBool weak) { - AtomicCmpXchgInst* acxi = unwrap(B)->CreateAtomicCmpXchg(unwrap(target), - unwrap(old), - unwrap(source), - order, - failure_order); + AtomicCmpXchgInst* acxi = unwrap(B)->CreateAtomicCmpXchg( + unwrap(target), + unwrap(old), + unwrap(source), + from_rust(order), + from_rust(failure_order)); acxi->setWeak(weak); return wrap(acxi); } -extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, - AtomicOrdering order, - SynchronizationScope scope) { - return wrap(unwrap(B)->CreateFence(order, scope)); + +enum class LLVMRustSynchronizationScope { + Other, + SingleThread, + CrossThread, +}; + +static SynchronizationScope +from_rust(LLVMRustSynchronizationScope scope) +{ + switch (scope) { + case LLVMRustSynchronizationScope::SingleThread: + return SingleThread; + case LLVMRustSynchronizationScope::CrossThread: + return CrossThread; + default: + abort(); + } } -extern "C" void LLVMSetDebug(int Enabled) { +extern "C" LLVMValueRef LLVMRustBuildAtomicFence( + LLVMBuilderRef B, + LLVMAtomicOrdering order, + LLVMRustSynchronizationScope scope) +{ + return wrap(unwrap(B)->CreateFence(from_rust(order), from_rust(scope))); +} + +extern "C" void LLVMRustSetDebug(int Enabled) { #ifndef NDEBUG DebugFlag = Enabled; #endif } -extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty, - char *AsmString, - char *Constraints, - LLVMBool HasSideEffects, - LLVMBool IsAlignStack, - unsigned Dialect) { +extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, + char *AsmString, + char *Constraints, + LLVMBool HasSideEffects, + LLVMBool IsAlignStack, + unsigned Dialect) { return wrap(InlineAsm::get(unwrap(Ty), AsmString, Constraints, HasSideEffects, IsAlignStack, (InlineAsm::AsmDialect) Dialect)); } -typedef DIBuilder* DIBuilderRef; +typedef DIBuilder* LLVMRustDIBuilderRef; -typedef struct LLVMOpaqueMetadata *LLVMMetadataRef; +typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; namespace llvm { -DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMMetadataRef) +DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMRustMetadataRef) -inline Metadata **unwrap(LLVMMetadataRef *Vals) { +inline Metadata **unwrap(LLVMRustMetadataRef *Vals) { return reinterpret_cast(Vals); } } template -DIT* unwrapDIptr(LLVMMetadataRef ref) { +DIT* unwrapDIptr(LLVMRustMetadataRef ref) { return (DIT*) (ref ? unwrap(ref) : NULL); } @@ -266,11 +317,11 @@ extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } -extern "C" uint32_t LLVMVersionMinor() { +extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } -extern "C" uint32_t LLVMVersionMajor() { +extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } @@ -280,20 +331,20 @@ extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, unwrap(M)->addModuleFlag(Module::Warning, name, value); } -extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) { +extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { return new DIBuilder(*unwrap(M)); } -extern "C" void LLVMDIBuilderDispose(DIBuilderRef Builder) { +extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) { delete Builder; } -extern "C" void LLVMDIBuilderFinalize(DIBuilderRef Builder) { +extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { Builder->finalize(); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateCompileUnit( + LLVMRustDIBuilderRef Builder, unsigned Lang, const char* File, const char* Dir, @@ -312,17 +363,17 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( SplitName)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateFile( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFile( + LLVMRustDIBuilderRef Builder, const char* Filename, const char* Directory) { return wrap(Builder->createFile(Filename, Directory)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( - DIBuilderRef Builder, - LLVMMetadataRef File, - LLVMMetadataRef ParameterTypes) { +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateSubroutineType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef File, + LLVMRustMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( #if LLVM_VERSION_MINOR == 7 unwrapDI(File), @@ -330,22 +381,22 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( DITypeRefArray(unwrap(ParameterTypes)))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, const char* LinkageName, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, + LLVMRustMetadataRef Ty, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, LLVMValueRef Fn, - LLVMMetadataRef TParam, - LLVMMetadataRef Decl) { + LLVMRustMetadataRef TParam, + LLVMRustMetadataRef Decl) { #if LLVM_VERSION_MINOR >= 8 DITemplateParameterArray TParams = DITemplateParameterArray(unwrap(TParam)); @@ -370,8 +421,8 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( #endif } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateBasicType( + LLVMRustDIBuilderRef Builder, const char* Name, uint64_t SizeInBits, uint64_t AlignInBits, @@ -381,9 +432,9 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( AlignInBits, Encoding)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreatePointerType( - DIBuilderRef Builder, - LLVMMetadataRef PointeeTy, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef PointeeTy, uint64_t SizeInBits, uint64_t AlignInBits, const char* Name) { @@ -391,19 +442,19 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreatePointerType( unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, - LLVMMetadataRef DerivedFrom, - LLVMMetadataRef Elements, + LLVMRustMetadataRef DerivedFrom, + LLVMRustMetadataRef Elements, unsigned RunTimeLang, - LLVMMetadataRef VTableHolder, + LLVMRustMetadataRef VTableHolder, const char *UniqueId) { return wrap(Builder->createStructType( unwrapDI(Scope), @@ -421,17 +472,17 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType( )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateMemberType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateMemberType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, - LLVMMetadataRef Ty) { + LLVMRustMetadataRef Ty) { return wrap(Builder->createMemberType( unwrapDI(Scope), Name, unwrapDI(File), LineNo, @@ -439,10 +490,10 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateMemberType( unwrapDI(Ty))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( - DIBuilderRef Builder, - LLVMMetadataRef Scope, - LLVMMetadataRef File, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, + LLVMRustMetadataRef File, unsigned Line, unsigned Col) { return wrap(Builder->createLexicalBlock( @@ -451,17 +502,17 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable( - DIBuilderRef Builder, - LLVMMetadataRef Context, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Context, const char* Name, const char* LinkageName, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, + LLVMRustMetadataRef Ty, bool isLocalToUnit, LLVMValueRef Val, - LLVMMetadataRef Decl = NULL) { + LLVMRustMetadataRef Decl = NULL) { return wrap(Builder->createGlobalVariable(unwrapDI(Context), Name, LinkageName, @@ -473,14 +524,14 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable( unwrapDIptr(Decl))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( + LLVMRustDIBuilderRef Builder, unsigned Tag, - LLVMMetadataRef Scope, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, + LLVMRustMetadataRef Ty, bool AlwaysPreserve, unsigned Flags, int64_t* AddrOps, @@ -509,50 +560,50 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( #endif } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateArrayType( + LLVMRustDIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, - LLVMMetadataRef Ty, - LLVMMetadataRef Subscripts) { + LLVMRustMetadataRef Ty, + LLVMRustMetadataRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, unwrapDI(Ty), DINodeArray(unwrapDI(Subscripts)) )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVectorType( + LLVMRustDIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, - LLVMMetadataRef Ty, - LLVMMetadataRef Subscripts) { + LLVMRustMetadataRef Ty, + LLVMRustMetadataRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, unwrapDI(Ty), DINodeArray(unwrapDI(Subscripts)) )); } -extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderGetOrCreateSubrange( + LLVMRustDIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(Builder->getOrCreateSubrange(Lo, Count)); } -extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateArray( - DIBuilderRef Builder, - LLVMMetadataRef* Ptr, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderGetOrCreateArray( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef* Ptr, unsigned Count) { Metadata **DataValue = unwrap(Ptr); return wrap(Builder->getOrCreateArray( ArrayRef(DataValue, Count)).get()); } -extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( - DIBuilderRef Builder, +extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( + LLVMRustDIBuilderRef Builder, LLVMValueRef Val, - LLVMMetadataRef VarInfo, + LLVMRustMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, @@ -566,10 +617,10 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( unwrap(InsertAtEnd))); } -extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( - DIBuilderRef Builder, +extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareBefore( + LLVMRustDIBuilderRef Builder, LLVMValueRef Val, - LLVMMetadataRef VarInfo, + LLVMRustMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, @@ -583,24 +634,24 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( unwrap(InsertBefore))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerator( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerator( + LLVMRustDIBuilderRef Builder, const char* Name, uint64_t Val) { return wrap(Builder->createEnumerator(Name, Val)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, - LLVMMetadataRef Elements, - LLVMMetadataRef ClassType) + LLVMRustMetadataRef Elements, + LLVMRustMetadataRef ClassType) { return wrap(Builder->createEnumerationType( unwrapDI(Scope), @@ -613,16 +664,16 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( unwrapDI(ClassType))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, - LLVMMetadataRef Elements, + LLVMRustMetadataRef Elements, unsigned RunTimeLang, const char* UniqueId) { @@ -640,12 +691,12 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType( )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef Ty, - LLVMMetadataRef File, + LLVMRustMetadataRef Ty, + LLVMRustMetadataRef File, unsigned LineNo, unsigned ColumnNo) { @@ -656,21 +707,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter( )); } -extern "C" int64_t LLVMDIBuilderCreateOpDeref() -{ - return dwarf::DW_OP_deref; -} - -extern "C" int64_t LLVMDIBuilderCreateOpPlus() -{ - return dwarf::DW_OP_plus; -} - -extern "C" LLVMMetadataRef LLVMDIBuilderCreateNameSpace( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateNameSpace( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo) { return wrap(Builder->createNameSpace( @@ -680,22 +721,22 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateNameSpace( LineNo)); } -extern "C" void LLVMDICompositeTypeSetTypeArray( - DIBuilderRef Builder, - LLVMMetadataRef CompositeType, - LLVMMetadataRef TypeArray) +extern "C" void LLVMRustDICompositeTypeSetTypeArray( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef CompositeType, + LLVMRustMetadataRef TypeArray) { DICompositeType *tmp = unwrapDI(CompositeType); Builder->replaceArrays(tmp, DINodeArray(unwrap(TypeArray))); } -extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation( +extern "C" LLVMValueRef LLVMRustDIBuilderCreateDebugLocation( LLVMContextRef Context, unsigned Line, unsigned Column, - LLVMMetadataRef Scope, - LLVMMetadataRef InlinedAt) { - + LLVMRustMetadataRef Scope, + LLVMRustMetadataRef InlinedAt) +{ LLVMContext& context = *unwrap(Context); DebugLoc debug_loc = DebugLoc::get(Line, @@ -706,12 +747,22 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation( return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode())); } -extern "C" void LLVMWriteTypeToString(LLVMTypeRef Type, RustStringRef str) { +extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() +{ + return dwarf::DW_OP_deref; +} + +extern "C" int64_t LLVMRustDIBuilderCreateOpPlus() +{ + return dwarf::DW_OP_plus; +} + +extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Type, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(Type)->print(os); } -extern "C" void LLVMWriteValueToString(LLVMValueRef Value, RustStringRef str) { +extern "C" void LLVMRustWriteValueToString(LLVMValueRef Value, RustStringRef str) { raw_rust_string_ostream os(str); os << "("; unwrap(Value)->getType()->print(os); @@ -746,11 +797,33 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { return true; } +enum class LLVMRustDLLStorageClassTypes { + Other, + Default, + DllImport, + DllExport, +}; + +static GlobalValue::DLLStorageClassTypes +from_rust(LLVMRustDLLStorageClassTypes Class) +{ + switch (Class) { + case LLVMRustDLLStorageClassTypes::Default: + return GlobalValue::DefaultStorageClass; + case LLVMRustDLLStorageClassTypes::DllImport: + return GlobalValue::DLLImportStorageClass; + case LLVMRustDLLStorageClassTypes::DllExport: + return GlobalValue::DLLExportStorageClass; + default: + abort(); + } +} + extern "C" void LLVMRustSetDLLStorageClass(LLVMValueRef Value, - GlobalValue::DLLStorageClassTypes Class) { + LLVMRustDLLStorageClassTypes Class) { GlobalValue *V = unwrap(Value); - V->setDLLStorageClass(Class); + V->setDLLStorageClass(from_rust(Class)); } // Note that the two following functions look quite similar to the @@ -768,7 +841,7 @@ inline section_iterator *unwrap(LLVMSectionIteratorRef SI) { return reinterpret_cast(SI); } -extern "C" int +extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) { StringRef ret; if (std::error_code ec = (*unwrap(SI))->getName(ret)) @@ -787,13 +860,13 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DebugLoc, LLVMDebugLocRef) extern "C" void -LLVMWriteTwineToString(LLVMTwineRef T, RustStringRef str) { +LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(T)->print(os); } extern "C" void -LLVMUnpackOptimizationDiagnostic( +LLVMRustUnpackOptimizationDiagnostic( LLVMDiagnosticInfoRef di, const char **pass_name_out, LLVMValueRef *function_out, @@ -811,7 +884,7 @@ LLVMUnpackOptimizationDiagnostic( } extern "C" void -LLVMUnpackInlineAsmDiagnostic( +LLVMRustUnpackInlineAsmDiagnostic( LLVMDiagnosticInfoRef di, unsigned *cookie_out, LLVMTwineRef *message_out, @@ -826,17 +899,68 @@ LLVMUnpackInlineAsmDiagnostic( *instruction_out = wrap(ia->getInstruction()); } -extern "C" void LLVMWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) { +extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) { raw_rust_string_ostream os(str); DiagnosticPrinterRawOStream dp(os); unwrap(di)->print(dp); } -extern "C" int LLVMGetDiagInfoKind(LLVMDiagnosticInfoRef di) { - return unwrap(di)->getKind(); +enum class LLVMRustDiagnosticKind { + Other, + InlineAsm, + StackSize, + DebugMetadataVersion, + SampleProfile, + OptimizationRemark, + OptimizationRemarkMissed, + OptimizationRemarkAnalysis, + OptimizationRemarkAnalysisFPCommute, + OptimizationRemarkAnalysisAliasing, + OptimizationRemarkOther, + OptimizationFailure, +}; + +static LLVMRustDiagnosticKind +to_rust(DiagnosticKind kind) +{ + switch (kind) { + case DK_InlineAsm: + return LLVMRustDiagnosticKind::InlineAsm; + case DK_StackSize: + return LLVMRustDiagnosticKind::StackSize; + case DK_DebugMetadataVersion: + return LLVMRustDiagnosticKind::DebugMetadataVersion; + case DK_SampleProfile: + return LLVMRustDiagnosticKind::SampleProfile; + case DK_OptimizationRemark: + return LLVMRustDiagnosticKind::OptimizationRemark; + case DK_OptimizationRemarkMissed: + return LLVMRustDiagnosticKind::OptimizationRemarkMissed; + case DK_OptimizationRemarkAnalysis: + return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis; +#if LLVM_VERSION_MINOR >= 8 + case DK_OptimizationRemarkAnalysisFPCommute: + return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute; + case DK_OptimizationRemarkAnalysisAliasing: + return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing; +#endif + default: +#if LLVM_VERSION_MINOR >= 9 + return (kind >= DK_FirstRemark && kind <= DK_LastRemark) ? + LLVMRustDiagnosticKind::OptimizationRemarkOther : + LLVMRustDiagnosticKind::Other; +#else + return LLVMRustDiagnosticKind::Other; +#endif + } } -extern "C" void LLVMWriteDebugLocToString( + +extern "C" LLVMRustDiagnosticKind LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef di) { + return to_rust((DiagnosticKind) unwrap(di)->getKind()); +} + +extern "C" void LLVMRustWriteDebugLocToString( LLVMContextRef C, LLVMDebugLocRef dl, RustStringRef str) @@ -847,7 +971,8 @@ extern "C" void LLVMWriteDebugLocToString( DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) -extern "C" void LLVMSetInlineAsmDiagnosticHandler( +// FIXME(type-audit): assume this function-pointer type does not change +extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( LLVMContextRef C, LLVMContext::InlineAsmDiagHandlerTy H, void *CX) @@ -855,7 +980,8 @@ extern "C" void LLVMSetInlineAsmDiagnosticHandler( unwrap(C)->setInlineAsmDiagnosticHandler(H, CX); } -extern "C" void LLVMWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, RustStringRef str) { +extern "C" void LLVMRustWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, + RustStringRef str) { raw_rust_string_ostream os(str); unwrap(d)->print("", os); } @@ -902,6 +1028,8 @@ LLVMRustBuildCleanupRet(LLVMBuilderRef Builder, #endif } +// FIXME: to here. + extern "C" LLVMValueRef LLVMRustBuildCatchPad(LLVMBuilderRef Builder, LLVMValueRef ParentPad, From 24874170b4dfc93243b18815b6d896e87f7ddafe Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 2 Aug 2016 23:10:10 +0300 Subject: [PATCH 294/331] split the FFI part of rustc_llvm to rustc_llvm::ffi --- src/librustc_llvm/diagnostic.rs | 3 +- src/librustc_llvm/ffi.rs | 2063 ++++++++++++++++++++++++++++++ src/librustc_llvm/lib.rs | 2086 +------------------------------ src/librustc_trans/build.rs | 4 +- src/librustc_trans/builder.rs | 4 +- 5 files changed, 2090 insertions(+), 2070 deletions(-) create mode 100644 src/librustc_llvm/ffi.rs diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index 4938a0216ee4..8520ae1df60d 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -16,7 +16,8 @@ pub use self::Diagnostic::*; use libc::{c_char, c_uint}; use std::ptr; -use {DebugLocRef, DiagnosticInfoRef, TwineRef, ValueRef}; +use {DiagnosticInfoRef, TwineRef, ValueRef}; +use ffi::DebugLocRef; #[derive(Copy, Clone)] pub enum OptimizationDiagnosticKind { diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs new file mode 100644 index 000000000000..53a287ea8ec0 --- /dev/null +++ b/src/librustc_llvm/ffi.rs @@ -0,0 +1,2063 @@ +// 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. + +use debuginfo::{DIBuilderRef, DIDescriptor, + DIFile, DILexicalBlock, DISubprogram, DIType, + DIBasicType, DIDerivedType, DICompositeType, DIScope, + DIVariable, DIGlobalVariable, DIArray, DISubrange, + DITemplateTypeParameter, DIEnumerator, DINameSpace}; +use RustStringRef; + +use libc::{c_uint, c_ushort, c_int, size_t, c_char}; +use libc::{c_longlong, c_ulonglong, c_void}; + +pub type Opcode = u32; +pub type Bool = c_uint; + +pub const True: Bool = 1 as Bool; +pub const False: Bool = 0 as Bool; + +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +pub enum LLVMRustResult { + Success, + Failure, +} +// Consts for the LLVM CallConv type, pre-cast to usize. + +/// LLVM CallingConv::ID. Should we wrap this? +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum CallConv { + CCallConv = 0, + FastCallConv = 8, + ColdCallConv = 9, + X86StdcallCallConv = 64, + X86FastcallCallConv = 65, + X86_64_Win64 = 79, + X86_VectorCall = 80 +} + +/// LLVMLinkage +/// +/// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage, +/// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. +/// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; +/// they've been removed in upstream LLVM commit r203866. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[repr(C)] +pub enum Linkage { + ExternalLinkage = 0, + AvailableExternallyLinkage = 1, + LinkOnceAnyLinkage = 2, + LinkOnceODRLinkage = 3, + WeakAnyLinkage = 5, + WeakODRLinkage = 6, + AppendingLinkage = 7, + InternalLinkage = 8, + PrivateLinkage = 9, + ExternalWeakLinkage = 12, + CommonLinkage = 14, +} + +/// LLVMDiagnosticSeverity +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub enum DiagnosticSeverity { + Error = 0, + Warning = 1, + Remark = 2, + Note = 3, +} + +/// LLVMRustDLLStorageClassTypes +#[repr(C)] +#[derive(Copy, Clone)] +pub enum DLLStorageClassTypes { + Other, + Default, + DllImport, + DllExport, +} + +bitflags! { + #[derive(Default, Debug)] + flags Attribute : u64 { + const ZExt = 1 << 0, + const SExt = 1 << 1, + const NoReturn = 1 << 2, + const InReg = 1 << 3, + const StructRet = 1 << 4, + const NoUnwind = 1 << 5, + const NoAlias = 1 << 6, + const ByVal = 1 << 7, + const Nest = 1 << 8, + const ReadNone = 1 << 9, + const ReadOnly = 1 << 10, + const NoInline = 1 << 11, + const AlwaysInline = 1 << 12, + const OptimizeForSize = 1 << 13, + const StackProtect = 1 << 14, + const StackProtectReq = 1 << 15, + const NoCapture = 1 << 21, + const NoRedZone = 1 << 22, + const NoImplicitFloat = 1 << 23, + const Naked = 1 << 24, + const InlineHint = 1 << 25, + const ReturnsTwice = 1 << 29, + const UWTable = 1 << 30, + const NonLazyBind = 1 << 31, + + // Some of these are missing from the LLVM C API, the rest are + // present, but commented out, and preceded by the following warning: + // FIXME: These attributes are currently not included in the C API as + // a temporary measure until the API/ABI impact to the C API is understood + // and the path forward agreed upon. + const SanitizeAddress = 1 << 32, + const MinSize = 1 << 33, + const NoDuplicate = 1 << 34, + const StackProtectStrong = 1 << 35, + const SanitizeThread = 1 << 36, + const SanitizeMemory = 1 << 37, + const NoBuiltin = 1 << 38, + const Returned = 1 << 39, + const Cold = 1 << 40, + const Builtin = 1 << 41, + const OptimizeNone = 1 << 42, + const InAlloca = 1 << 43, + const NonNull = 1 << 44, + const JumpTable = 1 << 45, + const Convergent = 1 << 46, + const SafeStack = 1 << 47, + const NoRecurse = 1 << 48, + const InaccessibleMemOnly = 1 << 49, + const InaccessibleMemOrArgMemOnly = 1 << 50, + } +} + +/// LLVMIntPredicate +#[derive(Copy, Clone)] +pub enum IntPredicate { + IntEQ = 32, + IntNE = 33, + IntUGT = 34, + IntUGE = 35, + IntULT = 36, + IntULE = 37, + IntSGT = 38, + IntSGE = 39, + IntSLT = 40, + IntSLE = 41, +} + +/// LLVMRealPredicate +#[derive(Copy, Clone)] +pub enum RealPredicate { + RealPredicateFalse = 0, + RealOEQ = 1, + RealOGT = 2, + RealOGE = 3, + RealOLT = 4, + RealOLE = 5, + RealONE = 6, + RealORD = 7, + RealUNO = 8, + RealUEQ = 9, + RealUGT = 10, + RealUGE = 11, + RealULT = 12, + RealULE = 13, + RealUNE = 14, + RealPredicateTrue = 15, +} + +/// LLVMTypeKind; FIXME: wrap +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +pub enum TypeKind { + Void = 0, + Half = 1, + Float = 2, + Double = 3, + X86_FP80 = 4, + FP128 = 5, + PPC_FP128 = 6, + Label = 7, + Integer = 8, + Function = 9, + Struct = 10, + Array = 11, + Pointer = 12, + Vector = 13, + Metadata = 14, + X86_MMX = 15, +} + +/// LLVMAtomicRmwBinOp +#[repr(C)] +#[derive(Copy, Clone)] +pub enum AtomicRmwBinOp { + AtomicXchg = 0, + AtomicAdd = 1, + AtomicSub = 2, + AtomicAnd = 3, + AtomicNand = 4, + AtomicOr = 5, + AtomicXor = 6, + AtomicMax = 7, + AtomicMin = 8, + AtomicUMax = 9, + AtomicUMin = 10, +} + +/// LLVMAtomicOrdering +#[repr(C)] +#[derive(Copy, Clone)] +pub enum AtomicOrdering { + NotAtomic = 0, + Unordered = 1, + Monotonic = 2, + // Consume = 3, // Not specified yet. + Acquire = 4, + Release = 5, + AcquireRelease = 6, + SequentiallyConsistent = 7 +} + +/// LLVMRustSynchronizationScope +#[repr(C)] +#[derive(Copy, Clone)] +pub enum SynchronizationScope { + Other, + SingleThread, + CrossThread, +} + +/// LLVMRustFileType +#[repr(C)] +#[derive(Copy, Clone)] +pub enum FileType { + Other, + AssemblyFile, + ObjectFile, +} + +/// FIXME: ? +#[derive(Copy, Clone)] +pub enum MetadataType { + MD_dbg = 0, + MD_tbaa = 1, + MD_prof = 2, + MD_fpmath = 3, + MD_range = 4, + MD_tbaa_struct = 5, + MD_invariant_load = 6, + MD_alias_scope = 7, + MD_noalias = 8, + MD_nontemporal = 9, + MD_mem_parallel_loop_access = 10, + MD_nonnull = 11, +} + +/// FIXME: ? +#[derive(Copy, Clone)] +pub enum AsmDialect { + AD_ATT = 0, + AD_Intel = 1 +} + +/// LLVMRustCodeGenOptLevel +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum CodeGenOptLevel { + Other, + None, + Less, + Default, + Aggressive, +} + +/// LLVMRelocMode +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum RelocMode { + Default = 0, + Static = 1, + PIC = 2, + DynamicNoPic = 3, +} + +/// LLVMRustCodeModel +#[repr(C)] +#[derive(Copy, Clone)] +pub enum CodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, +} + +/// LLVMRustDiagnosticKind +#[repr(C)] +#[derive(Copy, Clone)] +pub enum DiagnosticKind { + Other, + InlineAsm, + StackSize, + DebugMetadataVersion, + SampleProfile, + OptimizationRemark, + OptimizationRemarkMissed, + OptimizationRemarkAnalysis, + OptimizationRemarkAnalysisFPCommute, + OptimizationRemarkAnalysisAliasing, + OptimizationRemarkOther, + OptimizationFailure, +} + +/// LLVMRustArchiveKind +#[repr(C)] +#[derive(Copy, Clone)] +pub enum ArchiveKind { + Other, + K_GNU, + K_MIPS64, + K_BSD, + K_COFF, +} +/// LLVMRustPassKind +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +pub enum PassKind { + Other, + Function, + Module, +} + +// Opaque pointer types +#[allow(missing_copy_implementations)] +pub enum Module_opaque {} +pub type ModuleRef = *mut Module_opaque; +#[allow(missing_copy_implementations)] +pub enum Context_opaque {} +pub type ContextRef = *mut Context_opaque; +#[allow(missing_copy_implementations)] +pub enum Type_opaque {} +pub type TypeRef = *mut Type_opaque; +#[allow(missing_copy_implementations)] +pub enum Value_opaque {} +pub type ValueRef = *mut Value_opaque; +#[allow(missing_copy_implementations)] +pub enum Metadata_opaque {} +pub type MetadataRef = *mut Metadata_opaque; +#[allow(missing_copy_implementations)] +pub enum BasicBlock_opaque {} +pub type BasicBlockRef = *mut BasicBlock_opaque; +#[allow(missing_copy_implementations)] +pub enum Builder_opaque {} +pub type BuilderRef = *mut Builder_opaque; +#[allow(missing_copy_implementations)] +pub enum ExecutionEngine_opaque {} +pub type ExecutionEngineRef = *mut ExecutionEngine_opaque; +#[allow(missing_copy_implementations)] +pub enum MemoryBuffer_opaque {} +pub type MemoryBufferRef = *mut MemoryBuffer_opaque; +#[allow(missing_copy_implementations)] +pub enum PassManager_opaque {} +pub type PassManagerRef = *mut PassManager_opaque; +#[allow(missing_copy_implementations)] +pub enum PassManagerBuilder_opaque {} +pub type PassManagerBuilderRef = *mut PassManagerBuilder_opaque; +#[allow(missing_copy_implementations)] +pub enum Use_opaque {} +pub type UseRef = *mut Use_opaque; +#[allow(missing_copy_implementations)] +pub enum TargetData_opaque {} +pub type TargetDataRef = *mut TargetData_opaque; +#[allow(missing_copy_implementations)] +pub enum ObjectFile_opaque {} +pub type ObjectFileRef = *mut ObjectFile_opaque; +#[allow(missing_copy_implementations)] +pub enum SectionIterator_opaque {} +pub type SectionIteratorRef = *mut SectionIterator_opaque; +#[allow(missing_copy_implementations)] +pub enum Pass_opaque {} +pub type PassRef = *mut Pass_opaque; +#[allow(missing_copy_implementations)] +pub enum TargetMachine_opaque {} +pub type TargetMachineRef = *mut TargetMachine_opaque; +pub enum Archive_opaque {} +pub type ArchiveRef = *mut Archive_opaque; +pub enum ArchiveIterator_opaque {} +pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque; +pub enum ArchiveChild_opaque {} +pub type ArchiveChildRef = *mut ArchiveChild_opaque; +#[allow(missing_copy_implementations)] +pub enum Twine_opaque {} +pub type TwineRef = *mut Twine_opaque; +#[allow(missing_copy_implementations)] +pub enum DiagnosticInfo_opaque {} +pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque; +#[allow(missing_copy_implementations)] +pub enum DebugLoc_opaque {} +pub type DebugLocRef = *mut DebugLoc_opaque; +#[allow(missing_copy_implementations)] +pub enum SMDiagnostic_opaque {} +pub type SMDiagnosticRef = *mut SMDiagnostic_opaque; +#[allow(missing_copy_implementations)] +pub enum RustArchiveMember_opaque {} +pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; +#[allow(missing_copy_implementations)] +pub enum OperandBundleDef_opaque {} +pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; + +pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); +pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); + +pub mod debuginfo { + pub use self::DIDescriptorFlags::*; + use super::{MetadataRef}; + + #[allow(missing_copy_implementations)] + pub enum DIBuilder_opaque {} + pub type DIBuilderRef = *mut DIBuilder_opaque; + + pub type DIDescriptor = MetadataRef; + pub type DIScope = DIDescriptor; + pub type DILocation = DIDescriptor; + pub type DIFile = DIScope; + pub type DILexicalBlock = DIScope; + pub type DISubprogram = DIScope; + pub type DINameSpace = DIScope; + pub type DIType = DIDescriptor; + pub type DIBasicType = DIType; + pub type DIDerivedType = DIType; + pub type DICompositeType = DIDerivedType; + pub type DIVariable = DIDescriptor; + pub type DIGlobalVariable = DIDescriptor; + pub type DIArray = DIDescriptor; + pub type DISubrange = DIDescriptor; + pub type DIEnumerator = DIDescriptor; + pub type DITemplateTypeParameter = DIDescriptor; + + #[derive(Copy, Clone)] + pub enum DIDescriptorFlags { + FlagPrivate = 1 << 0, + FlagProtected = 1 << 1, + FlagFwdDecl = 1 << 2, + FlagAppleBlock = 1 << 3, + FlagBlockByrefStruct = 1 << 4, + FlagVirtual = 1 << 5, + FlagArtificial = 1 << 6, + FlagExplicit = 1 << 7, + FlagPrototyped = 1 << 8, + FlagObjcClassComplete = 1 << 9, + FlagObjectPointer = 1 << 10, + FlagVector = 1 << 11, + FlagStaticMember = 1 << 12, + FlagIndirectVariable = 1 << 13, + FlagLValueReference = 1 << 14, + FlagRValueReference = 1 << 15 + } +} + + +// Link to our native llvm bindings (things that we need to use the C++ api +// for) and because llvm is written in C++ we need to link against libstdc++ +// +// You'll probably notice that there is an omission of all LLVM libraries +// from this location. This is because the set of LLVM libraries that we +// link to is mostly defined by LLVM, and the `llvm-config` tool is used to +// figure out the exact set of libraries. To do this, the build system +// generates an llvmdeps.rs file next to this one which will be +// automatically updated whenever LLVM is updated to include an up-to-date +// set of the libraries we need to link to LLVM for. +#[link(name = "rustllvm", kind = "static")] +#[cfg(not(cargobuild))] +extern {} + +#[linked_from = "rustllvm"] // not quite true but good enough +extern { + /* Create and destroy contexts. */ + pub fn LLVMContextCreate() -> ContextRef; + pub fn LLVMContextDispose(C: ContextRef); + pub fn LLVMGetMDKindIDInContext(C: ContextRef, + Name: *const c_char, + SLen: c_uint) + -> c_uint; + + /* Create and destroy modules. */ + pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, + C: ContextRef) + -> ModuleRef; + pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef; + pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef; + pub fn LLVMDisposeModule(M: ModuleRef); + + /// Data layout. See Module::getDataLayout. + pub fn LLVMGetDataLayout(M: ModuleRef) -> *const c_char; + pub fn LLVMSetDataLayout(M: ModuleRef, Triple: *const c_char); + + /// Target triple. See Module::getTargetTriple. + pub fn LLVMGetTarget(M: ModuleRef) -> *const c_char; + pub fn LLVMSetTarget(M: ModuleRef, Triple: *const c_char); + + /// See Module::dump. + pub fn LLVMDumpModule(M: ModuleRef); + + /// See Module::setModuleInlineAsm. + pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); + + /// See llvm::LLVMTypeKind::getTypeID. + pub fn LLVMGetTypeKind(Ty: TypeRef) -> TypeKind; + + /// See llvm::LLVMType::getContext. + pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; + + /* Operations on integer types */ + pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) + -> TypeRef; + + pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; + + /* Operations on real types */ + pub fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMX86FP80TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMFP128TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef; + + /* Operations on function types */ + pub fn LLVMFunctionType(ReturnType: TypeRef, + ParamTypes: *const TypeRef, + ParamCount: c_uint, + IsVarArg: Bool) + -> TypeRef; + pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; + pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; + pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; + pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef); + + /* Operations on struct types */ + pub fn LLVMStructTypeInContext(C: ContextRef, + ElementTypes: *const TypeRef, + ElementCount: c_uint, + Packed: Bool) + -> TypeRef; + pub fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint; + pub fn LLVMGetStructElementTypes(StructTy: TypeRef, + Dest: *mut TypeRef); + pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool; + + /* Operations on array, pointer, and vector types (sequence types) */ + pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef; + pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) + -> TypeRef; + pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) + -> TypeRef; + + pub fn LLVMGetElementType(Ty: TypeRef) -> TypeRef; + pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint; + pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint; + pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef) + -> *const c_void; + pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint; + + /* Operations on other types */ + pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef; + + /* Operations on all values */ + pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef; + pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char; + pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char); + pub fn LLVMDumpValue(Val: ValueRef); + pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); + pub fn LLVMHasMetadata(Val: ValueRef) -> c_int; + pub fn LLVMGetMetadata(Val: ValueRef, KindID: c_uint) -> ValueRef; + pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef); + + /* Operations on Uses */ + pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef; + pub fn LLVMGetNextUse(U: UseRef) -> UseRef; + pub fn LLVMGetUser(U: UseRef) -> ValueRef; + pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef; + + /* Operations on Users */ + pub fn LLVMGetNumOperands(Val: ValueRef) -> c_int; + pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef; + pub fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef); + + /* Operations on constants of any type */ + pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef; + /* all zeroes */ + pub fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; + pub fn LLVMConstICmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) + -> ValueRef; + pub fn LLVMConstFCmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) + -> ValueRef; + /* only for isize/vector */ + pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; + pub fn LLVMIsConstant(Val: ValueRef) -> Bool; + pub fn LLVMIsNull(Val: ValueRef) -> Bool; + pub fn LLVMIsUndef(Val: ValueRef) -> Bool; + pub fn LLVMConstPointerNull(Ty: TypeRef) -> ValueRef; + + /* Operations on metadata */ + pub fn LLVMMDStringInContext(C: ContextRef, + Str: *const c_char, + SLen: c_uint) + -> ValueRef; + pub fn LLVMMDNodeInContext(C: ContextRef, + Vals: *const ValueRef, + Count: c_uint) + -> ValueRef; + pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, + Str: *const c_char, + Val: ValueRef); + + /* Operations on scalar constants */ + pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) + -> ValueRef; + pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) + -> ValueRef; + pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, + Text: *const c_char, + SLen: c_uint, + Radix: u8) + -> ValueRef; + pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; + pub fn LLVMConstRealOfString(RealTy: TypeRef, Text: *const c_char) + -> ValueRef; + pub fn LLVMConstRealOfStringAndSize(RealTy: TypeRef, + Text: *const c_char, + SLen: c_uint) + -> ValueRef; + pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; + pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; + + + /* Operations on composite constants */ + pub fn LLVMConstStringInContext(C: ContextRef, + Str: *const c_char, + Length: c_uint, + DontNullTerminate: Bool) + -> ValueRef; + pub fn LLVMConstStructInContext(C: ContextRef, + ConstantVals: *const ValueRef, + Count: c_uint, + Packed: Bool) + -> ValueRef; + + pub fn LLVMConstArray(ElementTy: TypeRef, + ConstantVals: *const ValueRef, + Length: c_uint) + -> ValueRef; + pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) + -> ValueRef; + + /* Constant expressions */ + pub fn LLVMAlignOf(Ty: TypeRef) -> ValueRef; + pub fn LLVMSizeOf(Ty: TypeRef) -> ValueRef; + pub fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstNSWNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstNUWNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstExactSDiv(LHSConstant: ValueRef, + RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstGEP(ConstantVal: ValueRef, + ConstantIndices: *const ValueRef, + NumIndices: c_uint) + -> ValueRef; + pub fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, + ConstantIndices: *const ValueRef, + NumIndices: c_uint) + -> ValueRef; + pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstIntCast(ConstantVal: ValueRef, + ToType: TypeRef, + isSigned: Bool) + -> ValueRef; + pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSelect(ConstantCondition: ValueRef, + ConstantIfTrue: ValueRef, + ConstantIfFalse: ValueRef) + -> ValueRef; + pub fn LLVMConstExtractElement(VectorConstant: ValueRef, + IndexConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstInsertElement(VectorConstant: ValueRef, + ElementValueConstant: ValueRef, + IndexConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstShuffleVector(VectorAConstant: ValueRef, + VectorBConstant: ValueRef, + MaskConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstExtractValue(AggConstant: ValueRef, + IdxList: *const c_uint, + NumIdx: c_uint) + -> ValueRef; + pub fn LLVMConstInsertValue(AggConstant: ValueRef, + ElementValueConstant: ValueRef, + IdxList: *const c_uint, + NumIdx: c_uint) + -> ValueRef; + pub fn LLVMConstInlineAsm(Ty: TypeRef, + AsmString: *const c_char, + Constraints: *const c_char, + HasSideEffects: Bool, + IsAlignStack: Bool) + -> ValueRef; + pub fn LLVMBlockAddress(F: ValueRef, BB: BasicBlockRef) -> ValueRef; + + + + /* Operations on global variables, functions, and aliases (globals) */ + pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; + pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool; + pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint; + pub fn LLVMSetLinkage(Global: ValueRef, Link: c_uint); + pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; + pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); + pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; + pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); + pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; + pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); + + + /* Operations on global variables */ + pub fn LLVMIsAGlobalVariable(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMAddGlobalInAddressSpace(M: ModuleRef, + Ty: TypeRef, + Name: *const c_char, + AddressSpace: c_uint) + -> ValueRef; + pub fn LLVMGetNamedGlobal(M: ModuleRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustGetOrInsertGlobal(M: ModuleRef, + Name: *const c_char, + T: TypeRef) + -> ValueRef; + pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; + pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; + pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousGlobal(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMDeleteGlobal(GlobalVar: ValueRef); + pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMSetInitializer(GlobalVar: ValueRef, + ConstantVal: ValueRef); + pub fn LLVMIsThreadLocal(GlobalVar: ValueRef) -> Bool; + pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); + pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; + pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); + pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; + + /* Operations on aliases */ + pub fn LLVMAddAlias(M: ModuleRef, + Ty: TypeRef, + Aliasee: ValueRef, + Name: *const c_char) + -> ValueRef; + + /* Operations on functions */ + pub fn LLVMAddFunction(M: ModuleRef, + Name: *const c_char, + FunctionTy: TypeRef) + -> ValueRef; + pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef; + pub fn LLVMGetLastFunction(M: ModuleRef) -> ValueRef; + pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; + pub fn LLVMDeleteFunction(Fn: ValueRef); + pub fn LLVMRustGetOrInsertFunction(M: ModuleRef, + Name: *const c_char, + FunctionTy: TypeRef) + -> ValueRef; + pub fn LLVMGetIntrinsicID(Fn: ValueRef) -> c_uint; + pub fn LLVMGetFunctionCallConv(Fn: ValueRef) -> c_uint; + pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); + pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; + pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); + pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64); + pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: u64); + pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, + Name: *const c_char, + Value: *const c_char); + pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, + index: c_uint, + attr: u64); + pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, + index: c_uint, + Name: *const c_char); + pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); + + /* Operations on parameters */ + pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; + pub fn LLVMGetParams(Fn: ValueRef, Params: *const ValueRef); + pub fn LLVMGetParam(Fn: ValueRef, Index: c_uint) -> ValueRef; + pub fn LLVMGetParamParent(Inst: ValueRef) -> ValueRef; + pub fn LLVMGetFirstParam(Fn: ValueRef) -> ValueRef; + pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; + pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; + pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint); + pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint); + pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; + pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); + + /* Operations on basic blocks */ + pub fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMValueIsBasicBlock(Val: ValueRef) -> Bool; + pub fn LLVMValueAsBasicBlock(Val: ValueRef) -> BasicBlockRef; + pub fn LLVMGetBasicBlockParent(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMCountBasicBlocks(Fn: ValueRef) -> c_uint; + pub fn LLVMGetBasicBlocks(Fn: ValueRef, BasicBlocks: *const ValueRef); + pub fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef; + pub fn LLVMGetLastBasicBlock(Fn: ValueRef) -> BasicBlockRef; + pub fn LLVMGetNextBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; + pub fn LLVMGetPreviousBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; + pub fn LLVMGetEntryBasicBlock(Fn: ValueRef) -> BasicBlockRef; + + pub fn LLVMAppendBasicBlockInContext(C: ContextRef, + Fn: ValueRef, + Name: *const c_char) + -> BasicBlockRef; + pub fn LLVMInsertBasicBlockInContext(C: ContextRef, + BB: BasicBlockRef, + Name: *const c_char) + -> BasicBlockRef; + pub fn LLVMDeleteBasicBlock(BB: BasicBlockRef); + + pub fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, + MoveAfter: BasicBlockRef); + + pub fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, + MoveBefore: BasicBlockRef); + + /* Operations on instructions */ + pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef; + pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMGetLastInstruction(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; + pub fn LLVMInstructionEraseFromParent(Inst: ValueRef); + + /* Operations on call sites */ + pub fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: c_uint); + pub fn LLVMGetInstructionCallConv(Instr: ValueRef) -> c_uint; + pub fn LLVMAddInstrAttribute(Instr: ValueRef, + index: c_uint, + IA: c_uint); + pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, + index: c_uint, + IA: c_uint); + pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, + index: c_uint, + align: c_uint); + pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, + index: c_uint, + Val: u64); + pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, + index: c_uint, + bytes: u64); + + /* Operations on call instructions (only) */ + pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; + pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); + + /* Operations on load/store instructions (only) */ + pub fn LLVMGetVolatile(MemoryAccessInst: ValueRef) -> Bool; + pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool); + + /* Operations on phi nodes */ + pub fn LLVMAddIncoming(PhiNode: ValueRef, + IncomingValues: *const ValueRef, + IncomingBlocks: *const BasicBlockRef, + Count: c_uint); + pub fn LLVMCountIncoming(PhiNode: ValueRef) -> c_uint; + pub fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: c_uint) + -> ValueRef; + pub fn LLVMGetIncomingBlock(PhiNode: ValueRef, Index: c_uint) + -> BasicBlockRef; + + /* Instruction builders */ + pub fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef; + pub fn LLVMPositionBuilder(Builder: BuilderRef, + Block: BasicBlockRef, + Instr: ValueRef); + pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, + Instr: ValueRef); + pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, + Block: BasicBlockRef); + pub fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef; + pub fn LLVMClearInsertionPosition(Builder: BuilderRef); + pub fn LLVMInsertIntoBuilder(Builder: BuilderRef, Instr: ValueRef); + pub fn LLVMInsertIntoBuilderWithName(Builder: BuilderRef, + Instr: ValueRef, + Name: *const c_char); + pub fn LLVMDisposeBuilder(Builder: BuilderRef); + + /* Metadata */ + pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); + pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; + pub fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef); + + /* Terminators */ + pub fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef; + pub fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef; + pub fn LLVMBuildAggregateRet(B: BuilderRef, + RetVals: *const ValueRef, + N: c_uint) + -> ValueRef; + pub fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef; + pub fn LLVMBuildCondBr(B: BuilderRef, + If: ValueRef, + Then: BasicBlockRef, + Else: BasicBlockRef) + -> ValueRef; + pub fn LLVMBuildSwitch(B: BuilderRef, + V: ValueRef, + Else: BasicBlockRef, + NumCases: c_uint) + -> ValueRef; + pub fn LLVMBuildIndirectBr(B: BuilderRef, + Addr: ValueRef, + NumDests: c_uint) + -> ValueRef; + pub fn LLVMRustBuildInvoke(B: BuilderRef, + Fn: ValueRef, + Args: *const ValueRef, + NumArgs: c_uint, + Then: BasicBlockRef, + Catch: BasicBlockRef, + Bundle: OperandBundleDefRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustBuildLandingPad(B: BuilderRef, + Ty: TypeRef, + PersFn: ValueRef, + NumClauses: c_uint, + Name: *const c_char, + F: ValueRef) + -> ValueRef; + pub fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef; + pub fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef; + + pub fn LLVMRustBuildCleanupPad(B: BuilderRef, + ParentPad: ValueRef, + ArgCnt: c_uint, + Args: *const ValueRef, + Name: *const c_char) -> ValueRef; + pub fn LLVMRustBuildCleanupRet(B: BuilderRef, + CleanupPad: ValueRef, + UnwindBB: BasicBlockRef) -> ValueRef; + pub fn LLVMRustBuildCatchPad(B: BuilderRef, + ParentPad: ValueRef, + ArgCnt: c_uint, + Args: *const ValueRef, + Name: *const c_char) -> ValueRef; + pub fn LLVMRustBuildCatchRet(B: BuilderRef, + Pad: ValueRef, + BB: BasicBlockRef) -> ValueRef; + pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef, + ParentPad: ValueRef, + BB: BasicBlockRef, + NumHandlers: c_uint, + Name: *const c_char) -> ValueRef; + pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, + Handler: BasicBlockRef); + pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); + + /* Add a case to the switch instruction */ + pub fn LLVMAddCase(Switch: ValueRef, + OnVal: ValueRef, + Dest: BasicBlockRef); + + /* Add a destination to the indirectbr instruction */ + pub fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); + + /* Add a clause to the landing pad instruction */ + pub fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); + + /* Set the cleanup on a landing pad instruction */ + pub fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); + + /* Arithmetic */ + pub fn LLVMBuildAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildUDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildExactSDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildURem(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSRem(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFRem(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildShl(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildLShr(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildAShr(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildAnd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildOr(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildXor(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildBinOp(B: BuilderRef, + Op: Opcode, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMRustSetHasUnsafeAlgebra(Instr: ValueRef); + + /* Memory */ + pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef; + pub fn LLVMBuildLoad(B: BuilderRef, + PointerVal: ValueRef, + Name: *const c_char) + -> ValueRef; + + pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) + -> ValueRef; + + pub fn LLVMBuildGEP(B: BuilderRef, + Pointer: ValueRef, + Indices: *const ValueRef, + NumIndices: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildInBoundsGEP(B: BuilderRef, + Pointer: ValueRef, + Indices: *const ValueRef, + NumIndices: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildStructGEP(B: BuilderRef, + Pointer: ValueRef, + Idx: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildGlobalString(B: BuilderRef, + Str: *const c_char, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildGlobalStringPtr(B: BuilderRef, + Str: *const c_char, + Name: *const c_char) + -> ValueRef; + + /* Casts */ + pub fn LLVMBuildTrunc(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildZExt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSExt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPToUI(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPToSI(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildUIToFP(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSIToFP(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPTrunc(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPExt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildPtrToInt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildIntToPtr(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildZExtOrBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSExtOrBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildTruncOrBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildCast(B: BuilderRef, + Op: Opcode, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) -> ValueRef; + pub fn LLVMBuildPointerCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildIntCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + + /* Comparisons */ + pub fn LLVMBuildICmp(B: BuilderRef, + Op: c_uint, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFCmp(B: BuilderRef, + Op: c_uint, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + + /* Miscellaneous instructions */ + pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMRustBuildCall(B: BuilderRef, + Fn: ValueRef, + Args: *const ValueRef, + NumArgs: c_uint, + Bundle: OperandBundleDefRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSelect(B: BuilderRef, + If: ValueRef, + Then: ValueRef, + Else: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildVAArg(B: BuilderRef, + list: ValueRef, + Ty: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildExtractElement(B: BuilderRef, + VecVal: ValueRef, + Index: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildInsertElement(B: BuilderRef, + VecVal: ValueRef, + EltVal: ValueRef, + Index: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildShuffleVector(B: BuilderRef, + V1: ValueRef, + V2: ValueRef, + Mask: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildExtractValue(B: BuilderRef, + AggVal: ValueRef, + Index: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildInsertValue(B: BuilderRef, + AggVal: ValueRef, + EltVal: ValueRef, + Index: c_uint, + Name: *const c_char) + -> ValueRef; + + pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildPtrDiff(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + + /* Atomic Operations */ + pub fn LLVMRustBuildAtomicLoad(B: BuilderRef, + PointerVal: ValueRef, + Name: *const c_char, + Order: AtomicOrdering, + Alignment: c_uint) + -> ValueRef; + + pub fn LLVMRustBuildAtomicStore(B: BuilderRef, + Val: ValueRef, + Ptr: ValueRef, + Order: AtomicOrdering, + Alignment: c_uint) + -> ValueRef; + + pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef, + LHS: ValueRef, + CMP: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering, + FailureOrder: AtomicOrdering, + Weak: Bool) + -> ValueRef; + + pub fn LLVMBuildAtomicRMW(B: BuilderRef, + Op: AtomicRmwBinOp, + LHS: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering, + SingleThreaded: Bool) + -> ValueRef; + + pub fn LLVMRustBuildAtomicFence(B: BuilderRef, + Order: AtomicOrdering, + Scope: SynchronizationScope); + + + /* Selected entries from the downcasts. */ + pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; + pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef; + + /// Writes a module to the specified path. Returns 0 on success. + pub fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: *const c_char) -> c_int; + + /// Creates target data from a target layout string. + pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef; + /// Number of bytes clobbered when doing a Store to *T. + pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_ulonglong; + + /// Number of bytes clobbered when doing a Store to *T. + pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) + -> c_ulonglong; + + /// Distance between successive elements in an array of T. Includes ABI padding. + pub fn LLVMABISizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; + + /// Returns the preferred alignment of a type. + pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_uint; + /// Returns the minimum alignment of a type. + pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_uint; + + /// Computes the byte offset of the indexed struct element for a + /// target. + pub fn LLVMOffsetOfElement(TD: TargetDataRef, + StructTy: TypeRef, + Element: c_uint) + -> c_ulonglong; + + /// Returns the minimum alignment of a type when part of a call frame. + pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_uint; + + /// Disposes target data. + pub fn LLVMDisposeTargetData(TD: TargetDataRef); + + /// Creates a pass manager. + pub fn LLVMCreatePassManager() -> PassManagerRef; + + /// Creates a function-by-function pass manager + pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) + -> PassManagerRef; + + /// Disposes a pass manager. + pub fn LLVMDisposePassManager(PM: PassManagerRef); + + /// Runs a pass manager on a module. + pub fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool; + + /// Runs the function passes on the provided function. + pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef) + -> Bool; + + /// Initializes all the function passes scheduled in the manager + pub fn LLVMInitializeFunctionPassManager(FPM: PassManagerRef) -> Bool; + + /// Finalizes all the function passes scheduled in the manager + pub fn LLVMFinalizeFunctionPassManager(FPM: PassManagerRef) -> Bool; + + pub fn LLVMInitializePasses(); + + /// Adds a verification pass. + pub fn LLVMAddVerifierPass(PM: PassManagerRef); + + pub fn LLVMAddGlobalOptimizerPass(PM: PassManagerRef); + pub fn LLVMAddIPSCCPPass(PM: PassManagerRef); + pub fn LLVMAddDeadArgEliminationPass(PM: PassManagerRef); + pub fn LLVMAddInstructionCombiningPass(PM: PassManagerRef); + pub fn LLVMAddCFGSimplificationPass(PM: PassManagerRef); + pub fn LLVMAddFunctionInliningPass(PM: PassManagerRef); + pub fn LLVMAddFunctionAttrsPass(PM: PassManagerRef); + pub fn LLVMAddScalarReplAggregatesPass(PM: PassManagerRef); + pub fn LLVMAddScalarReplAggregatesPassSSA(PM: PassManagerRef); + pub fn LLVMAddJumpThreadingPass(PM: PassManagerRef); + pub fn LLVMAddConstantPropagationPass(PM: PassManagerRef); + pub fn LLVMAddReassociatePass(PM: PassManagerRef); + pub fn LLVMAddLoopRotatePass(PM: PassManagerRef); + pub fn LLVMAddLICMPass(PM: PassManagerRef); + pub fn LLVMAddLoopUnswitchPass(PM: PassManagerRef); + pub fn LLVMAddLoopDeletionPass(PM: PassManagerRef); + pub fn LLVMAddLoopUnrollPass(PM: PassManagerRef); + pub fn LLVMAddGVNPass(PM: PassManagerRef); + pub fn LLVMAddMemCpyOptPass(PM: PassManagerRef); + pub fn LLVMAddSCCPPass(PM: PassManagerRef); + pub fn LLVMAddDeadStoreEliminationPass(PM: PassManagerRef); + pub fn LLVMAddStripDeadPrototypesPass(PM: PassManagerRef); + pub fn LLVMAddConstantMergePass(PM: PassManagerRef); + pub fn LLVMAddArgumentPromotionPass(PM: PassManagerRef); + pub fn LLVMAddTailCallEliminationPass(PM: PassManagerRef); + pub fn LLVMAddIndVarSimplifyPass(PM: PassManagerRef); + pub fn LLVMAddAggressiveDCEPass(PM: PassManagerRef); + pub fn LLVMAddGlobalDCEPass(PM: PassManagerRef); + pub fn LLVMAddCorrelatedValuePropagationPass(PM: PassManagerRef); + pub fn LLVMAddPruneEHPass(PM: PassManagerRef); + pub fn LLVMAddSimplifyLibCallsPass(PM: PassManagerRef); + pub fn LLVMAddLoopIdiomPass(PM: PassManagerRef); + pub fn LLVMAddEarlyCSEPass(PM: PassManagerRef); + pub fn LLVMAddTypeBasedAliasAnalysisPass(PM: PassManagerRef); + pub fn LLVMAddBasicAliasAnalysisPass(PM: PassManagerRef); + + pub fn LLVMPassManagerBuilderCreate() -> PassManagerBuilderRef; + pub fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef); + pub fn LLVMPassManagerBuilderSetOptLevel(PMB: PassManagerBuilderRef, + OptimizationLevel: c_uint); + pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableUnitAtATime( + PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableUnrollLoops( + PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls( + PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderUseInlinerWithThreshold( + PMB: PassManagerBuilderRef, + threshold: c_uint); + pub fn LLVMPassManagerBuilderPopulateModulePassManager( + PMB: PassManagerBuilderRef, + PM: PassManagerRef); + + pub fn LLVMPassManagerBuilderPopulateFunctionPassManager( + PMB: PassManagerBuilderRef, + PM: PassManagerRef); + pub fn LLVMPassManagerBuilderPopulateLTOPassManager( + PMB: PassManagerBuilderRef, + PM: PassManagerRef, + Internalize: Bool, + RunInliner: Bool); + + /// Destroys a memory buffer. + pub fn LLVMDisposeMemoryBuffer(MemBuf: MemoryBufferRef); + + + /* Stuff that's in rustllvm/ because it's not upstream yet. */ + + /// Opens an object file. + pub fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; + /// Closes an object file. + pub fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef); + + /// Enumerates the sections in an object file. + pub fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef; + /// Destroys a section iterator. + pub fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); + /// Returns true if the section iterator is at the end of the section + /// list: + pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, + SI: SectionIteratorRef) + -> Bool; + /// Moves the section iterator to point to the next section. + pub fn LLVMMoveToNextSection(SI: SectionIteratorRef); + /// Returns the current section size. + pub fn LLVMGetSectionSize(SI: SectionIteratorRef) -> c_ulonglong; + /// Returns the current section contents as a string buffer. + pub fn LLVMGetSectionContents(SI: SectionIteratorRef) -> *const c_char; + + /// Reads the given file and returns it as a memory buffer. Use + /// LLVMDisposeMemoryBuffer() to get rid of it. + pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) + -> MemoryBufferRef; + /// Borrows the contents of the memory buffer (doesn't copy it) + pub fn LLVMCreateMemoryBufferWithMemoryRange(InputData: *const c_char, + InputDataLength: size_t, + BufferName: *const c_char, + RequiresNull: Bool) + -> MemoryBufferRef; + pub fn LLVMCreateMemoryBufferWithMemoryRangeCopy(InputData: *const c_char, + InputDataLength: size_t, + BufferName: *const c_char) + -> MemoryBufferRef; + + pub fn LLVMIsMultithreaded() -> Bool; + pub fn LLVMStartMultithreaded() -> Bool; + + /// Returns a string describing the last error caused by an LLVMRust* call. + pub fn LLVMRustGetLastError() -> *const c_char; + + /// Print the pass timings since static dtors aren't picking them up. + pub fn LLVMRustPrintPassTimings(); + + pub fn LLVMStructCreateNamed(C: ContextRef, Name: *const c_char) -> TypeRef; + + pub fn LLVMStructSetBody(StructTy: TypeRef, + ElementTypes: *const TypeRef, + ElementCount: c_uint, + Packed: Bool); + + pub fn LLVMConstNamedStruct(S: TypeRef, + ConstantVals: *const ValueRef, + Count: c_uint) + -> ValueRef; + + /// Enables LLVM debug output. + pub fn LLVMRustSetDebug(Enabled: c_int); + + /// Prepares inline assembly. + pub fn LLVMRustInlineAsm(Ty: TypeRef, + AsmString: *const c_char, + Constraints: *const c_char, + SideEffects: Bool, + AlignStack: Bool, + Dialect: c_uint) + -> ValueRef; + + pub fn LLVMRustDebugMetadataVersion() -> u32; + pub fn LLVMRustVersionMajor() -> u32; + pub fn LLVMRustVersionMinor() -> u32; + + pub fn LLVMRustAddModuleFlag(M: ModuleRef, + name: *const c_char, + value: u32); + + pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; + + pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef); + + pub fn LLVMRustDIBuilderFinalize(Builder: DIBuilderRef); + + pub fn LLVMRustDIBuilderCreateCompileUnit(Builder: DIBuilderRef, + Lang: c_uint, + File: *const c_char, + Dir: *const c_char, + Producer: *const c_char, + isOptimized: bool, + Flags: *const c_char, + RuntimeVer: c_uint, + SplitName: *const c_char) + -> DIDescriptor; + + pub fn LLVMRustDIBuilderCreateFile(Builder: DIBuilderRef, + Filename: *const c_char, + Directory: *const c_char) + -> DIFile; + + pub fn LLVMRustDIBuilderCreateSubroutineType(Builder: DIBuilderRef, + File: DIFile, + ParameterTypes: DIArray) + -> DICompositeType; + + pub fn LLVMRustDIBuilderCreateFunction(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + LinkageName: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + isDefinition: bool, + ScopeLine: c_uint, + Flags: c_uint, + isOptimized: bool, + Fn: ValueRef, + TParam: DIArray, + Decl: DIDescriptor) + -> DISubprogram; + + pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef, + Name: *const c_char, + SizeInBits: u64, + AlignInBits: u64, + Encoding: c_uint) + -> DIBasicType; + + pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef, + PointeeTy: DIType, + SizeInBits: u64, + AlignInBits: u64, + Name: *const c_char) + -> DIDerivedType; + + pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Flags: c_uint, + DerivedFrom: DIType, + Elements: DIArray, + RunTimeLang: c_uint, + VTableHolder: DIType, + UniqueId: *const c_char) + -> DICompositeType; + + pub fn LLVMRustDIBuilderCreateMemberType(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNo: c_uint, + SizeInBits: u64, + AlignInBits: u64, + OffsetInBits: u64, + Flags: c_uint, + Ty: DIType) + -> DIDerivedType; + + pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: DIBuilderRef, + Scope: DIScope, + File: DIFile, + Line: c_uint, + Col: c_uint) + -> DILexicalBlock; + + pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef, + Context: DIScope, + Name: *const c_char, + LinkageName: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + Val: ValueRef, + Decl: DIDescriptor) + -> DIGlobalVariable; + + pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef, + Tag: c_uint, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + AlwaysPreserve: bool, + Flags: c_uint, + AddrOps: *const i64, + AddrOpsCount: c_uint, + ArgNo: c_uint) + -> DIVariable; + + pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef, + Size: u64, + AlignInBits: u64, + Ty: DIType, + Subscripts: DIArray) + -> DIType; + + pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef, + Size: u64, + AlignInBits: u64, + Ty: DIType, + Subscripts: DIArray) + -> DIType; + + pub fn LLVMRustDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef, + Lo: i64, + Count: i64) + -> DISubrange; + + pub fn LLVMRustDIBuilderGetOrCreateArray(Builder: DIBuilderRef, + Ptr: *const DIDescriptor, + Count: c_uint) + -> DIArray; + + pub fn LLVMRustDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + AddrOps: *const i64, + AddrOpsCount: c_uint, + DL: ValueRef, + InsertAtEnd: BasicBlockRef) + -> ValueRef; + + pub fn LLVMRustDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + AddrOps: *const i64, + AddrOpsCount: c_uint, + DL: ValueRef, + InsertBefore: ValueRef) + -> ValueRef; + + pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef, + Name: *const c_char, + Val: u64) + -> DIEnumerator; + + pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Elements: DIArray, + ClassType: DIType) + -> DIType; + + pub fn LLVMRustDIBuilderCreateUnionType(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Flags: c_uint, + Elements: DIArray, + RunTimeLang: c_uint, + UniqueId: *const c_char) + -> DIType; + + pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool); + + pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + Ty: DIType, + File: DIFile, + LineNo: c_uint, + ColumnNo: c_uint) + -> DITemplateTypeParameter; + + + pub fn LLVMRustDIBuilderCreateNameSpace(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNo: c_uint) + -> DINameSpace; + pub fn LLVMRustDICompositeTypeSetTypeArray(Builder: DIBuilderRef, + CompositeType: DIType, + TypeArray: DIArray); + + + pub fn LLVMRustDIBuilderCreateDebugLocation(Context: ContextRef, + Line: c_uint, + Column: c_uint, + Scope: DIScope, + InlinedAt: MetadataRef) + -> ValueRef; + pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; + pub fn LLVMRustDIBuilderCreateOpPlus() -> i64; + + pub fn LLVMRustWriteTypeToString(Type: TypeRef, s: RustStringRef); + pub fn LLVMRustWriteValueToString(value_ref: ValueRef, s: RustStringRef); + + pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; + + pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; + pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; + + pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind; + pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; + pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); + + pub fn LLVMRustHasFeature(T: TargetMachineRef, + s: *const c_char) -> bool; + + pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, + CPU: *const c_char, + Features: *const c_char, + Model: CodeModel, + Reloc: RelocMode, + Level: CodeGenOptLevel, + UseSoftFP: bool, + PositionIndependentExecutable: bool, + FunctionSections: bool, + DataSections: bool) -> TargetMachineRef; + pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); + pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, + PM: PassManagerRef, + M: ModuleRef); + pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, + M: ModuleRef, + DisableSimplifyLibCalls: bool); + pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef, + OptLevel: CodeGenOptLevel, + MergeFunctions: bool, + SLPVectorize: bool, + LoopVectorize: bool); + pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, + DisableSimplifyLibCalls: bool); + pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); + pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, + PM: PassManagerRef, + M: ModuleRef, + Output: *const c_char, + FileType: FileType) + -> LLVMRustResult; + pub fn LLVMRustPrintModule(PM: PassManagerRef, + M: ModuleRef, + Output: *const c_char); + pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); + pub fn LLVMRustPrintPasses(); + pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); + pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, + AddLifetimes: bool); + pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, + bc: *const c_char, + len: size_t) -> bool; + pub fn LLVMRustRunRestrictionPass(M: ModuleRef, + syms: *const *const c_char, + len: size_t); + pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); + + pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef; + pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef; + pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef) -> ArchiveChildRef; + pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, + size: *mut size_t) -> *const c_char; + pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, + size: *mut size_t) -> *const c_char; + pub fn LLVMRustArchiveChildFree(ACR: ArchiveChildRef); + pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef); + pub fn LLVMRustDestroyArchive(AR: ArchiveRef); + + pub fn LLVMRustSetDLLStorageClass(V: ValueRef, + C: DLLStorageClassTypes); + + pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, + data: *mut *const c_char) -> size_t; + + pub fn LLVMRustWriteTwineToString(T: TwineRef, s: RustStringRef); + + pub fn LLVMContextSetDiagnosticHandler(C: ContextRef, + Handler: DiagnosticHandler, + DiagnosticContext: *mut c_void); + + pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, + pass_name_out: *mut *const c_char, + function_out: *mut ValueRef, + debugloc_out: *mut DebugLocRef, + message_out: *mut TwineRef); + pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, + cookie_out: *mut c_uint, + message_out: *mut TwineRef, + instruction_out: *mut ValueRef); + + pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, + s: RustStringRef); + pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity; + pub fn LLVMRustGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; + + pub fn LLVMRustWriteDebugLocToString(C: ContextRef, + DL: DebugLocRef, + s: RustStringRef); + + pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: ContextRef, + H: InlineAsmDiagHandler, + CX: *mut c_void); + + pub fn LLVMRustWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); + + pub fn LLVMRustWriteArchive(Dst: *const c_char, + NumMembers: size_t, + Members: *const RustArchiveMemberRef, + WriteSymbtab: bool, + Kind: ArchiveKind) -> + LLVMRustResult; + pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, + Name: *const c_char, + Child: ArchiveChildRef) -> RustArchiveMemberRef; + pub fn LLVMRustArchiveMemberFree(Member: RustArchiveMemberRef); + + pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, + TM: TargetMachineRef); + pub fn LLVMRustGetModuleDataLayout(M: ModuleRef) -> TargetDataRef; + + pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char, + Inputs: *const ValueRef, + NumInputs: c_uint) + -> OperandBundleDefRef; + pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef); + + pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef); + + pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char); + pub fn LLVMRustUnsetComdat(V: ValueRef); + pub fn LLVMRustSetModulePIELevel(M: ModuleRef); +} + + +// LLVM requires symbols from this library, but apparently they're not printed +// during llvm-config? +#[cfg(windows)] +#[link(name = "ole32")] +extern {} diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 622e7923d8fb..f451b167196c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -37,43 +37,26 @@ pub use self::AttributeSet::*; pub use self::IntPredicate::*; pub use self::RealPredicate::*; pub use self::TypeKind::*; -pub use self::AtomicBinOp::*; +pub use self::AtomicRmwBinOp::*; pub use self::MetadataType::*; pub use self::AsmDialect::*; pub use self::CodeGenOptSize::*; pub use self::DiagnosticKind::*; pub use self::CallConv::*; -pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; use std::str::FromStr; +use std::slice; use std::ffi::{CString, CStr}; use std::cell::RefCell; -use std::slice; -use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; -use libc::{c_longlong, c_ulonglong, c_void}; -use debuginfo::{DIBuilderRef, DIDescriptor, - DIFile, DILexicalBlock, DISubprogram, DIType, - DIBasicType, DIDerivedType, DICompositeType, DIScope, - DIVariable, DIGlobalVariable, DIArray, DISubrange, - DITemplateTypeParameter, DIEnumerator, DINameSpace}; +use libc::{c_uint, c_ushort, c_char, size_t}; pub mod archive_ro; pub mod diagnostic; +pub mod ffi; -pub type Opcode = u32; -pub type Bool = c_uint; - -pub const True: Bool = 1 as Bool; -pub const False: Bool = 0 as Bool; - -#[repr(C)] -#[derive(Copy, Clone, PartialEq)] -pub enum LLVMRustResult { - Success = 0, - Failure = 1 -} +pub use ffi::*; impl LLVMRustResult { pub fn into_result(self) -> Result<(), ()> { @@ -84,122 +67,6 @@ impl LLVMRustResult { } } -// Consts for the LLVM CallConv type, pre-cast to usize. - -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum CallConv { - CCallConv = 0, - FastCallConv = 8, - ColdCallConv = 9, - X86StdcallCallConv = 64, - X86FastcallCallConv = 65, - X86_64_Win64 = 79, - X86_VectorCall = 80 -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub enum Visibility { - LLVMDefaultVisibility = 0, - HiddenVisibility = 1, - ProtectedVisibility = 2, -} - -// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage, -// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. -// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; -// they've been removed in upstream LLVM commit r203866. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[repr(C)] -pub enum Linkage { - ExternalLinkage = 0, - AvailableExternallyLinkage = 1, - LinkOnceAnyLinkage = 2, - LinkOnceODRLinkage = 3, - WeakAnyLinkage = 5, - WeakODRLinkage = 6, - AppendingLinkage = 7, - InternalLinkage = 8, - PrivateLinkage = 9, - ExternalWeakLinkage = 12, - CommonLinkage = 14, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub enum DiagnosticSeverity { - Error = 0, - Warning = 1, - Remark = 2, - Note = 3, -} - - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum DLLStorageClassTypes { - Other, - Default, - DllImport, - DllExport, -} - -bitflags! { - #[derive(Default, Debug)] - flags Attribute : u64 { - const ZExt = 1 << 0, - const SExt = 1 << 1, - const NoReturn = 1 << 2, - const InReg = 1 << 3, - const StructRet = 1 << 4, - const NoUnwind = 1 << 5, - const NoAlias = 1 << 6, - const ByVal = 1 << 7, - const Nest = 1 << 8, - const ReadNone = 1 << 9, - const ReadOnly = 1 << 10, - const NoInline = 1 << 11, - const AlwaysInline = 1 << 12, - const OptimizeForSize = 1 << 13, - const StackProtect = 1 << 14, - const StackProtectReq = 1 << 15, - const NoCapture = 1 << 21, - const NoRedZone = 1 << 22, - const NoImplicitFloat = 1 << 23, - const Naked = 1 << 24, - const InlineHint = 1 << 25, - const ReturnsTwice = 1 << 29, - const UWTable = 1 << 30, - const NonLazyBind = 1 << 31, - - // Some of these are missing from the LLVM C API, the rest are - // present, but commented out, and preceded by the following warning: - // FIXME: These attributes are currently not included in the C API as - // a temporary measure until the API/ABI impact to the C API is understood - // and the path forward agreed upon. - const SanitizeAddress = 1 << 32, - const MinSize = 1 << 33, - const NoDuplicate = 1 << 34, - const StackProtectStrong = 1 << 35, - const SanitizeThread = 1 << 36, - const SanitizeMemory = 1 << 37, - const NoBuiltin = 1 << 38, - const Returned = 1 << 39, - const Cold = 1 << 40, - const Builtin = 1 << 41, - const OptimizeNone = 1 << 42, - const InAlloca = 1 << 43, - const NonNull = 1 << 44, - const JumpTable = 1 << 45, - const Convergent = 1 << 46, - const SafeStack = 1 << 47, - const NoRecurse = 1 << 48, - const InaccessibleMemOnly = 1 << 49, - const InaccessibleMemOrArgMemOnly = 1 << 50, - } -} - #[derive(Copy, Clone, Default, Debug)] pub struct Attributes { regular: Attribute, @@ -255,143 +122,6 @@ pub enum AttributeSet { FunctionIndex = !0 } -// enum for the LLVM IntPredicate type -#[derive(Copy, Clone)] -pub enum IntPredicate { - IntEQ = 32, - IntNE = 33, - IntUGT = 34, - IntUGE = 35, - IntULT = 36, - IntULE = 37, - IntSGT = 38, - IntSGE = 39, - IntSLT = 40, - IntSLE = 41, -} - -// enum for the LLVM RealPredicate type -#[derive(Copy, Clone)] -pub enum RealPredicate { - RealPredicateFalse = 0, - RealOEQ = 1, - RealOGT = 2, - RealOGE = 3, - RealOLT = 4, - RealOLE = 5, - RealONE = 6, - RealORD = 7, - RealUNO = 8, - RealUEQ = 9, - RealUGT = 10, - RealUGE = 11, - RealULT = 12, - RealULE = 13, - RealUNE = 14, - RealPredicateTrue = 15, -} - -// The LLVM TypeKind type - must stay in sync with the def of -// LLVMTypeKind in llvm/include/llvm-c/Core.h -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum TypeKind { - Void = 0, - Half = 1, - Float = 2, - Double = 3, - X86_FP80 = 4, - FP128 = 5, - PPC_FP128 = 6, - Label = 7, - Integer = 8, - Function = 9, - Struct = 10, - Array = 11, - Pointer = 12, - Vector = 13, - Metadata = 14, - X86_MMX = 15, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum AtomicBinOp { - AtomicXchg = 0, - AtomicAdd = 1, - AtomicSub = 2, - AtomicAnd = 3, - AtomicNand = 4, - AtomicOr = 5, - AtomicXor = 6, - AtomicMax = 7, - AtomicMin = 8, - AtomicUMax = 9, - AtomicUMin = 10, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum AtomicOrdering { - NotAtomic = 0, - Unordered = 1, - Monotonic = 2, - // Consume = 3, // Not specified yet. - Acquire = 4, - Release = 5, - AcquireRelease = 6, - SequentiallyConsistent = 7 -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum SynchronizationScope { - Other, - SingleThread, - CrossThread, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum FileType { - Other, - AssemblyFile, - ObjectFile, -} - -#[derive(Copy, Clone)] -pub enum MetadataType { - MD_dbg = 0, - MD_tbaa = 1, - MD_prof = 2, - MD_fpmath = 3, - MD_range = 4, - MD_tbaa_struct = 5, - MD_invariant_load = 6, - MD_alias_scope = 7, - MD_noalias = 8, - MD_nontemporal = 9, - MD_mem_parallel_loop_access = 10, - MD_nonnull = 11, -} - -// Inline Asm Dialect -#[derive(Copy, Clone)] -pub enum AsmDialect { - AD_ATT = 0, - AD_Intel = 1 -} - -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum CodeGenOptLevel { - Other, - None, - Less, - Default, - Aggressive, -} - #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum CodeGenOptSize { @@ -400,54 +130,6 @@ pub enum CodeGenOptSize { CodeGenOptSizeAggressive = 2, } -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum RelocMode { - Default = 0, - Static = 1, - PIC = 2, - DynamicNoPic = 3, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum CodeModel { - Other, - Default, - JITDefault, - Small, - Kernel, - Medium, - Large, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum DiagnosticKind { - Other, - InlineAsm, - StackSize, - DebugMetadataVersion, - SampleProfile, - OptimizationRemark, - OptimizationRemarkMissed, - OptimizationRemarkAnalysis, - OptimizationRemarkAnalysisFPCommute, - OptimizationRemarkAnalysisAliasing, - OptimizationRemarkOther, - OptimizationFailure, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ArchiveKind { - Other, - K_GNU, - K_MIPS64, - K_BSD, - K_COFF, -} - impl FromStr for ArchiveKind { type Err = (); @@ -462,1732 +144,22 @@ impl FromStr for ArchiveKind { } } -/// Represents the different LLVM passes Rust supports -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum PassKind { - Other, - Function, - Module, +#[allow(missing_copy_implementations)] +pub enum RustString_opaque {} +pub type RustStringRef = *mut RustString_opaque; +type RustStringRepr = *mut RefCell>; + +/// Appending to a Rust string -- used by raw_rust_string_ostream. +#[no_mangle] +pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef, + ptr: *const c_char, + size: size_t) { + let slice = slice::from_raw_parts(ptr as *const u8, size as usize); + + let sr = sr as RustStringRepr; + (*sr).borrow_mut().extend_from_slice(slice); } -// Opaque pointer types -#[allow(missing_copy_implementations)] -pub enum Module_opaque {} -pub type ModuleRef = *mut Module_opaque; -#[allow(missing_copy_implementations)] -pub enum Context_opaque {} -pub type ContextRef = *mut Context_opaque; -#[allow(missing_copy_implementations)] -pub enum Type_opaque {} -pub type TypeRef = *mut Type_opaque; -#[allow(missing_copy_implementations)] -pub enum Value_opaque {} -pub type ValueRef = *mut Value_opaque; -#[allow(missing_copy_implementations)] -pub enum Metadata_opaque {} -pub type MetadataRef = *mut Metadata_opaque; -#[allow(missing_copy_implementations)] -pub enum BasicBlock_opaque {} -pub type BasicBlockRef = *mut BasicBlock_opaque; -#[allow(missing_copy_implementations)] -pub enum Builder_opaque {} -pub type BuilderRef = *mut Builder_opaque; -#[allow(missing_copy_implementations)] -pub enum ExecutionEngine_opaque {} -pub type ExecutionEngineRef = *mut ExecutionEngine_opaque; -#[allow(missing_copy_implementations)] -pub enum MemoryBuffer_opaque {} -pub type MemoryBufferRef = *mut MemoryBuffer_opaque; -#[allow(missing_copy_implementations)] -pub enum PassManager_opaque {} -pub type PassManagerRef = *mut PassManager_opaque; -#[allow(missing_copy_implementations)] -pub enum PassManagerBuilder_opaque {} -pub type PassManagerBuilderRef = *mut PassManagerBuilder_opaque; -#[allow(missing_copy_implementations)] -pub enum Use_opaque {} -pub type UseRef = *mut Use_opaque; -#[allow(missing_copy_implementations)] -pub enum TargetData_opaque {} -pub type TargetDataRef = *mut TargetData_opaque; -#[allow(missing_copy_implementations)] -pub enum ObjectFile_opaque {} -pub type ObjectFileRef = *mut ObjectFile_opaque; -#[allow(missing_copy_implementations)] -pub enum SectionIterator_opaque {} -pub type SectionIteratorRef = *mut SectionIterator_opaque; -#[allow(missing_copy_implementations)] -pub enum Pass_opaque {} -pub type PassRef = *mut Pass_opaque; -#[allow(missing_copy_implementations)] -pub enum TargetMachine_opaque {} -pub type TargetMachineRef = *mut TargetMachine_opaque; -pub enum Archive_opaque {} -pub type ArchiveRef = *mut Archive_opaque; -pub enum ArchiveIterator_opaque {} -pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque; -pub enum ArchiveChild_opaque {} -pub type ArchiveChildRef = *mut ArchiveChild_opaque; -#[allow(missing_copy_implementations)] -pub enum Twine_opaque {} -pub type TwineRef = *mut Twine_opaque; -#[allow(missing_copy_implementations)] -pub enum DiagnosticInfo_opaque {} -pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque; -#[allow(missing_copy_implementations)] -pub enum DebugLoc_opaque {} -pub type DebugLocRef = *mut DebugLoc_opaque; -#[allow(missing_copy_implementations)] -pub enum SMDiagnostic_opaque {} -pub type SMDiagnosticRef = *mut SMDiagnostic_opaque; -#[allow(missing_copy_implementations)] -pub enum RustArchiveMember_opaque {} -pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; -#[allow(missing_copy_implementations)] -pub enum OperandBundleDef_opaque {} -pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; - -pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); -pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); - -pub mod debuginfo { - pub use self::DIDescriptorFlags::*; - use super::{MetadataRef}; - - #[allow(missing_copy_implementations)] - pub enum DIBuilder_opaque {} - pub type DIBuilderRef = *mut DIBuilder_opaque; - - pub type DIDescriptor = MetadataRef; - pub type DIScope = DIDescriptor; - pub type DILocation = DIDescriptor; - pub type DIFile = DIScope; - pub type DILexicalBlock = DIScope; - pub type DISubprogram = DIScope; - pub type DINameSpace = DIScope; - pub type DIType = DIDescriptor; - pub type DIBasicType = DIType; - pub type DIDerivedType = DIType; - pub type DICompositeType = DIDerivedType; - pub type DIVariable = DIDescriptor; - pub type DIGlobalVariable = DIDescriptor; - pub type DIArray = DIDescriptor; - pub type DISubrange = DIDescriptor; - pub type DIEnumerator = DIDescriptor; - pub type DITemplateTypeParameter = DIDescriptor; - - #[derive(Copy, Clone)] - pub enum DIDescriptorFlags { - FlagPrivate = 1 << 0, - FlagProtected = 1 << 1, - FlagFwdDecl = 1 << 2, - FlagAppleBlock = 1 << 3, - FlagBlockByrefStruct = 1 << 4, - FlagVirtual = 1 << 5, - FlagArtificial = 1 << 6, - FlagExplicit = 1 << 7, - FlagPrototyped = 1 << 8, - FlagObjcClassComplete = 1 << 9, - FlagObjectPointer = 1 << 10, - FlagVector = 1 << 11, - FlagStaticMember = 1 << 12, - FlagIndirectVariable = 1 << 13, - FlagLValueReference = 1 << 14, - FlagRValueReference = 1 << 15 - } -} - - -// Link to our native llvm bindings (things that we need to use the C++ api -// for) and because llvm is written in C++ we need to link against libstdc++ -// -// You'll probably notice that there is an omission of all LLVM libraries -// from this location. This is because the set of LLVM libraries that we -// link to is mostly defined by LLVM, and the `llvm-config` tool is used to -// figure out the exact set of libraries. To do this, the build system -// generates an llvmdeps.rs file next to this one which will be -// automatically updated whenever LLVM is updated to include an up-to-date -// set of the libraries we need to link to LLVM for. -#[link(name = "rustllvm", kind = "static")] -#[cfg(not(cargobuild))] -extern {} - -#[linked_from = "rustllvm"] // not quite true but good enough -extern { - /* Create and destroy contexts. */ - pub fn LLVMContextCreate() -> ContextRef; - pub fn LLVMContextDispose(C: ContextRef); - pub fn LLVMGetMDKindIDInContext(C: ContextRef, - Name: *const c_char, - SLen: c_uint) - -> c_uint; - - /* Create and destroy modules. */ - pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, - C: ContextRef) - -> ModuleRef; - pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef; - pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef; - pub fn LLVMDisposeModule(M: ModuleRef); - - /// Data layout. See Module::getDataLayout. - pub fn LLVMGetDataLayout(M: ModuleRef) -> *const c_char; - pub fn LLVMSetDataLayout(M: ModuleRef, Triple: *const c_char); - - /// Target triple. See Module::getTargetTriple. - pub fn LLVMGetTarget(M: ModuleRef) -> *const c_char; - pub fn LLVMSetTarget(M: ModuleRef, Triple: *const c_char); - - /// See Module::dump. - pub fn LLVMDumpModule(M: ModuleRef); - - /// See Module::setModuleInlineAsm. - pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); - - /// See llvm::LLVMTypeKind::getTypeID. - pub fn LLVMGetTypeKind(Ty: TypeRef) -> TypeKind; - - /// See llvm::LLVMType::getContext. - pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; - - /* Operations on integer types */ - pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) - -> TypeRef; - - pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; - - /* Operations on real types */ - pub fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMX86FP80TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMFP128TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef; - - /* Operations on function types */ - pub fn LLVMFunctionType(ReturnType: TypeRef, - ParamTypes: *const TypeRef, - ParamCount: c_uint, - IsVarArg: Bool) - -> TypeRef; - pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; - pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; - pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; - pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef); - - /* Operations on struct types */ - pub fn LLVMStructTypeInContext(C: ContextRef, - ElementTypes: *const TypeRef, - ElementCount: c_uint, - Packed: Bool) - -> TypeRef; - pub fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint; - pub fn LLVMGetStructElementTypes(StructTy: TypeRef, - Dest: *mut TypeRef); - pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool; - - /* Operations on array, pointer, and vector types (sequence types) */ - pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef; - pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) - -> TypeRef; - pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) - -> TypeRef; - - pub fn LLVMGetElementType(Ty: TypeRef) -> TypeRef; - pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint; - pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint; - pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef) - -> *const c_void; - pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint; - - /* Operations on other types */ - pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef; - - /* Operations on all values */ - pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef; - pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char; - pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char); - pub fn LLVMDumpValue(Val: ValueRef); - pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); - pub fn LLVMHasMetadata(Val: ValueRef) -> c_int; - pub fn LLVMGetMetadata(Val: ValueRef, KindID: c_uint) -> ValueRef; - pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef); - - /* Operations on Uses */ - pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef; - pub fn LLVMGetNextUse(U: UseRef) -> UseRef; - pub fn LLVMGetUser(U: UseRef) -> ValueRef; - pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef; - - /* Operations on Users */ - pub fn LLVMGetNumOperands(Val: ValueRef) -> c_int; - pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef; - pub fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef); - - /* Operations on constants of any type */ - pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef; - /* all zeroes */ - pub fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; - pub fn LLVMConstICmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) - -> ValueRef; - pub fn LLVMConstFCmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) - -> ValueRef; - /* only for isize/vector */ - pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; - pub fn LLVMIsConstant(Val: ValueRef) -> Bool; - pub fn LLVMIsNull(Val: ValueRef) -> Bool; - pub fn LLVMIsUndef(Val: ValueRef) -> Bool; - pub fn LLVMConstPointerNull(Ty: TypeRef) -> ValueRef; - - /* Operations on metadata */ - pub fn LLVMMDStringInContext(C: ContextRef, - Str: *const c_char, - SLen: c_uint) - -> ValueRef; - pub fn LLVMMDNodeInContext(C: ContextRef, - Vals: *const ValueRef, - Count: c_uint) - -> ValueRef; - pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, - Str: *const c_char, - Val: ValueRef); - - /* Operations on scalar constants */ - pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) - -> ValueRef; - pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) - -> ValueRef; - pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, - Text: *const c_char, - SLen: c_uint, - Radix: u8) - -> ValueRef; - pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; - pub fn LLVMConstRealOfString(RealTy: TypeRef, Text: *const c_char) - -> ValueRef; - pub fn LLVMConstRealOfStringAndSize(RealTy: TypeRef, - Text: *const c_char, - SLen: c_uint) - -> ValueRef; - pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; - pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; - - - /* Operations on composite constants */ - pub fn LLVMConstStringInContext(C: ContextRef, - Str: *const c_char, - Length: c_uint, - DontNullTerminate: Bool) - -> ValueRef; - pub fn LLVMConstStructInContext(C: ContextRef, - ConstantVals: *const ValueRef, - Count: c_uint, - Packed: Bool) - -> ValueRef; - - pub fn LLVMConstArray(ElementTy: TypeRef, - ConstantVals: *const ValueRef, - Length: c_uint) - -> ValueRef; - pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) - -> ValueRef; - - /* Constant expressions */ - pub fn LLVMAlignOf(Ty: TypeRef) -> ValueRef; - pub fn LLVMSizeOf(Ty: TypeRef) -> ValueRef; - pub fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstNSWNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstNUWNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstExactSDiv(LHSConstant: ValueRef, - RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstGEP(ConstantVal: ValueRef, - ConstantIndices: *const ValueRef, - NumIndices: c_uint) - -> ValueRef; - pub fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, - ConstantIndices: *const ValueRef, - NumIndices: c_uint) - -> ValueRef; - pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstIntCast(ConstantVal: ValueRef, - ToType: TypeRef, - isSigned: Bool) - -> ValueRef; - pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSelect(ConstantCondition: ValueRef, - ConstantIfTrue: ValueRef, - ConstantIfFalse: ValueRef) - -> ValueRef; - pub fn LLVMConstExtractElement(VectorConstant: ValueRef, - IndexConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstInsertElement(VectorConstant: ValueRef, - ElementValueConstant: ValueRef, - IndexConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstShuffleVector(VectorAConstant: ValueRef, - VectorBConstant: ValueRef, - MaskConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstExtractValue(AggConstant: ValueRef, - IdxList: *const c_uint, - NumIdx: c_uint) - -> ValueRef; - pub fn LLVMConstInsertValue(AggConstant: ValueRef, - ElementValueConstant: ValueRef, - IdxList: *const c_uint, - NumIdx: c_uint) - -> ValueRef; - pub fn LLVMConstInlineAsm(Ty: TypeRef, - AsmString: *const c_char, - Constraints: *const c_char, - HasSideEffects: Bool, - IsAlignStack: Bool) - -> ValueRef; - pub fn LLVMBlockAddress(F: ValueRef, BB: BasicBlockRef) -> ValueRef; - - - - /* Operations on global variables, functions, and aliases (globals) */ - pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; - pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool; - pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint; - pub fn LLVMSetLinkage(Global: ValueRef, Link: c_uint); - pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; - pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); - pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; - pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); - pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; - pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); - - - /* Operations on global variables */ - pub fn LLVMIsAGlobalVariable(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMAddGlobalInAddressSpace(M: ModuleRef, - Ty: TypeRef, - Name: *const c_char, - AddressSpace: c_uint) - -> ValueRef; - pub fn LLVMGetNamedGlobal(M: ModuleRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMRustGetOrInsertGlobal(M: ModuleRef, - Name: *const c_char, - T: TypeRef) - -> ValueRef; - pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; - pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; - pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousGlobal(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMDeleteGlobal(GlobalVar: ValueRef); - pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMSetInitializer(GlobalVar: ValueRef, - ConstantVal: ValueRef); - pub fn LLVMIsThreadLocal(GlobalVar: ValueRef) -> Bool; - pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); - pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; - pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); - pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; - - /* Operations on aliases */ - pub fn LLVMAddAlias(M: ModuleRef, - Ty: TypeRef, - Aliasee: ValueRef, - Name: *const c_char) - -> ValueRef; - - /* Operations on functions */ - pub fn LLVMAddFunction(M: ModuleRef, - Name: *const c_char, - FunctionTy: TypeRef) - -> ValueRef; - pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; - pub fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef; - pub fn LLVMGetLastFunction(M: ModuleRef) -> ValueRef; - pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; - pub fn LLVMDeleteFunction(Fn: ValueRef); - pub fn LLVMRustGetOrInsertFunction(M: ModuleRef, - Name: *const c_char, - FunctionTy: TypeRef) - -> ValueRef; - pub fn LLVMGetIntrinsicID(Fn: ValueRef) -> c_uint; - pub fn LLVMGetFunctionCallConv(Fn: ValueRef) -> c_uint; - pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); - pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; - pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); - pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); - pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); - pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, - Name: *const c_char, - Value: *const c_char); - pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, - index: c_uint, - attr: uint64_t); - pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, - index: c_uint, - Name: *const c_char); - pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; - pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); - - /* Operations on parameters */ - pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; - pub fn LLVMGetParams(Fn: ValueRef, Params: *const ValueRef); - pub fn LLVMGetParam(Fn: ValueRef, Index: c_uint) -> ValueRef; - pub fn LLVMGetParamParent(Inst: ValueRef) -> ValueRef; - pub fn LLVMGetFirstParam(Fn: ValueRef) -> ValueRef; - pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; - pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; - pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; - pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); - - /* Operations on basic blocks */ - pub fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMValueIsBasicBlock(Val: ValueRef) -> Bool; - pub fn LLVMValueAsBasicBlock(Val: ValueRef) -> BasicBlockRef; - pub fn LLVMGetBasicBlockParent(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMCountBasicBlocks(Fn: ValueRef) -> c_uint; - pub fn LLVMGetBasicBlocks(Fn: ValueRef, BasicBlocks: *const ValueRef); - pub fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef; - pub fn LLVMGetLastBasicBlock(Fn: ValueRef) -> BasicBlockRef; - pub fn LLVMGetNextBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; - pub fn LLVMGetPreviousBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; - pub fn LLVMGetEntryBasicBlock(Fn: ValueRef) -> BasicBlockRef; - - pub fn LLVMAppendBasicBlockInContext(C: ContextRef, - Fn: ValueRef, - Name: *const c_char) - -> BasicBlockRef; - pub fn LLVMInsertBasicBlockInContext(C: ContextRef, - BB: BasicBlockRef, - Name: *const c_char) - -> BasicBlockRef; - pub fn LLVMDeleteBasicBlock(BB: BasicBlockRef); - - pub fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, - MoveAfter: BasicBlockRef); - - pub fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, - MoveBefore: BasicBlockRef); - - /* Operations on instructions */ - pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef; - pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMGetLastInstruction(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; - pub fn LLVMInstructionEraseFromParent(Inst: ValueRef); - - /* Operations on call sites */ - pub fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: c_uint); - pub fn LLVMGetInstructionCallConv(Instr: ValueRef) -> c_uint; - pub fn LLVMAddInstrAttribute(Instr: ValueRef, - index: c_uint, - IA: c_uint); - pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, - index: c_uint, - IA: c_uint); - pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, - index: c_uint, - align: c_uint); - pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, - index: c_uint, - Val: uint64_t); - pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, - index: c_uint, - bytes: uint64_t); - - /* Operations on call instructions (only) */ - pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; - pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); - - /* Operations on load/store instructions (only) */ - pub fn LLVMGetVolatile(MemoryAccessInst: ValueRef) -> Bool; - pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool); - - /* Operations on phi nodes */ - pub fn LLVMAddIncoming(PhiNode: ValueRef, - IncomingValues: *const ValueRef, - IncomingBlocks: *const BasicBlockRef, - Count: c_uint); - pub fn LLVMCountIncoming(PhiNode: ValueRef) -> c_uint; - pub fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: c_uint) - -> ValueRef; - pub fn LLVMGetIncomingBlock(PhiNode: ValueRef, Index: c_uint) - -> BasicBlockRef; - - /* Instruction builders */ - pub fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef; - pub fn LLVMPositionBuilder(Builder: BuilderRef, - Block: BasicBlockRef, - Instr: ValueRef); - pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, - Instr: ValueRef); - pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, - Block: BasicBlockRef); - pub fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef; - pub fn LLVMClearInsertionPosition(Builder: BuilderRef); - pub fn LLVMInsertIntoBuilder(Builder: BuilderRef, Instr: ValueRef); - pub fn LLVMInsertIntoBuilderWithName(Builder: BuilderRef, - Instr: ValueRef, - Name: *const c_char); - pub fn LLVMDisposeBuilder(Builder: BuilderRef); - - /* Metadata */ - pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); - pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; - pub fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef); - - /* Terminators */ - pub fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef; - pub fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef; - pub fn LLVMBuildAggregateRet(B: BuilderRef, - RetVals: *const ValueRef, - N: c_uint) - -> ValueRef; - pub fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef; - pub fn LLVMBuildCondBr(B: BuilderRef, - If: ValueRef, - Then: BasicBlockRef, - Else: BasicBlockRef) - -> ValueRef; - pub fn LLVMBuildSwitch(B: BuilderRef, - V: ValueRef, - Else: BasicBlockRef, - NumCases: c_uint) - -> ValueRef; - pub fn LLVMBuildIndirectBr(B: BuilderRef, - Addr: ValueRef, - NumDests: c_uint) - -> ValueRef; - pub fn LLVMRustBuildInvoke(B: BuilderRef, - Fn: ValueRef, - Args: *const ValueRef, - NumArgs: c_uint, - Then: BasicBlockRef, - Catch: BasicBlockRef, - Bundle: OperandBundleDefRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMRustBuildLandingPad(B: BuilderRef, - Ty: TypeRef, - PersFn: ValueRef, - NumClauses: c_uint, - Name: *const c_char, - F: ValueRef) - -> ValueRef; - pub fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef; - pub fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef; - - pub fn LLVMRustBuildCleanupPad(B: BuilderRef, - ParentPad: ValueRef, - ArgCnt: c_uint, - Args: *const ValueRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustBuildCleanupRet(B: BuilderRef, - CleanupPad: ValueRef, - UnwindBB: BasicBlockRef) -> ValueRef; - pub fn LLVMRustBuildCatchPad(B: BuilderRef, - ParentPad: ValueRef, - ArgCnt: c_uint, - Args: *const ValueRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustBuildCatchRet(B: BuilderRef, - Pad: ValueRef, - BB: BasicBlockRef) -> ValueRef; - pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef, - ParentPad: ValueRef, - BB: BasicBlockRef, - NumHandlers: c_uint, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, - Handler: BasicBlockRef); - pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); - - /* Add a case to the switch instruction */ - pub fn LLVMAddCase(Switch: ValueRef, - OnVal: ValueRef, - Dest: BasicBlockRef); - - /* Add a destination to the indirectbr instruction */ - pub fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); - - /* Add a clause to the landing pad instruction */ - pub fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); - - /* Set the cleanup on a landing pad instruction */ - pub fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); - - /* Arithmetic */ - pub fn LLVMBuildAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildUDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildExactSDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildURem(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSRem(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFRem(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildShl(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildLShr(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildAShr(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildAnd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildOr(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildXor(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildBinOp(B: BuilderRef, - Op: Opcode, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMRustSetHasUnsafeAlgebra(Instr: ValueRef); - - /* Memory */ - pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef; - pub fn LLVMBuildLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *const c_char) - -> ValueRef; - - pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) - -> ValueRef; - - pub fn LLVMBuildGEP(B: BuilderRef, - Pointer: ValueRef, - Indices: *const ValueRef, - NumIndices: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildInBoundsGEP(B: BuilderRef, - Pointer: ValueRef, - Indices: *const ValueRef, - NumIndices: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildStructGEP(B: BuilderRef, - Pointer: ValueRef, - Idx: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildGlobalString(B: BuilderRef, - Str: *const c_char, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildGlobalStringPtr(B: BuilderRef, - Str: *const c_char, - Name: *const c_char) - -> ValueRef; - - /* Casts */ - pub fn LLVMBuildTrunc(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildZExt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSExt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPToUI(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPToSI(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildUIToFP(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSIToFP(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPTrunc(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPExt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildPtrToInt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIntToPtr(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildZExtOrBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSExtOrBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildTruncOrBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildCast(B: BuilderRef, - Op: Opcode, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMBuildPointerCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIntCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - - /* Comparisons */ - pub fn LLVMBuildICmp(B: BuilderRef, - Op: c_uint, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFCmp(B: BuilderRef, - Op: c_uint, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - - /* Miscellaneous instructions */ - pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMRustBuildCall(B: BuilderRef, - Fn: ValueRef, - Args: *const ValueRef, - NumArgs: c_uint, - Bundle: OperandBundleDefRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSelect(B: BuilderRef, - If: ValueRef, - Then: ValueRef, - Else: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildVAArg(B: BuilderRef, - list: ValueRef, - Ty: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildExtractElement(B: BuilderRef, - VecVal: ValueRef, - Index: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildInsertElement(B: BuilderRef, - VecVal: ValueRef, - EltVal: ValueRef, - Index: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildShuffleVector(B: BuilderRef, - V1: ValueRef, - V2: ValueRef, - Mask: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildExtractValue(B: BuilderRef, - AggVal: ValueRef, - Index: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildInsertValue(B: BuilderRef, - AggVal: ValueRef, - EltVal: ValueRef, - Index: c_uint, - Name: *const c_char) - -> ValueRef; - - pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildPtrDiff(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - - /* Atomic Operations */ - pub fn LLVMRustBuildAtomicLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *const c_char, - Order: AtomicOrdering, - Alignment: c_uint) - -> ValueRef; - - pub fn LLVMRustBuildAtomicStore(B: BuilderRef, - Val: ValueRef, - Ptr: ValueRef, - Order: AtomicOrdering, - Alignment: c_uint) - -> ValueRef; - - pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef, - LHS: ValueRef, - CMP: ValueRef, - RHS: ValueRef, - Order: AtomicOrdering, - FailureOrder: AtomicOrdering, - Weak: Bool) - -> ValueRef; - - pub fn LLVMBuildAtomicRMW(B: BuilderRef, - Op: AtomicBinOp, - LHS: ValueRef, - RHS: ValueRef, - Order: AtomicOrdering, - SingleThreaded: Bool) - -> ValueRef; - - pub fn LLVMRustBuildAtomicFence(B: BuilderRef, - Order: AtomicOrdering, - Scope: SynchronizationScope); - - - /* Selected entries from the downcasts. */ - pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; - pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef; - - /// Writes a module to the specified path. Returns 0 on success. - pub fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: *const c_char) -> c_int; - - /// Creates target data from a target layout string. - pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef; - /// Number of bytes clobbered when doing a Store to *T. - pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_ulonglong; - - /// Number of bytes clobbered when doing a Store to *T. - pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) - -> c_ulonglong; - - /// Distance between successive elements in an array of T. Includes ABI padding. - pub fn LLVMABISizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; - - /// Returns the preferred alignment of a type. - pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; - /// Returns the minimum alignment of a type. - pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; - - /// Computes the byte offset of the indexed struct element for a - /// target. - pub fn LLVMOffsetOfElement(TD: TargetDataRef, - StructTy: TypeRef, - Element: c_uint) - -> c_ulonglong; - - /// Returns the minimum alignment of a type when part of a call frame. - pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; - - /// Disposes target data. - pub fn LLVMDisposeTargetData(TD: TargetDataRef); - - /// Creates a pass manager. - pub fn LLVMCreatePassManager() -> PassManagerRef; - - /// Creates a function-by-function pass manager - pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) - -> PassManagerRef; - - /// Disposes a pass manager. - pub fn LLVMDisposePassManager(PM: PassManagerRef); - - /// Runs a pass manager on a module. - pub fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool; - - /// Runs the function passes on the provided function. - pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef) - -> Bool; - - /// Initializes all the function passes scheduled in the manager - pub fn LLVMInitializeFunctionPassManager(FPM: PassManagerRef) -> Bool; - - /// Finalizes all the function passes scheduled in the manager - pub fn LLVMFinalizeFunctionPassManager(FPM: PassManagerRef) -> Bool; - - pub fn LLVMInitializePasses(); - - /// Adds a verification pass. - pub fn LLVMAddVerifierPass(PM: PassManagerRef); - - pub fn LLVMAddGlobalOptimizerPass(PM: PassManagerRef); - pub fn LLVMAddIPSCCPPass(PM: PassManagerRef); - pub fn LLVMAddDeadArgEliminationPass(PM: PassManagerRef); - pub fn LLVMAddInstructionCombiningPass(PM: PassManagerRef); - pub fn LLVMAddCFGSimplificationPass(PM: PassManagerRef); - pub fn LLVMAddFunctionInliningPass(PM: PassManagerRef); - pub fn LLVMAddFunctionAttrsPass(PM: PassManagerRef); - pub fn LLVMAddScalarReplAggregatesPass(PM: PassManagerRef); - pub fn LLVMAddScalarReplAggregatesPassSSA(PM: PassManagerRef); - pub fn LLVMAddJumpThreadingPass(PM: PassManagerRef); - pub fn LLVMAddConstantPropagationPass(PM: PassManagerRef); - pub fn LLVMAddReassociatePass(PM: PassManagerRef); - pub fn LLVMAddLoopRotatePass(PM: PassManagerRef); - pub fn LLVMAddLICMPass(PM: PassManagerRef); - pub fn LLVMAddLoopUnswitchPass(PM: PassManagerRef); - pub fn LLVMAddLoopDeletionPass(PM: PassManagerRef); - pub fn LLVMAddLoopUnrollPass(PM: PassManagerRef); - pub fn LLVMAddGVNPass(PM: PassManagerRef); - pub fn LLVMAddMemCpyOptPass(PM: PassManagerRef); - pub fn LLVMAddSCCPPass(PM: PassManagerRef); - pub fn LLVMAddDeadStoreEliminationPass(PM: PassManagerRef); - pub fn LLVMAddStripDeadPrototypesPass(PM: PassManagerRef); - pub fn LLVMAddConstantMergePass(PM: PassManagerRef); - pub fn LLVMAddArgumentPromotionPass(PM: PassManagerRef); - pub fn LLVMAddTailCallEliminationPass(PM: PassManagerRef); - pub fn LLVMAddIndVarSimplifyPass(PM: PassManagerRef); - pub fn LLVMAddAggressiveDCEPass(PM: PassManagerRef); - pub fn LLVMAddGlobalDCEPass(PM: PassManagerRef); - pub fn LLVMAddCorrelatedValuePropagationPass(PM: PassManagerRef); - pub fn LLVMAddPruneEHPass(PM: PassManagerRef); - pub fn LLVMAddSimplifyLibCallsPass(PM: PassManagerRef); - pub fn LLVMAddLoopIdiomPass(PM: PassManagerRef); - pub fn LLVMAddEarlyCSEPass(PM: PassManagerRef); - pub fn LLVMAddTypeBasedAliasAnalysisPass(PM: PassManagerRef); - pub fn LLVMAddBasicAliasAnalysisPass(PM: PassManagerRef); - - pub fn LLVMPassManagerBuilderCreate() -> PassManagerBuilderRef; - pub fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef); - pub fn LLVMPassManagerBuilderSetOptLevel(PMB: PassManagerBuilderRef, - OptimizationLevel: c_uint); - pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableUnitAtATime( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableUnrollLoops( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderUseInlinerWithThreshold( - PMB: PassManagerBuilderRef, - threshold: c_uint); - pub fn LLVMPassManagerBuilderPopulateModulePassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef); - - pub fn LLVMPassManagerBuilderPopulateFunctionPassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef); - pub fn LLVMPassManagerBuilderPopulateLTOPassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef, - Internalize: Bool, - RunInliner: Bool); - - /// Destroys a memory buffer. - pub fn LLVMDisposeMemoryBuffer(MemBuf: MemoryBufferRef); - - - /* Stuff that's in rustllvm/ because it's not upstream yet. */ - - /// Opens an object file. - pub fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; - /// Closes an object file. - pub fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef); - - /// Enumerates the sections in an object file. - pub fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef; - /// Destroys a section iterator. - pub fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); - /// Returns true if the section iterator is at the end of the section - /// list: - pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, - SI: SectionIteratorRef) - -> Bool; - /// Moves the section iterator to point to the next section. - pub fn LLVMMoveToNextSection(SI: SectionIteratorRef); - /// Returns the current section size. - pub fn LLVMGetSectionSize(SI: SectionIteratorRef) -> c_ulonglong; - /// Returns the current section contents as a string buffer. - pub fn LLVMGetSectionContents(SI: SectionIteratorRef) -> *const c_char; - - /// Reads the given file and returns it as a memory buffer. Use - /// LLVMDisposeMemoryBuffer() to get rid of it. - pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) - -> MemoryBufferRef; - /// Borrows the contents of the memory buffer (doesn't copy it) - pub fn LLVMCreateMemoryBufferWithMemoryRange(InputData: *const c_char, - InputDataLength: size_t, - BufferName: *const c_char, - RequiresNull: Bool) - -> MemoryBufferRef; - pub fn LLVMCreateMemoryBufferWithMemoryRangeCopy(InputData: *const c_char, - InputDataLength: size_t, - BufferName: *const c_char) - -> MemoryBufferRef; - - pub fn LLVMIsMultithreaded() -> Bool; - pub fn LLVMStartMultithreaded() -> Bool; - - /// Returns a string describing the last error caused by an LLVMRust* call. - pub fn LLVMRustGetLastError() -> *const c_char; - - /// Print the pass timings since static dtors aren't picking them up. - pub fn LLVMRustPrintPassTimings(); - - pub fn LLVMStructCreateNamed(C: ContextRef, Name: *const c_char) -> TypeRef; - - pub fn LLVMStructSetBody(StructTy: TypeRef, - ElementTypes: *const TypeRef, - ElementCount: c_uint, - Packed: Bool); - - pub fn LLVMConstNamedStruct(S: TypeRef, - ConstantVals: *const ValueRef, - Count: c_uint) - -> ValueRef; - - /// Enables LLVM debug output. - pub fn LLVMRustSetDebug(Enabled: c_int); - - /// Prepares inline assembly. - pub fn LLVMRustInlineAsm(Ty: TypeRef, - AsmString: *const c_char, - Constraints: *const c_char, - SideEffects: Bool, - AlignStack: Bool, - Dialect: c_uint) - -> ValueRef; - - pub fn LLVMRustDebugMetadataVersion() -> u32; - pub fn LLVMRustVersionMajor() -> u32; - pub fn LLVMRustVersionMinor() -> u32; - - pub fn LLVMRustAddModuleFlag(M: ModuleRef, - name: *const c_char, - value: u32); - - pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; - - pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef); - - pub fn LLVMRustDIBuilderFinalize(Builder: DIBuilderRef); - - pub fn LLVMRustDIBuilderCreateCompileUnit(Builder: DIBuilderRef, - Lang: c_uint, - File: *const c_char, - Dir: *const c_char, - Producer: *const c_char, - isOptimized: bool, - Flags: *const c_char, - RuntimeVer: c_uint, - SplitName: *const c_char) - -> DIDescriptor; - - pub fn LLVMRustDIBuilderCreateFile(Builder: DIBuilderRef, - Filename: *const c_char, - Directory: *const c_char) - -> DIFile; - - pub fn LLVMRustDIBuilderCreateSubroutineType(Builder: DIBuilderRef, - File: DIFile, - ParameterTypes: DIArray) - -> DICompositeType; - - pub fn LLVMRustDIBuilderCreateFunction(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - LinkageName: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - isLocalToUnit: bool, - isDefinition: bool, - ScopeLine: c_uint, - Flags: c_uint, - isOptimized: bool, - Fn: ValueRef, - TParam: DIArray, - Decl: DIDescriptor) - -> DISubprogram; - - pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef, - Name: *const c_char, - SizeInBits: u64, - AlignInBits: u64, - Encoding: c_uint) - -> DIBasicType; - - pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef, - PointeeTy: DIType, - SizeInBits: u64, - AlignInBits: u64, - Name: *const c_char) - -> DIDerivedType; - - pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: u64, - AlignInBits: u64, - Flags: c_uint, - DerivedFrom: DIType, - Elements: DIArray, - RunTimeLang: c_uint, - VTableHolder: DIType, - UniqueId: *const c_char) - -> DICompositeType; - - pub fn LLVMRustDIBuilderCreateMemberType(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNo: c_uint, - SizeInBits: u64, - AlignInBits: u64, - OffsetInBits: u64, - Flags: c_uint, - Ty: DIType) - -> DIDerivedType; - - pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: DIBuilderRef, - Scope: DIScope, - File: DIFile, - Line: c_uint, - Col: c_uint) - -> DILexicalBlock; - - pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef, - Context: DIScope, - Name: *const c_char, - LinkageName: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - isLocalToUnit: bool, - Val: ValueRef, - Decl: DIDescriptor) - -> DIGlobalVariable; - - pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef, - Tag: c_uint, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - AlwaysPreserve: bool, - Flags: c_uint, - AddrOps: *const i64, - AddrOpsCount: c_uint, - ArgNo: c_uint) - -> DIVariable; - - pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef, - Size: u64, - AlignInBits: u64, - Ty: DIType, - Subscripts: DIArray) - -> DIType; - - pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef, - Size: u64, - AlignInBits: u64, - Ty: DIType, - Subscripts: DIArray) - -> DIType; - - pub fn LLVMRustDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef, - Lo: i64, - Count: i64) - -> DISubrange; - - pub fn LLVMRustDIBuilderGetOrCreateArray(Builder: DIBuilderRef, - Ptr: *const DIDescriptor, - Count: c_uint) - -> DIArray; - - pub fn LLVMRustDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, - AddrOps: *const i64, - AddrOpsCount: c_uint, - DL: ValueRef, - InsertAtEnd: BasicBlockRef) - -> ValueRef; - - pub fn LLVMRustDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, - AddrOps: *const i64, - AddrOpsCount: c_uint, - DL: ValueRef, - InsertBefore: ValueRef) - -> ValueRef; - - pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef, - Name: *const c_char, - Val: u64) - -> DIEnumerator; - - pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: u64, - AlignInBits: u64, - Elements: DIArray, - ClassType: DIType) - -> DIType; - - pub fn LLVMRustDIBuilderCreateUnionType(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: u64, - AlignInBits: u64, - Flags: c_uint, - Elements: DIArray, - RunTimeLang: c_uint, - UniqueId: *const c_char) - -> DIType; - - pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool); - - pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - Ty: DIType, - File: DIFile, - LineNo: c_uint, - ColumnNo: c_uint) - -> DITemplateTypeParameter; - - - pub fn LLVMRustDIBuilderCreateNameSpace(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNo: c_uint) - -> DINameSpace; - pub fn LLVMRustDICompositeTypeSetTypeArray(Builder: DIBuilderRef, - CompositeType: DIType, - TypeArray: DIArray); - - - pub fn LLVMRustDIBuilderCreateDebugLocation(Context: ContextRef, - Line: c_uint, - Column: c_uint, - Scope: DIScope, - InlinedAt: MetadataRef) - -> ValueRef; - pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; - pub fn LLVMRustDIBuilderCreateOpPlus() -> i64; - - pub fn LLVMRustWriteTypeToString(Type: TypeRef, s: RustStringRef); - pub fn LLVMRustWriteValueToString(value_ref: ValueRef, s: RustStringRef); - - pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; - - pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; - pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; - - pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind; - pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; - pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); - - pub fn LLVMRustHasFeature(T: TargetMachineRef, - s: *const c_char) -> bool; - - pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, - CPU: *const c_char, - Features: *const c_char, - Model: CodeModel, - Reloc: RelocMode, - Level: CodeGenOptLevel, - UseSoftFP: bool, - PositionIndependentExecutable: bool, - FunctionSections: bool, - DataSections: bool) -> TargetMachineRef; - pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); - pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, - PM: PassManagerRef, - M: ModuleRef); - pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, - M: ModuleRef, - DisableSimplifyLibCalls: bool); - pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef, - OptLevel: CodeGenOptLevel, - MergeFunctions: bool, - SLPVectorize: bool, - LoopVectorize: bool); - pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, - DisableSimplifyLibCalls: bool); - pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); - pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, - PM: PassManagerRef, - M: ModuleRef, - Output: *const c_char, - FileType: FileType) - -> LLVMRustResult; - pub fn LLVMRustPrintModule(PM: PassManagerRef, - M: ModuleRef, - Output: *const c_char); - pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); - pub fn LLVMRustPrintPasses(); - pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); - pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, - AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, - bc: *const c_char, - len: size_t) -> bool; - pub fn LLVMRustRunRestrictionPass(M: ModuleRef, - syms: *const *const c_char, - len: size_t); - pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); - - pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef; - pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef; - pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef) -> ArchiveChildRef; - pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, - size: *mut size_t) -> *const c_char; - pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, - size: *mut size_t) -> *const c_char; - pub fn LLVMRustArchiveChildFree(ACR: ArchiveChildRef); - pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef); - pub fn LLVMRustDestroyArchive(AR: ArchiveRef); - - pub fn LLVMRustSetDLLStorageClass(V: ValueRef, - C: DLLStorageClassTypes); - - pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, - data: *mut *const c_char) -> size_t; - - pub fn LLVMRustWriteTwineToString(T: TwineRef, s: RustStringRef); - - pub fn LLVMContextSetDiagnosticHandler(C: ContextRef, - Handler: DiagnosticHandler, - DiagnosticContext: *mut c_void); - - pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, - pass_name_out: *mut *const c_char, - function_out: *mut ValueRef, - debugloc_out: *mut DebugLocRef, - message_out: *mut TwineRef); - pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, - cookie_out: *mut c_uint, - message_out: *mut TwineRef, - instruction_out: *mut ValueRef); - - pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, - s: RustStringRef); - pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity; - pub fn LLVMRustGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; - - pub fn LLVMRustWriteDebugLocToString(C: ContextRef, - DL: DebugLocRef, - s: RustStringRef); - - pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: ContextRef, - H: InlineAsmDiagHandler, - CX: *mut c_void); - - pub fn LLVMRustWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); - - pub fn LLVMRustWriteArchive(Dst: *const c_char, - NumMembers: size_t, - Members: *const RustArchiveMemberRef, - WriteSymbtab: bool, - Kind: ArchiveKind) -> - LLVMRustResult; - pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, - Name: *const c_char, - Child: ArchiveChildRef) -> RustArchiveMemberRef; - pub fn LLVMRustArchiveMemberFree(Member: RustArchiveMemberRef); - - pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, - TM: TargetMachineRef); - pub fn LLVMRustGetModuleDataLayout(M: ModuleRef) -> TargetDataRef; - - pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char, - Inputs: *const ValueRef, - NumInputs: c_uint) - -> OperandBundleDefRef; - pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef); - - pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef); - - pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char); - pub fn LLVMRustUnsetComdat(V: ValueRef); - pub fn LLVMRustSetModulePIELevel(M: ModuleRef); -} - -// LLVM requires symbols from this library, but apparently they're not printed -// during llvm-config? -#[cfg(windows)] -#[link(name = "ole32")] -extern {} - pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) { unsafe { LLVMSetInstructionCallConv(instr, cc as c_uint); @@ -2254,14 +226,14 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { unsafe { LLVMRustAddFunctionAttribute(fn_, FunctionIndex as c_uint, - attr.bits() as uint64_t) + attr.bits() as u64) } } pub fn RemoveFunctionAttributes(fn_: ValueRef, attr: Attribute) { unsafe { LLVMRustRemoveFunctionAttributes(fn_, FunctionIndex as c_uint, - attr.bits() as uint64_t) + attr.bits() as u64) } } @@ -2359,22 +331,6 @@ pub fn get_params(llfn: ValueRef) -> Vec { } } -#[allow(missing_copy_implementations)] -pub enum RustString_opaque {} -pub type RustStringRef = *mut RustString_opaque; -type RustStringRepr = *mut RefCell>; - -/// Appending to a Rust string -- used by raw_rust_string_ostream. -#[no_mangle] -pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef, - ptr: *const c_char, - size: size_t) { - let slice = slice::from_raw_parts(ptr as *const u8, size as usize); - - let sr = sr as RustStringRepr; - (*sr).borrow_mut().extend_from_slice(slice); -} - pub fn build_string(f: F) -> Option where F: FnOnce(RustStringRef){ let mut buf = RefCell::new(Vec::new()); f(&mut buf as RustStringRepr as RustStringRef); diff --git a/src/librustc_trans/build.rs b/src/librustc_trans/build.rs index 4a7a5736b13a..8cd47bd148d0 100644 --- a/src/librustc_trans/build.rs +++ b/src/librustc_trans/build.rs @@ -12,7 +12,7 @@ #![allow(non_snake_case)] use llvm; -use llvm::{AtomicBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate}; use llvm::{ValueRef, BasicBlockRef}; use common::*; @@ -1117,7 +1117,7 @@ pub fn AtomicCmpXchg(cx: Block, dst: ValueRef, weak: llvm::Bool) -> ValueRef { B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order, weak) } -pub fn AtomicRMW(cx: Block, op: AtomicBinOp, +pub fn AtomicRMW(cx: Block, op: AtomicRmwBinOp, dst: ValueRef, src: ValueRef, order: AtomicOrdering) -> ValueRef { B(cx).atomic_rmw(op, dst, src, order) diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 12809ab26841..28d69d4815fa 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] // FFI wrappers use llvm; -use llvm::{AtomicBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; use base; @@ -1087,7 +1087,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { order, failure_order, weak) } } - pub fn atomic_rmw(&self, op: AtomicBinOp, + pub fn atomic_rmw(&self, op: AtomicRmwBinOp, dst: ValueRef, src: ValueRef, order: AtomicOrdering) -> ValueRef { unsafe { From 3041a97b1acef4f8549d9e297db8deaf571341f2 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 3 Aug 2016 00:25:19 +0300 Subject: [PATCH 295/331] finish type-auditing rustllvm --- src/librustc_llvm/ffi.rs | 71 +++++++++-------- src/librustc_llvm/lib.rs | 116 +++++++++++++++++----------- src/librustc_trans/abi.rs | 8 +- src/librustc_trans/asm.rs | 4 +- src/librustc_trans/attributes.rs | 62 +++++---------- src/librustc_trans/base.rs | 8 +- src/librustc_trans/builder.rs | 2 +- src/librustc_trans/closure.rs | 12 +-- src/librustc_trans/common.rs | 2 +- src/librustc_trans/consts.rs | 16 ++-- src/librustc_trans/debuginfo/gdb.rs | 2 +- src/librustc_trans/declare.rs | 13 ++-- src/librustc_trans/mir/constant.rs | 4 +- src/librustc_trans/monomorphize.rs | 4 +- src/librustc_trans/trans_item.rs | 6 +- src/librustc_trans/type_.rs | 2 +- src/rustllvm/ArchiveWrapper.cpp | 2 +- src/rustllvm/PassWrapper.cpp | 6 +- src/rustllvm/RustWrapper.cpp | 102 +++++++++++++++--------- 19 files changed, 247 insertions(+), 195 deletions(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 53a287ea8ec0..6301c57c5554 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -13,19 +13,20 @@ use debuginfo::{DIBuilderRef, DIDescriptor, DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable, DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator, DINameSpace}; -use RustStringRef; -use libc::{c_uint, c_ushort, c_int, size_t, c_char}; +use libc::{c_uint, c_int, size_t, c_char}; use libc::{c_longlong, c_ulonglong, c_void}; +use RustStringRef; + pub type Opcode = u32; pub type Bool = c_uint; pub const True: Bool = 1 as Bool; pub const False: Bool = 0 as Bool; -#[repr(C)] #[derive(Copy, Clone, PartialEq)] +#[repr(C)] pub enum LLVMRustResult { Success, Failure, @@ -68,8 +69,8 @@ pub enum Linkage { } /// LLVMDiagnosticSeverity -#[repr(C)] #[derive(Copy, Clone, Debug)] +#[repr(C)] pub enum DiagnosticSeverity { Error = 0, Warning = 1, @@ -77,14 +78,13 @@ pub enum DiagnosticSeverity { Note = 3, } -/// LLVMRustDLLStorageClassTypes -#[repr(C)] +/// LLVMDLLStorageClass #[derive(Copy, Clone)] -pub enum DLLStorageClassTypes { - Other, - Default, - DllImport, - DllExport, +#[repr(C)] +pub enum DLLStorageClass { + Default = 0, + DllImport = 1, /* Function to be imported from DLL. */ + DllExport = 2, /* Function to be accessible from DLL. */ } bitflags! { @@ -144,6 +144,7 @@ bitflags! { /// LLVMIntPredicate #[derive(Copy, Clone)] +#[repr(C)] pub enum IntPredicate { IntEQ = 32, IntNE = 33, @@ -159,6 +160,7 @@ pub enum IntPredicate { /// LLVMRealPredicate #[derive(Copy, Clone)] +#[repr(C)] pub enum RealPredicate { RealPredicateFalse = 0, RealOEQ = 1, @@ -178,7 +180,7 @@ pub enum RealPredicate { RealPredicateTrue = 15, } -/// LLVMTypeKind; FIXME: wrap +/// LLVMTypeKind #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] pub enum TypeKind { @@ -198,11 +200,12 @@ pub enum TypeKind { Vector = 13, Metadata = 14, X86_MMX = 15, + Token = 16, } /// LLVMAtomicRmwBinOp -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum AtomicRmwBinOp { AtomicXchg = 0, AtomicAdd = 1, @@ -218,8 +221,8 @@ pub enum AtomicRmwBinOp { } /// LLVMAtomicOrdering -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum AtomicOrdering { NotAtomic = 0, Unordered = 1, @@ -232,8 +235,8 @@ pub enum AtomicOrdering { } /// LLVMRustSynchronizationScope -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum SynchronizationScope { Other, SingleThread, @@ -241,16 +244,18 @@ pub enum SynchronizationScope { } /// LLVMRustFileType -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum FileType { Other, AssemblyFile, ObjectFile, } -/// FIXME: ? +/// Enum pinned in LLVMContext, used in +/// LLVMSetMetadata so ABI-stable. #[derive(Copy, Clone)] +#[repr(C)] pub enum MetadataType { MD_dbg = 0, MD_tbaa = 1, @@ -266,11 +271,13 @@ pub enum MetadataType { MD_nonnull = 11, } -/// FIXME: ? +/// LLVMRustAsmDialect #[derive(Copy, Clone)] +#[repr(C)] pub enum AsmDialect { - AD_ATT = 0, - AD_Intel = 1 + Other, + Att, + Intel, } /// LLVMRustCodeGenOptLevel @@ -295,8 +302,8 @@ pub enum RelocMode { } /// LLVMRustCodeModel -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum CodeModel { Other, Default, @@ -308,8 +315,8 @@ pub enum CodeModel { } /// LLVMRustDiagnosticKind -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum DiagnosticKind { Other, InlineAsm, @@ -326,8 +333,8 @@ pub enum DiagnosticKind { } /// LLVMRustArchiveKind -#[repr(C)] #[derive(Copy, Clone)] +#[repr(C)] pub enum ArchiveKind { Other, K_GNU, @@ -335,6 +342,7 @@ pub enum ArchiveKind { K_BSD, K_COFF, } + /// LLVMRustPassKind #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] @@ -519,7 +527,7 @@ extern { pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); /// See llvm::LLVMTypeKind::getTypeID. - pub fn LLVMGetTypeKind(Ty: TypeRef) -> TypeKind; + pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind; /// See llvm::LLVMType::getContext. pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; @@ -589,8 +597,6 @@ extern { pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char); pub fn LLVMDumpValue(Val: ValueRef); pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); - pub fn LLVMHasMetadata(Val: ValueRef) -> c_int; - pub fn LLVMGetMetadata(Val: ValueRef, KindID: c_uint) -> ValueRef; pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef); /* Operations on Uses */ @@ -608,9 +614,9 @@ extern { pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef; /* all zeroes */ pub fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; - pub fn LLVMConstICmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) + pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef; - pub fn LLVMConstFCmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) + pub fn LLVMConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef; /* only for isize/vector */ pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; @@ -815,13 +821,15 @@ extern { pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool; pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint; - pub fn LLVMSetLinkage(Global: ValueRef, Link: c_uint); + pub fn LLVMSetLinkage(Global: ValueRef, Link: Linkage); pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); + pub fn LLVMSetDLLStorageClass(V: ValueRef, + C: DLLStorageClass); /* Operations on global variables */ @@ -1685,7 +1693,7 @@ extern { Constraints: *const c_char, SideEffects: Bool, AlignStack: Bool, - Dialect: c_uint) + Dialect: AsmDialect) -> ValueRef; pub fn LLVMRustDebugMetadataVersion() -> u32; @@ -1990,9 +1998,6 @@ extern { pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef); pub fn LLVMRustDestroyArchive(AR: ArchiveRef); - pub fn LLVMRustSetDLLStorageClass(V: ValueRef, - C: DLLStorageClassTypes); - pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, data: *mut *const c_char) -> size_t; diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index f451b167196c..6c4e1a54ea72 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -33,13 +33,11 @@ extern crate libc; #[macro_use] #[no_link] extern crate rustc_bitflags; -pub use self::AttributeSet::*; pub use self::IntPredicate::*; pub use self::RealPredicate::*; pub use self::TypeKind::*; pub use self::AtomicRmwBinOp::*; pub use self::MetadataType::*; -pub use self::AsmDialect::*; pub use self::CodeGenOptSize::*; pub use self::DiagnosticKind::*; pub use self::CallConv::*; @@ -50,7 +48,7 @@ use std::str::FromStr; use std::slice; use std::ffi::{CString, CStr}; use std::cell::RefCell; -use libc::{c_uint, c_ushort, c_char, size_t}; +use libc::{c_uint, c_char, size_t}; pub mod archive_ro; pub mod diagnostic; @@ -94,32 +92,64 @@ impl Attributes { self } - pub fn apply_llfn(&self, idx: usize, llfn: ValueRef) { + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { unsafe { - LLVMRustAddFunctionAttribute(llfn, idx as c_uint, self.regular.bits()); + self.regular.apply_llfn(idx, llfn); if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableAttr(llfn, idx as c_uint, - self.dereferenceable_bytes); + LLVMRustAddDereferenceableAttr( + llfn, + idx.as_uint(), + self.dereferenceable_bytes); } } } - pub fn apply_callsite(&self, idx: usize, callsite: ValueRef) { + pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { unsafe { - LLVMRustAddCallSiteAttribute(callsite, idx as c_uint, self.regular.bits()); + self.regular.apply_callsite(idx, callsite); if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableCallSiteAttr(callsite, idx as c_uint, - self.dereferenceable_bytes); + LLVMRustAddDereferenceableCallSiteAttr( + callsite, + idx.as_uint(), + self.dereferenceable_bytes); } } } } +pub fn AddFunctionAttrStringValue( + llfn: ValueRef, + idx: AttributePlace, + attr: &'static str, + value: &'static str +) { + unsafe { + LLVMRustAddFunctionAttrStringValue( + llfn, + idx.as_uint(), + attr.as_ptr() as *const _, + value.as_ptr() as *const _) + } +} + #[repr(C)] #[derive(Copy, Clone)] -pub enum AttributeSet { - ReturnIndex = 0, - FunctionIndex = !0 +pub enum AttributePlace { + Argument(u32), + Function, +} + +impl AttributePlace { + pub fn ReturnValue() -> Self { + AttributePlace::Argument(0) + } + + fn as_uint(self) -> c_uint { + match self { + AttributePlace::Function => !0, + AttributePlace::Argument(i) => i, + } + } } #[derive(Copy, Clone, PartialEq)] @@ -170,11 +200,6 @@ pub fn SetFunctionCallConv(fn_: ValueRef, cc: CallConv) { LLVMSetFunctionCallConv(fn_, cc as c_uint); } } -pub fn SetLinkage(global: ValueRef, link: Linkage) { - unsafe { - LLVMSetLinkage(global, link as c_uint); - } -} // Externally visible symbols that might appear in multiple translation units need to appear in // their own comdat section so that the duplicates can be discarded at link time. This can for @@ -194,12 +219,6 @@ pub fn UnsetComdat(val: ValueRef) { } } -pub fn SetDLLStorageClass(global: ValueRef, class: DLLStorageClassTypes) { - unsafe { - LLVMRustSetDLLStorageClass(global, class); - } -} - pub fn SetUnnamedAddr(global: ValueRef, unnamed: bool) { unsafe { LLVMSetUnnamedAddr(global, unnamed as Bool); @@ -212,29 +231,40 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { } } -pub fn ConstICmp(pred: IntPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { - unsafe { - LLVMConstICmp(pred as c_ushort, v1, v2) +impl Attribute { + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + unsafe { + LLVMRustAddFunctionAttribute( + llfn, idx.as_uint(), self.bits()) + } } -} -pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { - unsafe { - LLVMConstFCmp(pred as c_ushort, v1, v2) - } -} -pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { - unsafe { - LLVMRustAddFunctionAttribute(fn_, FunctionIndex as c_uint, - attr.bits() as u64) + pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { + unsafe { + LLVMRustAddCallSiteAttribute( + callsite, idx.as_uint(), self.bits()) + } } -} -pub fn RemoveFunctionAttributes(fn_: ValueRef, attr: Attribute) { - unsafe { - LLVMRustRemoveFunctionAttributes(fn_, FunctionIndex as c_uint, - attr.bits() as u64) + pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + unsafe { + LLVMRustRemoveFunctionAttributes( + llfn, idx.as_uint(), self.bits()) + } } + + pub fn toggle_llfn(&self, + idx: AttributePlace, + llfn: ValueRef, + set: bool) + { + if set { + self.apply_llfn(idx, llfn); + } else { + self.unapply_llfn(idx, llfn); + } + } + } /* Memory-managed interface to target data. */ diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 6c2a09f8060c..587c03af3abb 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -552,13 +552,13 @@ impl FnType { pub fn apply_attrs_llfn(&self, llfn: ValueRef) { let mut i = if self.ret.is_indirect() { 1 } else { 0 }; if !self.ret.is_ignore() { - self.ret.attrs.apply_llfn(i, llfn); + self.ret.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); } i += 1; for arg in &self.args { if !arg.is_ignore() { if arg.pad.is_some() { i += 1; } - arg.attrs.apply_llfn(i, llfn); + arg.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); i += 1; } } @@ -567,13 +567,13 @@ impl FnType { pub fn apply_attrs_callsite(&self, callsite: ValueRef) { let mut i = if self.ret.is_indirect() { 1 } else { 0 }; if !self.ret.is_ignore() { - self.ret.attrs.apply_callsite(i, callsite); + self.ret.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); } i += 1; for arg in &self.args { if !arg.is_ignore() { if arg.pad.is_some() { i += 1; } - arg.attrs.apply_callsite(i, callsite); + arg.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); i += 1; } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index e27bec683757..5514fb0f4efc 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -83,8 +83,8 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let dialect = match ia.dialect { - AsmDialect::Att => llvm::AD_ATT, - AsmDialect::Intel => llvm::AD_Intel + AsmDialect::Att => llvm::AsmDialect::Att, + AsmDialect::Intel => llvm::AsmDialect::Intel, }; let asm = CString::new(ia.asm.as_bytes()).unwrap(); diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 9c121ae9bfc6..62eac35e0abd 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -9,8 +9,8 @@ // except according to those terms. //! Set and unset common attributes on LLVM values. -use libc::c_uint; -use llvm::{self, ValueRef}; +use llvm::{self, Attribute, ValueRef}; +use llvm::AttributePlace::Function; pub use syntax::attr::InlineAttr; use syntax::ast; use context::CrateContext; @@ -20,14 +20,14 @@ use context::CrateContext; pub fn inline(val: ValueRef, inline: InlineAttr) { use self::InlineAttr::*; match inline { - Hint => llvm::SetFunctionAttribute(val, llvm::Attribute::InlineHint), - Always => llvm::SetFunctionAttribute(val, llvm::Attribute::AlwaysInline), - Never => llvm::SetFunctionAttribute(val, llvm::Attribute::NoInline), + Hint => Attribute::InlineHint.apply_llfn(Function, val), + Always => Attribute::AlwaysInline.apply_llfn(Function, val), + Never => Attribute::NoInline.apply_llfn(Function, val), None => { - let attr = llvm::Attribute::InlineHint | - llvm::Attribute::AlwaysInline | - llvm::Attribute::NoInline; - llvm::RemoveFunctionAttributes(val, attr) + let attr = Attribute::InlineHint | + Attribute::AlwaysInline | + Attribute::NoInline; + attr.unapply_llfn(Function, val) }, }; } @@ -35,56 +35,37 @@ pub fn inline(val: ValueRef, inline: InlineAttr) { /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. #[inline] pub fn emit_uwtable(val: ValueRef, emit: bool) { - if emit { - llvm::SetFunctionAttribute(val, llvm::Attribute::UWTable); - } else { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::UWTable); - } + Attribute::UWTable.toggle_llfn(Function, val, emit); } /// Tell LLVM whether the function can or cannot unwind. #[inline] pub fn unwind(val: ValueRef, can_unwind: bool) { - if can_unwind { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::NoUnwind); - } else { - llvm::SetFunctionAttribute(val, llvm::Attribute::NoUnwind); - } + Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind); } /// Tell LLVM whether it should optimise function for size. #[inline] #[allow(dead_code)] // possibly useful function pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { - if optimize { - llvm::SetFunctionAttribute(val, llvm::Attribute::OptimizeForSize); - } else { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::OptimizeForSize); - } + Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize); } /// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue. #[inline] pub fn naked(val: ValueRef, is_naked: bool) { - if is_naked { - llvm::SetFunctionAttribute(val, llvm::Attribute::Naked); - } else { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::Naked); - } + Attribute::Naked.toggle_llfn(Function, val, is_naked); } pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) { // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a // parameter. if ccx.sess().must_not_eliminate_frame_pointers() { - unsafe { - let attr = "no-frame-pointer-elim\0".as_ptr() as *const _; - let val = "true\0".as_ptr() as *const _; - llvm::LLVMRustAddFunctionAttrStringValue(llfn, - llvm::FunctionIndex as c_uint, - attr, - val); - } + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + "no-frame-pointer-elim\0", + "true\0") } } @@ -98,13 +79,12 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe for attr in attrs { if attr.check_name("cold") { - llvm::Attributes::default().set(llvm::Attribute::Cold) - .apply_llfn(llvm::FunctionIndex as usize, llfn) + Attribute::Cold.apply_llfn(Function, llfn); } else if attr.check_name("naked") { naked(llfn, true); } else if attr.check_name("allocator") { - llvm::Attributes::default().set(llvm::Attribute::NoAlias) - .apply_llfn(llvm::ReturnIndex as usize, llfn) + Attribute::NoAlias.apply_llfn( + llvm::AttributePlace::ReturnValue(), llfn); } else if attr.check_name("unwind") { unwind(llfn, true); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3e66f6de242f..7fb19fefee2d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2347,9 +2347,9 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { - llvm::SetLinkage(val, llvm::InternalLinkage); - llvm::SetDLLStorageClass(val, - llvm::DLLStorageClassTypes::Default); + llvm::LLVMSetLinkage(val, llvm::InternalLinkage); + llvm::LLVMSetDLLStorageClass(val, + llvm::DLLStorageClass::Default); llvm::UnsetComdat(val); } } @@ -2394,7 +2394,7 @@ fn create_imps(cx: &CrateContextList) { imp_name.as_ptr() as *const _); let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref()); llvm::LLVMSetInitializer(imp, init); - llvm::SetLinkage(imp, llvm::ExternalLinkage); + llvm::LLVMSetLinkage(imp, llvm::ExternalLinkage); } } } diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 28d69d4815fa..90f96af54969 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -841,7 +841,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fty = Type::func(&argtys[..], &output); unsafe { let v = llvm::LLVMRustInlineAsm( - fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint); + fty.to_ref(), asm, cons, volatile, alignstack, dia); self.call(v, inputs, None) } } diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 6b9de4a48786..e53a5edfc668 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -249,11 +249,13 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, if !ccx.instances().borrow().contains_key(&instance) { let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); - if ccx.sess().target.target.options.allows_weak_linkage { - llvm::SetLinkage(llfn, llvm::WeakODRLinkage); - llvm::SetUniqueComdat(ccx.llmod(), llfn); - } else { - llvm::SetLinkage(llfn, llvm::InternalLinkage); + unsafe { + if ccx.sess().target.target.options.allows_weak_linkage { + llvm::LLVMSetLinkage(llfn, llvm::WeakODRLinkage); + llvm::SetUniqueComdat(ccx.llmod(), llfn); + } else { + llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage); + } } // set an inline hint for all closures diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 61d8a0837c1d..a1783e9c0a38 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -980,7 +980,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va }); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); - llvm::SetLinkage(g, llvm::InternalLinkage); + llvm::LLVMSetLinkage(g, llvm::InternalLinkage); cx.const_cstr_cache().borrow_mut().insert(s, g); g diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 996efc9c1132..7afb5257258e 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -10,7 +10,7 @@ use llvm; -use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; +use llvm::{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}; @@ -125,7 +125,7 @@ pub fn addr_of_mut(ccx: &CrateContext, }); llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetAlignment(gv, align); - SetLinkage(gv, InternalLinkage); + llvm::LLVMSetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); gv } @@ -637,10 +637,10 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::BiEq | hir::BiNe | hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => { if is_float { let cmp = base::bin_op_to_fcmp_predicate(b.node); - ConstFCmp(cmp, te1, te2) + llvm::LLVMConstFCmp(cmp, te1, te2) } else { let cmp = base::bin_op_to_icmp_predicate(b.node, signed); - ConstICmp(cmp, te1, te2) + llvm::LLVMConstICmp(cmp, te1, te2) } }, } } // unsafe { match b.node { @@ -1072,7 +1072,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) unsafe { // Declare a symbol `foo` with the desired linkage. let g1 = declare::declare_global(ccx, &sym, llty2); - llvm::SetLinkage(g1, linkage); + llvm::LLVMSetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is @@ -1086,7 +1086,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) ccx.sess().span_fatal(span, &format!("symbol `{}` is already defined", &sym)) }); - llvm::SetLinkage(g2, llvm::InternalLinkage); + llvm::LLVMSetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 } @@ -1126,7 +1126,9 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } } if ccx.use_dll_storage_attrs() { - llvm::SetDLLStorageClass(g, llvm::DLLStorageClassTypes::DllImport); + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } } g }; diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_trans/debuginfo/gdb.rs index cf312855d75b..0a8d490dcd2d 100644 --- a/src/librustc_trans/debuginfo/gdb.rs +++ b/src/librustc_trans/debuginfo/gdb.rs @@ -77,7 +77,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); - llvm::SetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); + llvm::LLVMSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. llvm::LLVMSetAlignment(section_var, 1); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 15d90504ee7f..324e8697ecae 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -20,6 +20,7 @@ //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. use llvm::{self, ValueRef}; +use llvm::AttributePlace::Function; use rustc::ty; use abi::{Abi, FnType}; use attributes; @@ -65,16 +66,16 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: if ccx.tcx().sess.opts.cg.no_redzone .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoRedZone) + llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { Some("s") => { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); }, Some("z") => { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::MinSize); - llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize); + llvm::Attribute::MinSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); }, _ => {}, } @@ -111,7 +112,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx)); if sig.output == ty::FnDiverging { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn); + llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } if abi != Abi::Rust && abi != Abi::RustCall { @@ -162,7 +163,7 @@ pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, fn_type: ty::Ty<'tcx>) -> ValueRef { let llfn = define_fn(ccx, name, fn_type); - llvm::SetLinkage(llfn, llvm::InternalLinkage); + unsafe { llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage) }; llfn } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8dc5e5f993fb..00db19d2739c 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -824,11 +824,11 @@ pub fn const_scalar_binop(op: mir::BinOp, mir::BinOp::Gt | mir::BinOp::Ge => { if is_float { let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop()); - llvm::ConstFCmp(cmp, lhs, rhs) + llvm::LLVMConstFCmp(cmp, lhs, rhs) } else { let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(), signed); - llvm::ConstICmp(cmp, lhs, rhs) + llvm::LLVMConstICmp(cmp, lhs, rhs) } } } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 96a05f11bfd1..e9aacaa0f954 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -125,7 +125,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if ccx.shared().translation_items().borrow().contains(&trans_item) { attributes::from_fn_attrs(ccx, attrs, lldecl); - llvm::SetLinkage(lldecl, llvm::ExternalLinkage); + unsafe { + llvm::LLVMSetLinkage(lldecl, llvm::ExternalLinkage); + } } else { // FIXME: #34151 // Normally, getting here would indicate a bug in trans::collector, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index fc2758e50f2c..35bb0481c8e9 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> TransItem<'tcx> { &format!("symbol `{}` is already defined", symbol_name)) }); - llvm::SetLinkage(g, linkage); + unsafe { llvm::LLVMSetLinkage(g, linkage) }; } item => bug!("predefine_static: expected static, found {:?}", item) @@ -250,7 +250,7 @@ impl<'a, 'tcx> TransItem<'tcx> { ref attrs, node: hir::ImplItemKind::Method(..), .. }) => { let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); - llvm::SetLinkage(lldecl, linkage); + unsafe { llvm::LLVMSetLinkage(lldecl, linkage) }; base::set_link_section(ccx, lldecl, attrs); if linkage == llvm::LinkOnceODRLinkage || linkage == llvm::WeakODRLinkage { @@ -287,7 +287,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(declare::get_defined_value(ccx, symbol_name).is_none()); let llfn = declare::declare_cfn(ccx, symbol_name, llfnty); - llvm::SetLinkage(llfn, linkage); + unsafe { llvm::LLVMSetLinkage(llfn, linkage) }; if linkage == llvm::LinkOnceODRLinkage || linkage == llvm::WeakODRLinkage { llvm::SetUniqueComdat(ccx.llmod(), llfn); diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index c09515a51389..d191591e082a 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -208,7 +208,7 @@ impl Type { pub fn kind(&self) -> TypeKind { unsafe { - llvm::LLVMGetTypeKind(self.to_ref()) + llvm::LLVMRustGetTypeKind(self.to_ref()) } } diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 059cc40d5114..1e873b5345c4 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -61,7 +61,7 @@ from_rust(LLVMRustArchiveKind kind) case LLVMRustArchiveKind::COFF: return Archive::K_COFF; default: - abort(); + llvm_unreachable("Bad ArchiveKind."); } } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 9e72724d8ab7..e3dcf45cf0fb 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -196,7 +196,7 @@ from_rust(LLVMRustCodeModel model) case LLVMRustCodeModel::Large: return CodeModel::Large; default: - abort(); + llvm_unreachable("Bad CodeModel."); } } @@ -221,7 +221,7 @@ from_rust(LLVMRustCodeGenOptLevel level) case LLVMRustCodeGenOptLevel::Aggressive: return CodeGenOpt::Aggressive; default: - abort(); + llvm_unreachable("Bad CodeGenOptLevel."); } } @@ -395,7 +395,7 @@ from_rust(LLVMRustFileType type) case LLVMRustFileType::ObjectFile: return TargetMachine::CGFT_ObjectFile; default: - abort(); + llvm_unreachable("Bad FileType."); } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index a9c31bc33e07..0da25e7ac57b 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -263,7 +263,7 @@ from_rust(LLVMRustSynchronizationScope scope) case LLVMRustSynchronizationScope::CrossThread: return CrossThread; default: - abort(); + llvm_unreachable("bad SynchronizationScope."); } } @@ -281,15 +281,34 @@ extern "C" void LLVMRustSetDebug(int Enabled) { #endif } +enum class LLVMRustAsmDialect { + Other, + Att, + Intel, +}; + +static InlineAsm::AsmDialect +from_rust(LLVMRustAsmDialect dialect) +{ + switch (dialect) { + case LLVMRustAsmDialect::Att: + return InlineAsm::AD_ATT; + case LLVMRustAsmDialect::Intel: + return InlineAsm::AD_Intel; + default: + llvm_unreachable("bad AsmDialect."); + } +} + extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, char *Constraints, LLVMBool HasSideEffects, LLVMBool IsAlignStack, - unsigned Dialect) { + LLVMRustAsmDialect Dialect) { return wrap(InlineAsm::get(unwrap(Ty), AsmString, Constraints, HasSideEffects, - IsAlignStack, (InlineAsm::AsmDialect) Dialect)); + IsAlignStack, from_rust(Dialect))); } typedef DIBuilder* LLVMRustDIBuilderRef; @@ -797,35 +816,6 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { return true; } -enum class LLVMRustDLLStorageClassTypes { - Other, - Default, - DllImport, - DllExport, -}; - -static GlobalValue::DLLStorageClassTypes -from_rust(LLVMRustDLLStorageClassTypes Class) -{ - switch (Class) { - case LLVMRustDLLStorageClassTypes::Default: - return GlobalValue::DefaultStorageClass; - case LLVMRustDLLStorageClassTypes::DllImport: - return GlobalValue::DLLImportStorageClass; - case LLVMRustDLLStorageClassTypes::DllExport: - return GlobalValue::DLLExportStorageClass; - default: - abort(); - } -} - -extern "C" void -LLVMRustSetDLLStorageClass(LLVMValueRef Value, - LLVMRustDLLStorageClassTypes Class) { - GlobalValue *V = unwrap(Value); - V->setDLLStorageClass(from_rust(Class)); -} - // Note that the two following functions look quite similar to the // LLVMGetSectionName function. Sadly, it appears that this function only // returns a char* pointer, which isn't guaranteed to be null-terminated. The @@ -955,10 +945,53 @@ to_rust(DiagnosticKind kind) } } - extern "C" LLVMRustDiagnosticKind LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef di) { return to_rust((DiagnosticKind) unwrap(di)->getKind()); } +// This is kept distinct from LLVMGetTypeKind, because when +// a new type kind is added, the Rust-side enum must be +// updated or UB will result. +extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { + switch (unwrap(Ty)->getTypeID()) { + case Type::VoidTyID: + return LLVMVoidTypeKind; + case Type::HalfTyID: + return LLVMHalfTypeKind; + case Type::FloatTyID: + return LLVMFloatTypeKind; + case Type::DoubleTyID: + return LLVMDoubleTypeKind; + case Type::X86_FP80TyID: + return LLVMX86_FP80TypeKind; + case Type::FP128TyID: + return LLVMFP128TypeKind; + case Type::PPC_FP128TyID: + return LLVMPPC_FP128TypeKind; + case Type::LabelTyID: + return LLVMLabelTypeKind; + case Type::MetadataTyID: + return LLVMMetadataTypeKind; + case Type::IntegerTyID: + return LLVMIntegerTypeKind; + case Type::FunctionTyID: + return LLVMFunctionTypeKind; + case Type::StructTyID: + return LLVMStructTypeKind; + case Type::ArrayTyID: + return LLVMArrayTypeKind; + case Type::PointerTyID: + return LLVMPointerTypeKind; + case Type::VectorTyID: + return LLVMVectorTypeKind; + case Type::X86_MMXTyID: + return LLVMX86_MMXTypeKind; +#if LLVM_VERSION_MINOR >= 8 + case Type::TokenTyID: + return LLVMTokenTypeKind; +#endif + } + llvm_unreachable("Unhandled TypeID."); +} extern "C" void LLVMRustWriteDebugLocToString( LLVMContextRef C, @@ -971,7 +1004,6 @@ extern "C" void LLVMRustWriteDebugLocToString( DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) -// FIXME(type-audit): assume this function-pointer type does not change extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( LLVMContextRef C, LLVMContext::InlineAsmDiagHandlerTy H, @@ -1028,8 +1060,6 @@ LLVMRustBuildCleanupRet(LLVMBuilderRef Builder, #endif } -// FIXME: to here. - extern "C" LLVMValueRef LLVMRustBuildCatchPad(LLVMBuilderRef Builder, LLVMValueRef ParentPad, From 06acf16cdb23dad19b9cf816a55df24d4084823c Mon Sep 17 00:00:00 2001 From: Scott A Carr Date: Wed, 3 Aug 2016 11:10:38 -0700 Subject: [PATCH 296/331] reduce rightward drift, add precondition comment --- src/librustc_mir/transform/deaggregator.rs | 35 ++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index ae91123c6926..fccd4a607fdc 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -34,6 +34,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { // Do not trigger on constants. Could be revised in future if let MirSource::Fn(_) = source {} else { return; } + // In fact, we might not want to trigger in other cases. + // Ex: when we could use SROA. See issue #35259 let mut curr: usize = 0; for bb in mir.basic_blocks_mut() { @@ -90,21 +92,24 @@ fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize, for i in curr..statements.len() { let ref statement = statements[i]; let StatementKind::Assign(_, ref rhs) = statement.kind; - if let &Rvalue::Aggregate(ref kind, ref operands) = rhs { - if let &AggregateKind::Adt(adt_def, variant, _) = kind { - if operands.len() > 0 { // don't deaggregate () - if adt_def.variants.len() > 1 { - // only deaggrate structs for now - continue; - } - debug!("getting variant {:?}", variant); - debug!("for adt_def {:?}", adt_def); - let variant_def = &adt_def.variants[variant]; - if variant_def.kind == VariantKind::Struct { - return Some(i); - } - } - } + let (kind, operands) = match rhs { + &Rvalue::Aggregate(ref kind, ref operands) => (kind, operands), + _ => continue, + }; + let (adt_def, variant) = match kind { + &AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant), + _ => continue, + }; + if operands.len() == 0 || adt_def.variants.len() > 1 { + // don't deaggregate () + // don't deaggregate enums ... for now + continue; + } + debug!("getting variant {:?}", variant); + debug!("for adt_def {:?}", adt_def); + let variant_def = &adt_def.variants[variant]; + if variant_def.kind == VariantKind::Struct { + return Some(i); } }; None From 63f0c4de6732b699e2b4ded5fb9a8530a1c8a5ac Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 3 Aug 2016 22:37:57 +0300 Subject: [PATCH 297/331] Support removed LLVM intrinsics by invoking its AutoUpgrade mechanism. --- src/rustllvm/PassWrapper.cpp | 8 ++++++++ src/test/run-pass/simd-upgraded.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/test/run-pass/simd-upgraded.rs diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index e3dcf45cf0fb..3a20bb2714ec 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/Host.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/AutoUpgrade.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSubtargetInfo.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -361,10 +362,17 @@ extern "C" void LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) { llvm::legacy::FunctionPassManager *P = unwrap(PM); P->doInitialization(); + + // Upgrade all calls to old intrinsics first. + for (Module::iterator I = unwrap(M)->begin(), + E = unwrap(M)->end(); I != E;) + UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove + for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E; ++I) if (!I->isDeclaration()) P->run(*I); + P->doFinalization(); } diff --git a/src/test/run-pass/simd-upgraded.rs b/src/test/run-pass/simd-upgraded.rs new file mode 100644 index 000000000000..821a505c1384 --- /dev/null +++ b/src/test/run-pass/simd-upgraded.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that removed LLVM SIMD intrinsics continue +// to work via the "AutoUpgrade" mechanism. + +#![feature(cfg_target_feature, repr_simd)] +#![feature(platform_intrinsics, stmt_expr_attributes)] + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); + +fn main() { + #[cfg(target_feature = "sse2")] unsafe { + extern "platform-intrinsic" { + fn x86_mm_min_epi16(x: i16x8, y: i16x8) -> i16x8; + } + assert_eq!(x86_mm_min_epi16(i16x8(0, 1, 2, 3, 4, 5, 6, 7), + i16x8(7, 6, 5, 4, 3, 2, 1, 0)), + i16x8(0, 1, 2, 3, 3, 2, 1, 0)); + }; +} From d603892ea7649f5b1a31f871a2ddc54c18d6a02b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Aug 2016 20:42:05 +0200 Subject: [PATCH 298/331] Add span method for hir::Generics struct --- src/librustc/hir/mod.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 20bf4f7d3edb..9212fda65025 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -36,7 +36,7 @@ use hir::def::Def; use hir::def_id::DefId; use util::nodemap::{NodeMap, FnvHashSet}; -use syntax_pos::{mk_sp, Span, ExpnId}; +use syntax_pos::{BytePos, mk_sp, Span, ExpnId}; use syntax::codemap::{self, respan, Spanned}; use syntax::abi::Abi; use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect}; @@ -326,6 +326,38 @@ impl Generics { pub fn is_parameterized(&self) -> bool { self.is_lt_parameterized() || self.is_type_parameterized() } + + // Does return a span which includes lifetimes and type parameters, + // not where clause. + pub fn span(&self) -> Option { + if !self.is_parameterized() { + None + } else { + let mut span: Option = None; + for lifetime in self.lifetimes.iter() { + if let Some(ref mut span) = span { + let life_span = lifetime.lifetime.span; + span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi }; + span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo }; + } else { + span = Some(lifetime.lifetime.span.clone()); + } + } + for ty_param in self.ty_params.iter() { + if let Some(ref mut span) = span { + span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo }; + span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi }; + } else { + span = Some(ty_param.span.clone()); + } + } + if let Some(ref mut span) = span { + span.lo = span.lo - BytePos(1); + span.hi = span.hi + BytePos(1); + } + span + } + } } /// A `where` clause in a definition From 9b690c94f042a49f5f06c417cb9c5ab401dd0be8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Aug 2016 20:42:42 +0200 Subject: [PATCH 299/331] Update E0132 to new format --- src/librustc_typeck/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 3b2d02dc861c..6f0892cdcdf1 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -261,8 +261,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, match it.node { hir::ItemFn(_,_,_,_,ref ps,_) if ps.is_parameterized() => { - span_err!(tcx.sess, start_span, E0132, - "start function is not allowed to have type parameters"); + struct_span_err!(tcx.sess, start_span, E0132, + "start function is not allowed to have type parameters") + .span_label(ps.span().unwrap(), + &format!("start function cannot have type parameters")) + .emit(); return; } _ => () From 4fc6f5ac264a58ddaaaf3d2ddfbe011eb675edaf Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Wed, 3 Aug 2016 13:30:28 +0200 Subject: [PATCH 300/331] Add an example to `std::thread::park_timeout` --- src/libstd/thread/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index e9736fea7b37..40d5c7002468 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -478,6 +478,25 @@ pub fn park_timeout_ms(ms: u32) { /// /// Platforms which do not support nanosecond precision for sleeping will have /// `dur` rounded up to the nearest granularity of time they can sleep for. +/// +/// # Example +/// +/// Waiting for the complete expiration of the timeout: +/// +/// ```rust,no_run +/// use std::thread::park_timeout; +/// use std::time::{Instant, Duration}; +/// +/// let timeout = Duration::from_secs(2); +/// let beginning_park = Instant::now(); +/// park_timeout(timeout); +/// +/// while beginning_park.elapsed() < timeout { +/// println!("restarting park_timeout after {:?}", beginning_park.elapsed()); +/// let timeout = timeout - beginning_park.elapsed(); +/// park_timeout(timeout); +/// } +/// ``` #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { let thread = current(); From 20721a4923db5a8a462d8a8229d1f1a13e56e17c Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Wed, 3 Aug 2016 13:34:49 +0200 Subject: [PATCH 301/331] Add link to replacement function --- src/libstd/thread/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 40d5c7002468..f06c105d30e6 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -447,6 +447,8 @@ pub fn park() { *guard = false; } +/// Use [park_timeout]. +/// /// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). /// @@ -456,7 +458,10 @@ pub fn park() { /// preemption or platform differences that may not cause the maximum /// amount of time waited to be precisely `ms` long. /// -/// See the module doc for more detail. +/// See the [module documentation][thread] for more detail. +/// +/// [thread]: index.html +/// [park_timeout]: fn.park_timeout.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] pub fn park_timeout_ms(ms: u32) { From 1607d5b437d613908aee08cb9d2bc7330abf5b96 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Aug 2016 23:13:48 +0200 Subject: [PATCH 302/331] Add note test for E0132 --- src/test/compile-fail/E0132.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/E0132.rs b/src/test/compile-fail/E0132.rs index ff19a577f903..1a33fb24ca1a 100644 --- a/src/test/compile-fail/E0132.rs +++ b/src/test/compile-fail/E0132.rs @@ -12,6 +12,7 @@ #[start] fn f() {} //~ ERROR E0132 + //~| NOTE start function cannot have type parameters fn main() { } From c89e27824f8f30e0c8dd153a9f6bb6a31ddfc65b Mon Sep 17 00:00:00 2001 From: Chris Stankus Date: Wed, 3 Aug 2016 18:00:52 -0500 Subject: [PATCH 303/331] Update error message for E0109 --- src/librustc/middle/astconv_util.rs | 6 ++++-- src/test/compile-fail/E0109.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index e856eb84ff2c..f9a05056a7cf 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -24,8 +24,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) { for segment in segments { for typ in segment.parameters.types() { - span_err!(self.sess, typ.span, E0109, - "type parameters are not allowed on this type"); + struct_span_err!(self.sess, typ.span, E0109, + "type parameters are not allowed on this type") + .span_label(typ.span, &format!("type parameter not allowed")) + .emit(); break; } for lifetime in segment.parameters.lifetimes() { diff --git a/src/test/compile-fail/E0109.rs b/src/test/compile-fail/E0109.rs index 9fc478422504..2e4cbf869269 100644 --- a/src/test/compile-fail/E0109.rs +++ b/src/test/compile-fail/E0109.rs @@ -9,6 +9,7 @@ // except according to those terms. type X = u32; //~ ERROR E0109 + //~| NOTE type parameter not allowed fn main() { } From e5e4cccd3b95783da49cf74116f57d0b0851f719 Mon Sep 17 00:00:00 2001 From: Shantanu Raj Date: Thu, 4 Aug 2016 07:31:06 +0530 Subject: [PATCH 304/331] Update wording on E0080 Change "attempted" to "attempt" --- src/librustc/diagnostics.rs | 2 +- src/librustc_const_math/err.rs | 22 ++++---- src/librustc_trans/expr.rs | 2 +- src/test/compile-fail/const-err-early.rs | 8 +-- src/test/compile-fail/const-err-multi.rs | 2 +- src/test/compile-fail/const-err.rs | 10 ++-- src/test/compile-fail/const-err2.rs | 10 ++-- .../compile-fail/const-eval-overflow-2.rs | 6 +- .../compile-fail/const-eval-overflow-3.rs | 2 +- .../compile-fail/const-eval-overflow-4.rs | 2 +- src/test/compile-fail/const-eval-overflow.rs | 56 +++++++++---------- .../const-len-underflow-separate-spans.rs | 2 +- .../const-len-underflow-subspans.rs | 2 +- src/test/compile-fail/const-tup-index-span.rs | 2 +- src/test/compile-fail/eval-enum.rs | 4 +- src/test/compile-fail/issue-8460-const.rs | 40 ++++++------- .../compile-fail/lint-exceeding-bitshifts.rs | 2 +- src/test/compile-fail/lint-type-overflow2.rs | 2 +- src/test/run-fail/divide-by-zero.rs | 2 +- src/test/run-fail/mod-zero.rs | 2 +- src/test/run-fail/overflowing-add.rs | 2 +- src/test/run-fail/overflowing-lsh-1.rs | 2 +- src/test/run-fail/overflowing-lsh-2.rs | 2 +- src/test/run-fail/overflowing-lsh-3.rs | 2 +- src/test/run-fail/overflowing-lsh-4.rs | 2 +- src/test/run-fail/overflowing-mul.rs | 2 +- src/test/run-fail/overflowing-neg.rs | 2 +- src/test/run-fail/overflowing-pow.rs | 2 +- src/test/run-fail/overflowing-rsh-1.rs | 2 +- src/test/run-fail/overflowing-rsh-2.rs | 2 +- src/test/run-fail/overflowing-rsh-3.rs | 2 +- src/test/run-fail/overflowing-rsh-4.rs | 2 +- src/test/run-fail/overflowing-rsh-5.rs | 2 +- src/test/run-fail/overflowing-rsh-6.rs | 2 +- src/test/run-fail/overflowing-sub.rs | 2 +- 35 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9040e4bf8db5..74e2c90503cd 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -23,7 +23,7 @@ code example: #[deny(const_err)] const X: i32 = 42 / 0; -// error: attempted to divide by zero in a constant expression +// error: attempt to divide by zero in a constant expression ``` "##, diff --git a/src/librustc_const_math/err.rs b/src/librustc_const_math/err.rs index e4eb0f2c97eb..e2e30ef026c2 100644 --- a/src/librustc_const_math/err.rs +++ b/src/librustc_const_math/err.rs @@ -57,18 +57,18 @@ impl ConstMathErr { UnequalTypes(BitOr) => "tried to bitor two values of different types", UnequalTypes(BitXor) => "tried to xor two values of different types", UnequalTypes(_) => unreachable!(), - Overflow(Add) => "attempted to add with overflow", - Overflow(Sub) => "attempted to subtract with overflow", - Overflow(Mul) => "attempted to multiply with overflow", - Overflow(Div) => "attempted to divide with overflow", - Overflow(Rem) => "attempted to calculate the remainder with overflow", - Overflow(Neg) => "attempted to negate with overflow", - Overflow(Shr) => "attempted to shift right with overflow", - Overflow(Shl) => "attempted to shift left with overflow", + Overflow(Add) => "attempt to add with overflow", + Overflow(Sub) => "attempt to subtract with overflow", + Overflow(Mul) => "attempt to multiply with overflow", + Overflow(Div) => "attempt to divide with overflow", + Overflow(Rem) => "attempt to calculate the remainder with overflow", + Overflow(Neg) => "attempt to negate with overflow", + Overflow(Shr) => "attempt to shift right with overflow", + Overflow(Shl) => "attempt to shift left with overflow", Overflow(_) => unreachable!(), - ShiftNegative => "attempted to shift by a negative amount", - DivisionByZero => "attempted to divide by zero", - RemainderByZero => "attempted to calculate the remainder with a divisor of zero", + ShiftNegative => "attempt to shift by a negative amount", + DivisionByZero => "attempt to divide by zero", + RemainderByZero => "attempt to calculate the remainder with a divisor of zero", UnsignedNegation => "unary negation of unsigned integer", ULitOutOfRange(ast::UintTy::U8) => "literal out of range for u8", ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16", diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index b8dd7273a833..2a60dd174467 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -1512,7 +1512,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, C_integral(llty, min, true), debug_loc); with_cond(bcx, is_min, |bcx| { let msg = InternedString::new( - "attempted to negate with overflow"); + "attempt to negate with overflow"); controlflow::trans_fail(bcx, expr_info(expr), msg) }) } else { diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index f666140970b6..42fb40394fb2 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -11,10 +11,10 @@ #![feature(const_indexing)] #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow -pub const B: u8 = 200u8 + 200u8; //~ ERROR attempted to add with overflow -pub const C: u8 = 200u8 * 4; //~ ERROR attempted to multiply with overflow -pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempted to subtract with overflow +pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow +pub const B: u8 = 200u8 + 200u8; //~ ERROR attempt to add with overflow +pub const C: u8 = 200u8 * 4; //~ ERROR attempt to multiply with overflow +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempt to subtract with overflow pub const E: u8 = [5u8][1]; //~^ ERROR index out of bounds: the len is 1 but the index is 1 diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index 7de93a213b02..d4f9c0fe56da 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -10,7 +10,7 @@ #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow +pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow pub const B: i8 = A; pub const C: u8 = A as u8; pub const D: i8 = 50 - A; diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index f2079800cad3..944e458c4c0f 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -30,18 +30,18 @@ const FOO: u8 = [5u8][1]; fn main() { let a = -std::i8::MIN; //~^ WARN this expression will panic at run-time - //~| attempted to negate with overflow + //~| attempt to negate with overflow let b = 200u8 + 200u8 + 200u8; //~^ WARN this expression will panic at run-time - //~| attempted to add with overflow + //~| attempt to add with overflow //~^^^ WARN this expression will panic at run-time - //~| attempted to add with overflow + //~| attempt to add with overflow let c = 200u8 * 4; //~^ WARN this expression will panic at run-time - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow let d = 42u8 - (42u8 + 1); //~^ WARN this expression will panic at run-time - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow let _e = [5u8][1]; //~^ WARN this expression will panic at run-time //~| index out of bounds: the len is 1 but the index is 1 diff --git a/src/test/compile-fail/const-err2.rs b/src/test/compile-fail/const-err2.rs index f0d65f1424c4..7c1fb2ccd472 100644 --- a/src/test/compile-fail/const-err2.rs +++ b/src/test/compile-fail/const-err2.rs @@ -18,14 +18,14 @@ fn black_box(_: T) { fn main() { let a = -std::i8::MIN; - //~^ ERROR attempted to negate with overflow + //~^ ERROR attempt to negate with overflow let b = 200u8 + 200u8 + 200u8; - //~^ ERROR attempted to add with overflow - //~| ERROR attempted to add with overflow + //~^ ERROR attempt to add with overflow + //~| ERROR attempt to add with overflow let c = 200u8 * 4; - //~^ ERROR attempted to multiply with overflow + //~^ ERROR attempt to multiply with overflow let d = 42u8 - (42u8 + 1); - //~^ ERROR attempted to subtract with overflow + //~^ ERROR attempt to subtract with overflow let _e = [5u8][1]; black_box(a); black_box(b); diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 4749457da881..264f02588ae5 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -20,11 +20,11 @@ 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 +//~| attempt to negate with overflow //~| ERROR constant evaluation error -//~| attempted to negate with overflow +//~| attempt to negate with overflow //~| ERROR constant evaluation error -//~| attempted to negate with overflow +//~| attempt to negate with overflow fn main() { match -128i8 { diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs index c78c74e9e231..d930cb770472 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: attempted to add with overflow +// error-pattern: attempt to add with overflow #![allow(unused_imports)] diff --git a/src/test/compile-fail/const-eval-overflow-4.rs b/src/test/compile-fail/const-eval-overflow-4.rs index f1f125adaa7e..67525fc16261 100644 --- a/src/test/compile-fail/const-eval-overflow-4.rs +++ b/src/test/compile-fail/const-eval-overflow-4.rs @@ -23,7 +23,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR error evaluating count: attempted to add with overflow + //~^ ERROR error evaluating count: attempt to add with overflow = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index c1c693544fa9..b8f3f714a84e 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -22,113 +22,113 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8, i8, i8, i8) = (-i8::MIN, //~^ ERROR constant evaluation error - //~| attempted to negate with overflow + //~| attempt to negate with overflow i8::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow i8::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow i8::MIN * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_I16: (i16, i16, i16, i16) = (-i16::MIN, //~^ ERROR constant evaluation error - //~| attempted to negate with overflow + //~| attempt to negate with overflow i16::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow i16::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow i16::MIN * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_I32: (i32, i32, i32, i32) = (-i32::MIN, //~^ ERROR constant evaluation error - //~| attempted to negate with overflow + //~| attempt to negate with overflow i32::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow i32::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow i32::MIN * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_I64: (i64, i64, i64, i64) = (-i64::MIN, //~^ ERROR constant evaluation error - //~| attempted to negate with overflow + //~| attempt to negate with overflow i64::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow i64::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow i64::MAX * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_U8: (u8, u8, u8, u8) = (-(u8::MIN as i8) as u8, u8::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow u8::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow u8::MAX * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_U16: (u16, u16, u16, u16) = (-(u16::MIN as i16) as u16, u16::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow u16::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow u16::MAX * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_U32: (u32, u32, u32, u32) = (-(u32::MIN as i32) as u32, u32::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow u32::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow u32::MAX * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); const VALS_U64: (u64, u64, u64, u64) = (-(u64::MIN as i64) as u64, u64::MIN - 1, //~^ ERROR constant evaluation error - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow u64::MAX + 1, //~^ ERROR constant evaluation error - //~| attempted to add with overflow + //~| attempt to add with overflow u64::MAX * 2, //~^ ERROR constant evaluation error - //~| attempted to multiply with overflow + //~| attempt to multiply with overflow ); fn main() { 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 43375ee3d189..c01bb8267630 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -16,7 +16,7 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; //~^ ERROR E0080 -//~| attempted to subtract with overflow +//~| attempt 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 e338f206553b..7f2229b5a653 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -17,5 +17,5 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); //~^ ERROR constant evaluation error [E0080] - //~| attempted to subtract with overflow + //~| attempt to subtract with overflow } diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 6f095b3041ff..8f7ec9de58af 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -12,7 +12,7 @@ const TUP: (usize,) = 5 << 64; //~^ ERROR E0080 -//~| attempted to shift left with overflow +//~| attempt to shift left with overflow const ARR: [i32; TUP.0] = []; fn main() { diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 57db583aefe2..86cc2c144ac0 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -10,10 +10,10 @@ enum test { div_zero = 1/0, //~ ERROR E0080 - //~| attempted to divide by zero + //~| attempt to divide by zero rem_zero = 1%0, //~^ ERROR E0080 - //~| attempted to calculate the remainder with a divisor of zero + //~| attempt to calculate the remainder with a divisor of zero } fn main() {} diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index fe51d0b69987..d8ab48d1ec3e 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -15,43 +15,43 @@ use std::thread; fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index 6d5abc944e78..3e51550d1fa0 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -53,7 +53,7 @@ fn main() { let n = n << 8; //~ ERROR: bitshift exceeds the type's number of bits let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits - //~^ WARN: attempted to shift by a negative amount + //~^ WARN: attempt to shift by a negative amount let n = 1u8 << (4+3); let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs index e99dfb9aa0f0..a2971f23a79e 100644 --- a/src/test/compile-fail/lint-type-overflow2.rs +++ b/src/test/compile-fail/lint-type-overflow2.rs @@ -15,7 +15,7 @@ #[allow(unused_variables)] fn main() { let x2: i8 = --128; //~ error: literal out of range for i8 - //~^ error: attempted to negate with overflow + //~^ error: attempt to negate with overflow let x = -3.40282348e+38_f32; //~ error: literal out of range for f32 let x = 3.40282348e+38_f32; //~ error: literal out of range for f32 diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs index 3d9bee3c86a5..c9c4a88c9b53 100644 --- a/src/test/run-fail/divide-by-zero.rs +++ b/src/test/run-fail/divide-by-zero.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:attempted to divide by zero +// error-pattern:attempt to divide by zero fn main() { let y = 0; diff --git a/src/test/run-fail/mod-zero.rs b/src/test/run-fail/mod-zero.rs index 686c3eb2f83b..d2b598a7933b 100644 --- a/src/test/run-fail/mod-zero.rs +++ b/src/test/run-fail/mod-zero.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:attempted to calculate the remainder with a divisor of zero +// error-pattern:attempt to calculate the remainder with a divisor of zero fn main() { let y = 0; diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs index ecb8c676cf70..acc7676db457 100644 --- a/src/test/run-fail/overflowing-add.rs +++ b/src/test/run-fail/overflowing-add.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to add with overflow' +// error-pattern:thread 'main' panicked at 'attempt to add with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index e277886d003d..29ce3b0e6a16 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 42cb0f2d55bc..62fc9230f353 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 8c6623dcf50c..1bc1703a89ce 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index 3b7a00a2c73c..8de44f25e048 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions // This function is checking that our automatic truncation does not diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs index 0e168bf6ffbc..a09c0f06a5cc 100644 --- a/src/test/run-fail/overflowing-mul.rs +++ b/src/test/run-fail/overflowing-mul.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs index 84e41ea84880..96853fc565b7 100644 --- a/src/test/run-fail/overflowing-neg.rs +++ b/src/test/run-fail/overflowing-neg.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to negate with overflow' +// error-pattern:thread 'main' panicked at 'attempt to negate with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-fail/overflowing-pow.rs b/src/test/run-fail/overflowing-pow.rs index 9172374ec281..b0ff0df55770 100644 --- a/src/test/run-fail/overflowing-pow.rs +++ b/src/test/run-fail/overflowing-pow.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index d275792485d5..ef4a503cfe42 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index 1b888cddf644..da072b5a9a5a 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index be5c213493d6..0b7809402e6d 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index 820d9611d6ac..1e0cc18fbdcd 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions // This function is checking that our (type-based) automatic diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index b87be696fcb2..690901ff0c25 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index 554675686b5e..6a6ed4f11f20 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs index 1cb207240ca4..083e8d24467f 100644 --- a/src/test/run-fail/overflowing-sub.rs +++ b/src/test/run-fail/overflowing-sub.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to subtract with overflow' +// error-pattern:thread 'main' panicked at 'attempt to subtract with overflow' // compile-flags: -C debug-assertions fn main() { From 61318156f86c828b7d09decf45ea8e40aafbcc25 Mon Sep 17 00:00:00 2001 From: William Lee Date: Thu, 4 Aug 2016 00:32:49 -0400 Subject: [PATCH 305/331] Fixes for issues #35215 and #35216 --- src/librustc_typeck/check/mod.rs | 6 ++++++ src/test/compile-fail/E0060.rs | 2 ++ src/test/compile-fail/E0061.rs | 4 +++- src/test/compile-fail/issue-18819.rs | 1 + src/test/compile-fail/issue-3044.rs | 2 +- src/test/compile-fail/issue-4935.rs | 1 + src/test/compile-fail/method-call-err-msg.rs | 3 +++ src/test/compile-fail/not-enough-arguments.rs | 1 + src/test/compile-fail/overloaded-calls-bad.rs | 2 ++ src/test/compile-fail/variadic-ffi-3.rs | 2 ++ 10 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6062bd048b3d..de81ae26f5dd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2384,6 +2384,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_count, if arg_count == 1 {" was"} else {"s were"}), error_code); + + err.span_label(sp, &format!("expected {}{} parameter{}", + if variadic {"at least "} else {""}, + expected_count, + if expected_count == 1 {""} else {"s"})); + let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::>(); if input_types.len() > 0 { err.note(&format!("the following parameter type{} expected: {}", diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs index b4a289874979..f0aecba8afe5 100644 --- a/src/test/compile-fail/E0060.rs +++ b/src/test/compile-fail/E0060.rs @@ -14,4 +14,6 @@ extern "C" { fn main() { unsafe { printf(); } //~ ERROR E0060 + //~| NOTE expected at least 1 parameter + //~| NOTE the following parameter type was expected } diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs index 4a8eac2a9e22..3d8622647ef2 100644 --- a/src/test/compile-fail/E0061.rs +++ b/src/test/compile-fail/E0061.rs @@ -11,5 +11,7 @@ fn f(a: u16, b: &str) {} fn main() { - f(0); //~ ERROR E0061 + f(0); //~ ERROR E0061 + //~| NOTE expected 2 parameters + //~| NOTE the following parameter types were expected } diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 3591b9824145..b6bdd4c2e65d 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -25,4 +25,5 @@ fn print_x(_: &Foo, extra: &str) { fn main() { print_x(X); //~error this function takes 2 parameters but 1 parameter was supplied //~^ NOTE the following parameter types were expected: &Foo, &str + //~| NOTE expected 2 parameters } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index 68046056fb31..144ceafdbfcd 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -15,6 +15,6 @@ fn main() { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied //~^^^ NOTE the following parameter types were expected - // + //~| NOTE expected 2 parameters // the first error is, um, non-ideal. } diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs index 438d238b6fe6..9ca4de7878ce 100644 --- a/src/test/compile-fail/issue-4935.rs +++ b/src/test/compile-fail/issue-4935.rs @@ -13,3 +13,4 @@ fn foo(a: usize) {} fn main() { foo(5, 6) } //~ ERROR this function takes 1 parameter but 2 parameters were supplied //~^ NOTE the following parameter type was expected +//~| NOTE expected 1 parameter diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs index 212c09364cf4..bcf676dbede6 100644 --- a/src/test/compile-fail/method-call-err-msg.rs +++ b/src/test/compile-fail/method-call-err-msg.rs @@ -20,10 +20,13 @@ impl Foo { fn main() { let x = Foo; x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied + //~^ NOTE expected 0 parameters .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied //~^ NOTE the following parameter type was expected + //~| NOTE expected 1 parameter .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied //~^ NOTE the following parameter types were expected + //~| NOTE expected 2 parameters let y = Foo; y.zero() diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs index 1f5a54477dd6..8dcde2cf48ce 100644 --- a/src/test/compile-fail/not-enough-arguments.rs +++ b/src/test/compile-fail/not-enough-arguments.rs @@ -20,4 +20,5 @@ fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 parameters but 3 //~^^ NOTE the following parameter types were expected + //~| NOTE expected 4 parameters } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 8763fb0913a8..5865d93e1282 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -42,7 +42,9 @@ fn main() { let ans = s(); //~^ ERROR this function takes 1 parameter but 0 parameters were supplied //~| NOTE the following parameter type was expected + //~| NOTE expected 1 parameter let ans = s("burma", "shave"); //~^ ERROR this function takes 1 parameter but 2 parameters were supplied //~| NOTE the following parameter type was expected + //~| NOTE expected 1 parameter } diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index d8620ead8363..cc9a7c84eded 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -18,8 +18,10 @@ fn main() { unsafe { foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied //~^ NOTE the following parameter types were expected + //~| NOTE expected at least 2 parameters foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied //~^ NOTE the following parameter types were expected + //~| NOTE expected at least 2 parameters let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types From 8502c6cb7c7d9fe5624ded221b6a6db1c7693524 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Aug 2016 01:51:52 +0200 Subject: [PATCH 306/331] Add new error code tests --- src/test/compile-fail/E0201.rs | 32 ++++++++++++++++++++++++++++++++ src/test/compile-fail/E0204.rs | 23 +++++++++++++++++++++++ src/test/compile-fail/E0205.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/E0206.rs | 22 ++++++++++++++++++++++ src/test/compile-fail/E0207.rs | 20 ++++++++++++++++++++ src/test/compile-fail/E0214.rs | 13 +++++++++++++ src/test/compile-fail/E0220.rs | 19 +++++++++++++++++++ src/test/compile-fail/E0221.rs | 26 ++++++++++++++++++++++++++ src/test/compile-fail/E0223.rs | 15 +++++++++++++++ src/test/compile-fail/E0225.rs | 13 +++++++++++++ src/test/compile-fail/E0229.rs | 26 ++++++++++++++++++++++++++ src/test/compile-fail/E0232.rs | 17 +++++++++++++++++ src/test/compile-fail/E0243.rs | 15 +++++++++++++++ src/test/compile-fail/E0244.rs | 15 +++++++++++++++ src/test/compile-fail/E0248.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0252.rs | 23 +++++++++++++++++++++++ src/test/compile-fail/E0306.rs | 16 ++++++++++++++++ src/test/compile-fail/E0308-2.rs | 20 ++++++++++++++++++++ src/test/compile-fail/E0308-3.rs | 11 +++++++++++ src/test/compile-fail/E0308-4.rs | 17 +++++++++++++++++ src/test/compile-fail/E0308.rs | 18 ++++++++++++++++++ 21 files changed, 404 insertions(+) create mode 100644 src/test/compile-fail/E0201.rs create mode 100644 src/test/compile-fail/E0204.rs create mode 100644 src/test/compile-fail/E0205.rs create mode 100644 src/test/compile-fail/E0206.rs create mode 100644 src/test/compile-fail/E0207.rs create mode 100644 src/test/compile-fail/E0214.rs create mode 100644 src/test/compile-fail/E0220.rs create mode 100644 src/test/compile-fail/E0221.rs create mode 100644 src/test/compile-fail/E0223.rs create mode 100644 src/test/compile-fail/E0225.rs create mode 100644 src/test/compile-fail/E0229.rs create mode 100644 src/test/compile-fail/E0232.rs create mode 100644 src/test/compile-fail/E0243.rs create mode 100644 src/test/compile-fail/E0244.rs create mode 100644 src/test/compile-fail/E0248.rs create mode 100644 src/test/compile-fail/E0252.rs create mode 100644 src/test/compile-fail/E0306.rs create mode 100644 src/test/compile-fail/E0308-2.rs create mode 100644 src/test/compile-fail/E0308-3.rs create mode 100644 src/test/compile-fail/E0308-4.rs create mode 100644 src/test/compile-fail/E0308.rs diff --git a/src/test/compile-fail/E0201.rs b/src/test/compile-fail/E0201.rs new file mode 100644 index 000000000000..ff6cb55f388c --- /dev/null +++ b/src/test/compile-fail/E0201.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo(u8); + +impl Foo { + fn bar(&self) -> bool { self.0 > 5 } + fn bar() {} //~ ERROR E0201 +} + +trait Baz { + type Quux; + fn baz(&self) -> bool; +} + +impl Baz for Foo { + type Quux = u32; + + fn baz(&self) -> bool { true } + fn baz(&self) -> bool { self.0 > 5 } //~ ERROR E0201 + type Quux = u32; //~ ERROR E0201 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0204.rs b/src/test/compile-fail/E0204.rs new file mode 100644 index 000000000000..2fa2afa12eb4 --- /dev/null +++ b/src/test/compile-fail/E0204.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. + +struct Foo { + foo: Vec, +} + +impl Copy for Foo { } //~ ERROR E0204 + +#[derive(Copy)] //~ ERROR E0204 +struct Foo2<'a> { + ty: &'a mut bool, +} + +fn main() { +} diff --git a/src/test/compile-fail/E0205.rs b/src/test/compile-fail/E0205.rs new file mode 100644 index 000000000000..e4781bba08aa --- /dev/null +++ b/src/test/compile-fail/E0205.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + Bar(Vec), + Baz, +} + +impl Copy for Foo { } //~ ERROR E0205 + +#[derive(Copy)] //~ ERROR E0205 +enum Foo2<'a> { + Bar(&'a mut bool), + Baz, +} + +fn main() { +} diff --git a/src/test/compile-fail/E0206.rs b/src/test/compile-fail/E0206.rs new file mode 100644 index 000000000000..31b01da3d75b --- /dev/null +++ b/src/test/compile-fail/E0206.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Foo = i32; + +impl Copy for Foo { } //~ ERROR E0206 + //~^ ERROR E0117 + +#[derive(Copy, Clone)] +struct Bar; + +impl Copy for &'static Bar { } //~ ERROR E0206 + +fn main() { +} diff --git a/src/test/compile-fail/E0207.rs b/src/test/compile-fail/E0207.rs new file mode 100644 index 000000000000..bd87dbaf786a --- /dev/null +++ b/src/test/compile-fail/E0207.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. + +struct Foo; + +impl Foo { //~ ERROR E0207 + fn get(&self) -> T { + ::default() + } +} + +fn main() { +} diff --git a/src/test/compile-fail/E0214.rs b/src/test/compile-fail/E0214.rs new file mode 100644 index 000000000000..59609345ee52 --- /dev/null +++ b/src/test/compile-fail/E0214.rs @@ -0,0 +1,13 @@ +// 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() { + let v: Vec(&str) = vec!["foo"]; //~ ERROR E0214 +} diff --git a/src/test/compile-fail/E0220.rs b/src/test/compile-fail/E0220.rs new file mode 100644 index 000000000000..17e2b18b3745 --- /dev/null +++ b/src/test/compile-fail/E0220.rs @@ -0,0 +1,19 @@ +// 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. + +trait Trait { + type Bar; +} + +type Foo = Trait; //~ ERROR E0220 + //~^ ERROR E0191 + +fn main() { +} diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs new file mode 100644 index 000000000000..213ec5a04888 --- /dev/null +++ b/src/test/compile-fail/E0221.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. + +trait T1 {} +trait T2 {} + +trait Foo { + type A: T1; +} + +trait Bar : Foo { + type A: T2; + fn do_something() { + let _: Self::A; //~ ERROR E0221 + } +} + +fn main() { +} diff --git a/src/test/compile-fail/E0223.rs b/src/test/compile-fail/E0223.rs new file mode 100644 index 000000000000..bbf7d762ef00 --- /dev/null +++ b/src/test/compile-fail/E0223.rs @@ -0,0 +1,15 @@ +// 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. + +trait MyTrait { type X; } + +fn main() { + let foo: MyTrait::X; //~ ERROR E0223 +} diff --git a/src/test/compile-fail/E0225.rs b/src/test/compile-fail/E0225.rs new file mode 100644 index 000000000000..190350c5a557 --- /dev/null +++ b/src/test/compile-fail/E0225.rs @@ -0,0 +1,13 @@ +// 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() { + let _: Box; //~ ERROR E0225 +} diff --git a/src/test/compile-fail/E0229.rs b/src/test/compile-fail/E0229.rs new file mode 100644 index 000000000000..45d5c59592f7 --- /dev/null +++ b/src/test/compile-fail/E0229.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. + +pub trait Foo { + type A; + fn boo(&self) -> ::A; +} + +struct Bar; + +impl Foo for isize { + type A = usize; + fn boo(&self) -> usize { 42 } +} + +fn baz(x: &>::A) {} //~ ERROR E0229 + +fn main() { +} diff --git a/src/test/compile-fail/E0232.rs b/src/test/compile-fail/E0232.rs new file mode 100644 index 000000000000..efeb869d71fa --- /dev/null +++ b/src/test/compile-fail/E0232.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(on_unimplemented)] + +#[rustc_on_unimplemented] //~ ERROR E0232 +trait Bar {} + +fn main() { +} diff --git a/src/test/compile-fail/E0243.rs b/src/test/compile-fail/E0243.rs new file mode 100644 index 000000000000..8cc245c10cbe --- /dev/null +++ b/src/test/compile-fail/E0243.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { x: T } +struct Bar { x: Foo } //~ ERROR E0243 + +fn main() { +} diff --git a/src/test/compile-fail/E0244.rs b/src/test/compile-fail/E0244.rs new file mode 100644 index 000000000000..4c5744710929 --- /dev/null +++ b/src/test/compile-fail/E0244.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { x: bool } +struct Bar { x: Foo } //~ ERROR E0244 + +fn main() { +} diff --git a/src/test/compile-fail/E0248.rs b/src/test/compile-fail/E0248.rs new file mode 100644 index 000000000000..fdfd41a456bf --- /dev/null +++ b/src/test/compile-fail/E0248.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + Bar(u32), +} + +fn do_something(x: Foo::Bar) { } //~ ERROR E0248 + +fn main() { +} diff --git a/src/test/compile-fail/E0252.rs b/src/test/compile-fail/E0252.rs new file mode 100644 index 000000000000..6b353c8cd1a6 --- /dev/null +++ b/src/test/compile-fail/E0252.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. + +use foo::baz; +use bar::baz; //~ ERROR E0252 + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} + +fn main() { +} diff --git a/src/test/compile-fail/E0306.rs b/src/test/compile-fail/E0306.rs new file mode 100644 index 000000000000..61cc8902036e --- /dev/null +++ b/src/test/compile-fail/E0306.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. + +const A: [u32; "hello"] = []; //~ ERROR E0306 +const B: [u32; true] = []; //~ ERROR E0306 +const C: [u32; 0.0] = []; //~ ERROR E0306 + +fn main() { +} diff --git a/src/test/compile-fail/E0308-2.rs b/src/test/compile-fail/E0308-2.rs new file mode 100644 index 000000000000..8c9fc9551561 --- /dev/null +++ b/src/test/compile-fail/E0308-2.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. + +use std::rc::Rc; + +struct Foo; + +impl Foo { + fn x(self: Rc) {} //~ ERROR E0308 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0308-3.rs b/src/test/compile-fail/E0308-3.rs new file mode 100644 index 000000000000..d7dca056f3fa --- /dev/null +++ b/src/test/compile-fail/E0308-3.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() -> i32 { 0 } //~ ERROR E0308 diff --git a/src/test/compile-fail/E0308-4.rs b/src/test/compile-fail/E0308-4.rs new file mode 100644 index 000000000000..bb4cd1434167 --- /dev/null +++ b/src/test/compile-fail/E0308-4.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = 1u8; + match x { + 0u8...3i8 => (), //~ ERROR E0308 + _ => () + } +} diff --git a/src/test/compile-fail/E0308.rs b/src/test/compile-fail/E0308.rs new file mode 100644 index 000000000000..078f1d3a9a1a --- /dev/null +++ b/src/test/compile-fail/E0308.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of(); //~ ERROR E0308 +} + +fn main() { +} From 0e756840f0625f06a5e150528820e96316f7929f Mon Sep 17 00:00:00 2001 From: William Lee Date: Thu, 4 Aug 2016 08:07:14 -0400 Subject: [PATCH 307/331] Tidying up some of the line spacing / code formatting for NOTE/ERROR annotation to match other files. --- src/test/compile-fail/E0060.rs | 7 ++++--- src/test/compile-fail/E0061.rs | 7 ++++--- src/test/compile-fail/issue-18819.rs | 5 +++-- src/test/compile-fail/issue-3044.rs | 2 +- src/test/compile-fail/issue-4935.rs | 5 +++-- src/test/compile-fail/not-enough-arguments.rs | 2 +- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs index f0aecba8afe5..342ad3f2148a 100644 --- a/src/test/compile-fail/E0060.rs +++ b/src/test/compile-fail/E0060.rs @@ -13,7 +13,8 @@ extern "C" { } fn main() { - unsafe { printf(); } //~ ERROR E0060 - //~| NOTE expected at least 1 parameter - //~| NOTE the following parameter type was expected + unsafe { printf(); } + //~^ ERROR E0060 + //~| NOTE expected at least 1 parameter + //~| NOTE the following parameter type was expected } diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs index 3d8622647ef2..83b32200019f 100644 --- a/src/test/compile-fail/E0061.rs +++ b/src/test/compile-fail/E0061.rs @@ -11,7 +11,8 @@ fn f(a: u16, b: &str) {} fn main() { - f(0); //~ ERROR E0061 - //~| NOTE expected 2 parameters - //~| NOTE the following parameter types were expected + f(0); + //~^ ERROR E0061 + //~| NOTE expected 2 parameters + //~| NOTE the following parameter types were expected } diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index b6bdd4c2e65d..0310b4ea75fe 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -23,7 +23,8 @@ fn print_x(_: &Foo, extra: &str) { } fn main() { - print_x(X); //~error this function takes 2 parameters but 1 parameter was supplied - //~^ NOTE the following parameter types were expected: &Foo, &str + print_x(X); + //~^ ERROR this function takes 2 parameters but 1 parameter was supplied + //~| NOTE the following parameter types were expected: &Foo, &str //~| NOTE expected 2 parameters } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index 144ceafdbfcd..d19e3b2c7b0a 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -14,7 +14,7 @@ fn main() { needlesArr.iter().fold(|x, y| { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied - //~^^^ NOTE the following parameter types were expected + //~| NOTE the following parameter types were expected //~| NOTE expected 2 parameters // the first error is, um, non-ideal. } diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs index 9ca4de7878ce..58a84f3490b3 100644 --- a/src/test/compile-fail/issue-4935.rs +++ b/src/test/compile-fail/issue-4935.rs @@ -11,6 +11,7 @@ // Regression test for issue #4935 fn foo(a: usize) {} -fn main() { foo(5, 6) } //~ ERROR this function takes 1 parameter but 2 parameters were supplied -//~^ NOTE the following parameter type was expected +fn main() { foo(5, 6) } +//~^ ERROR this function takes 1 parameter but 2 parameters were supplied +//~| NOTE the following parameter type was expected //~| NOTE expected 1 parameter diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs index 8dcde2cf48ce..f2f61fcaeec1 100644 --- a/src/test/compile-fail/not-enough-arguments.rs +++ b/src/test/compile-fail/not-enough-arguments.rs @@ -19,6 +19,6 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 parameters but 3 - //~^^ NOTE the following parameter types were expected + //~| NOTE the following parameter types were expected //~| NOTE expected 4 parameters } From ded0d512dc663c774d849cd9836212ff69e56f5c Mon Sep 17 00:00:00 2001 From: William Lee Date: Thu, 4 Aug 2016 08:28:48 -0400 Subject: [PATCH 308/331] Removing trailing whitespace leftover from last re-formatting commit --- src/test/compile-fail/E0060.rs | 2 +- src/test/compile-fail/E0061.rs | 2 +- src/test/compile-fail/issue-18819.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs index 342ad3f2148a..e1f2618c180f 100644 --- a/src/test/compile-fail/E0060.rs +++ b/src/test/compile-fail/E0060.rs @@ -13,7 +13,7 @@ extern "C" { } fn main() { - unsafe { printf(); } + unsafe { printf(); } //~^ ERROR E0060 //~| NOTE expected at least 1 parameter //~| NOTE the following parameter type was expected diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs index 83b32200019f..ca04b059dc7f 100644 --- a/src/test/compile-fail/E0061.rs +++ b/src/test/compile-fail/E0061.rs @@ -12,7 +12,7 @@ fn f(a: u16, b: &str) {} fn main() { f(0); - //~^ ERROR E0061 + //~^ ERROR E0061 //~| NOTE expected 2 parameters //~| NOTE the following parameter types were expected } diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 0310b4ea75fe..cf650460c3de 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -23,7 +23,7 @@ fn print_x(_: &Foo, extra: &str) { } fn main() { - print_x(X); + print_x(X); //~^ ERROR this function takes 2 parameters but 1 parameter was supplied //~| NOTE the following parameter types were expected: &Foo, &str //~| NOTE expected 2 parameters From 7fc0b2f3e29e9d2d4bcdbd82864864da21ddee8c Mon Sep 17 00:00:00 2001 From: Yossi Konstantinovsky Date: Thu, 4 Aug 2016 16:19:52 +0300 Subject: [PATCH 309/331] Update E0079 to new format --- src/librustc_typeck/collect.rs | 1 + src/test/compile-fail/E0079.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4486748a1f05..d59f07f6c5d6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1057,6 +1057,7 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let print_err = |cv: ConstVal| { struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types") .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description())) + .span_label(e.span, &format!("expected '{}' type", ty_hint)) .emit(); }; diff --git a/src/test/compile-fail/E0079.rs b/src/test/compile-fail/E0079.rs index 23957c72ff00..c9b7f549d5aa 100644 --- a/src/test/compile-fail/E0079.rs +++ b/src/test/compile-fail/E0079.rs @@ -10,6 +10,7 @@ enum Foo { Q = "32" //~ ERROR E0079 + //~^ expected 'isize' type } fn main() { From ee8d6b07091e762fbef8a3465806b48201ec5a2e Mon Sep 17 00:00:00 2001 From: Roy Brunton Date: Thu, 4 Aug 2016 15:13:46 +0100 Subject: [PATCH 310/331] Update error message for E0172 --- src/librustc_typeck/astconv.rs | 6 ++++-- src/test/compile-fail/E0172.rs | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3b2bca4ab391..744b4296ade2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1075,8 +1075,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Ok((trait_ref, projection_bounds)) } _ => { - span_err!(self.tcx().sess, ty.span, E0172, - "expected a reference to a trait"); + struct_span_err!(self.tcx().sess, ty.span, E0172, + "expected a reference to a trait") + .span_label(ty.span, &format!("expected a trait")) + .emit(); Err(ErrorReported) } } diff --git a/src/test/compile-fail/E0172.rs b/src/test/compile-fail/E0172.rs index 7011bf0e9373..485a31d96663 100644 --- a/src/test/compile-fail/E0172.rs +++ b/src/test/compile-fail/E0172.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(bar: i32+std::fmt::Display) {} //~ ERROR E0172 +fn foo(bar: i32+std::fmt::Display) {} + //~^ ERROR E0172 + //~| NOTE expected a trait fn main() { } From 08ff7a80c06037d5fcdc0a4124c937c02d419d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Medzi=C5=84ski?= Date: Thu, 4 Aug 2016 16:24:39 +0200 Subject: [PATCH 311/331] Update error message E0178 --- src/librustc_typeck/astconv.rs | 1 + src/test/compile-fail/E0178.rs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3b2bca4ab391..01aa0740c0e6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1086,6 +1086,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { "expected a path on the left-hand side \ of `+`, not `{}`", pprust::ty_to_string(ty)); + err.span_label(ty.span, &format!("expected a path")); let hi = bounds.iter().map(|x| match *x { hir::TraitTyParamBound(ref tr, _) => tr.span.hi, hir::RegionTyParamBound(ref r) => r.span.hi, diff --git a/src/test/compile-fail/E0178.rs b/src/test/compile-fail/E0178.rs index f34f3834e05b..6527465e0b7f 100644 --- a/src/test/compile-fail/E0178.rs +++ b/src/test/compile-fail/E0178.rs @@ -11,10 +11,18 @@ trait Foo {} struct Bar<'a> { - w: &'a Foo + Copy, //~ ERROR E0178 - x: &'a Foo + 'a, //~ ERROR E0178 - y: &'a mut Foo + 'a, //~ ERROR E0178 - z: fn() -> Foo + 'a, //~ ERROR E0178 + w: &'a Foo + Copy, + //~^ ERROR E0178 + //~| NOTE expected a path + x: &'a Foo + 'a, + //~^ ERROR E0178 + //~| NOTE expected a path + y: &'a mut Foo + 'a, + //~^ ERROR E0178 + //~| NOTE expected a path + z: fn() -> Foo + 'a, + //~^ ERROR E0178 + //~| NOTE expected a path } fn main() { From eeda69fcca2c554bd60072476292b37fccb01a61 Mon Sep 17 00:00:00 2001 From: saml Date: Thu, 4 Aug 2016 10:42:01 -0400 Subject: [PATCH 312/331] Set label for unreachable pattern Part of #35233 Fixes #35190 r? @jonathandturner --- src/librustc_const_eval/check_match.rs | 1 + src/test/compile-fail/issue-31221.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index d3952de2fbe3..6528525a6104 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -335,6 +335,7 @@ fn check_arms(cx: &MatchCheckCtxt, hir::MatchSource::Normal => { let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"); + err.span_label(pat.span, &format!("this is unreachable pattern")); // if we had a catchall pattern, hint at that for row in &seen.0 { if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) { diff --git a/src/test/compile-fail/issue-31221.rs b/src/test/compile-fail/issue-31221.rs index 2b3df9ad1d83..85eac907105b 100644 --- a/src/test/compile-fail/issue-31221.rs +++ b/src/test/compile-fail/issue-31221.rs @@ -22,6 +22,7 @@ fn main() { //~^ NOTE this pattern matches any value Var2 => (), //~^ ERROR unreachable pattern + //~^^ NOTE this is unreachable pattern }; match &s { &Var1 => (), @@ -29,6 +30,7 @@ fn main() { //~^ NOTE this pattern matches any value &Var2 => (), //~^ ERROR unreachable pattern + //~^^ NOTE this is unreachable pattern }; let t = (Var1, Var1); match t { @@ -37,6 +39,7 @@ fn main() { //~^ NOTE this pattern matches any value anything => () //~^ ERROR unreachable pattern + //~^^ NOTE this is unreachable pattern }; // `_` need not emit a note, it is pretty obvious already. let t = (Var1, Var1); @@ -45,5 +48,6 @@ fn main() { _ => (), anything => () //~^ ERROR unreachable pattern + //~^^ NOTE this is unreachable pattern }; } From 034e6594112114897b243cb2cc2944c91c28d529 Mon Sep 17 00:00:00 2001 From: saml Date: Thu, 4 Aug 2016 11:22:02 -0400 Subject: [PATCH 313/331] Changing label to "this is an..." --- src/librustc_const_eval/check_match.rs | 2 +- src/test/compile-fail/issue-31221.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 6528525a6104..d148d2a0885e 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -335,7 +335,7 @@ fn check_arms(cx: &MatchCheckCtxt, hir::MatchSource::Normal => { let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"); - err.span_label(pat.span, &format!("this is unreachable pattern")); + err.span_label(pat.span, &format!("this is an unreachable pattern")); // if we had a catchall pattern, hint at that for row in &seen.0 { if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) { diff --git a/src/test/compile-fail/issue-31221.rs b/src/test/compile-fail/issue-31221.rs index 85eac907105b..4997a6fee195 100644 --- a/src/test/compile-fail/issue-31221.rs +++ b/src/test/compile-fail/issue-31221.rs @@ -22,7 +22,7 @@ fn main() { //~^ NOTE this pattern matches any value Var2 => (), //~^ ERROR unreachable pattern - //~^^ NOTE this is unreachable pattern + //~^^ NOTE this is an unreachable pattern }; match &s { &Var1 => (), @@ -30,7 +30,7 @@ fn main() { //~^ NOTE this pattern matches any value &Var2 => (), //~^ ERROR unreachable pattern - //~^^ NOTE this is unreachable pattern + //~^^ NOTE this is an unreachable pattern }; let t = (Var1, Var1); match t { @@ -39,7 +39,7 @@ fn main() { //~^ NOTE this pattern matches any value anything => () //~^ ERROR unreachable pattern - //~^^ NOTE this is unreachable pattern + //~^^ NOTE this is an unreachable pattern }; // `_` need not emit a note, it is pretty obvious already. let t = (Var1, Var1); @@ -48,6 +48,6 @@ fn main() { _ => (), anything => () //~^ ERROR unreachable pattern - //~^^ NOTE this is unreachable pattern + //~^^ NOTE this is an unreachable pattern }; } From 7c58b26f704b60eaac2a872cb4a6268ad4d1a458 Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Wed, 3 Aug 2016 22:13:07 +0200 Subject: [PATCH 314/331] Updated E0071 to new format. The span underlines only the name of the thing that's not a struct rather than the whole expression. --- src/librustc_typeck/check/mod.rs | 9 ++++++--- src/test/compile-fail/E0071.rs | 9 +++++++-- src/test/compile-fail/trait-as-struct-constructor.rs | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6062bd048b3d..6081ef9964c2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3147,9 +3147,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple { // Reject tuple structs for now, braced and unit structs are allowed. - span_err!(self.tcx.sess, span, E0071, - "`{}` does not name a struct or a struct variant", - pprust::path_to_string(path)); + struct_span_err!(self.tcx.sess, path.span, E0071, + "`{}` does not name a struct or a struct variant", + pprust::path_to_string(path)) + .span_label(path.span, &format!("not a struct")) + .emit(); + return None; } diff --git a/src/test/compile-fail/E0071.rs b/src/test/compile-fail/E0071.rs index 658c8fb15511..6f0e55efffc9 100644 --- a/src/test/compile-fail/E0071.rs +++ b/src/test/compile-fail/E0071.rs @@ -11,6 +11,11 @@ enum Foo { FirstValue(i32) } fn main() { - let u = Foo::FirstValue { value: 0 }; //~ ERROR E0071 - let t = u32 { value: 4 }; //~ ERROR E0071 + let u = Foo::FirstValue { value: 0 }; + //~^ ERROR `Foo::FirstValue` does not name a struct or a struct variant [E0071] + //~| NOTE not a struct + + let t = u32 { value: 4 }; + //~^ ERROR `u32` does not name a struct or a struct variant [E0071] + //~| NOTE not a struct } diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs index 13fdaa302f70..c78eebddbfdb 100644 --- a/src/test/compile-fail/trait-as-struct-constructor.rs +++ b/src/test/compile-fail/trait-as-struct-constructor.rs @@ -13,4 +13,5 @@ trait TraitNotAStruct {} fn main() { TraitNotAStruct{ value: 0 }; //~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071] + //~| NOTE not a struct } From 5430e555f5eba563a8f99c8ebab641abfb0642c8 Mon Sep 17 00:00:00 2001 From: Chris Stankus Date: Thu, 4 Aug 2016 10:47:39 -0500 Subject: [PATCH 315/331] E0110 update error format --- src/librustc/middle/astconv_util.rs | 7 +++++-- src/test/compile-fail/E0110.rs | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index e856eb84ff2c..487f2d17cd97 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -29,8 +29,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { break; } for lifetime in segment.parameters.lifetimes() { - span_err!(self.sess, lifetime.span, E0110, - "lifetime parameters are not allowed on this type"); + struct_span_err!(self.sess, lifetime.span, E0110, + "lifetime parameters are not allowed on this type") + .span_label(lifetime.span, + &format!("lifetime parameter not allowed on this type")) + .emit(); break; } for binding in segment.parameters.bindings() { diff --git a/src/test/compile-fail/E0110.rs b/src/test/compile-fail/E0110.rs index fd169f4acc5e..5a9e7a43de96 100644 --- a/src/test/compile-fail/E0110.rs +++ b/src/test/compile-fail/E0110.rs @@ -9,6 +9,7 @@ // except according to those terms. type X = u32<'static>; //~ ERROR E0110 + //~| NOTE lifetime parameter not allowed on this type fn main() { } From fbabe616413d34c1ab68668de34de4322d963b93 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 4 Aug 2016 19:57:57 +0300 Subject: [PATCH 316/331] rustc_trans: don't Assert(Overflow(Neg)) when overflow checks are off. --- src/librustc_trans/mir/block.rs | 18 +++++++++++++++++- src/test/run-pass/mir_overflow_off.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/mir_overflow_off.rs diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 2d1769b8637b..9bfdb511c623 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -261,7 +261,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { let cond = self.trans_operand(&bcx, cond).immediate(); - let const_cond = common::const_to_opt_uint(cond).map(|c| c == 1); + let mut const_cond = common::const_to_opt_uint(cond).map(|c| c == 1); + + // This case can currently arise only from functions marked + // with #[rustc_inherit_overflow_checks] and inlined from + // another crate (mostly core::num generic/#[inline] fns), + // while the current crate doesn't use overflow checks. + // NOTE: Unlike binops, negation doesn't have its own + // checked operation, just a comparison with the minimum + // value, so we have to check for the assert message. + if !bcx.ccx().check_overflow() { + use rustc_const_math::ConstMathErr::Overflow; + use rustc_const_math::Op::Neg; + + if let mir::AssertMessage::Math(Overflow(Neg)) = *msg { + const_cond = Some(expected); + } + } // Don't translate the panic block if success if known. if const_cond == Some(expected) { diff --git a/src/test/run-pass/mir_overflow_off.rs b/src/test/run-pass/mir_overflow_off.rs new file mode 100644 index 000000000000..04ac606a8a9a --- /dev/null +++ b/src/test/run-pass/mir_overflow_off.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. + +// compile-flags: -Z force-overflow-checks=off -Z orbit + +// Test that with MIR trans, overflow checks can be +// turned off, even when they're from core::ops::*. + +use std::ops::*; + +fn main() { + assert_eq!(i8::neg(-0x80), -0x80); + + assert_eq!(u8::add(0xff, 1), 0_u8); + assert_eq!(u8::sub(0, 1), 0xff_u8); + assert_eq!(u8::mul(0xff, 2), 0xfe_u8); + assert_eq!(u8::shl(1, 9), 2_u8); + assert_eq!(u8::shr(2, 9), 1_u8); +} From a0bdb1761892f77e9ebd2fd3e42e8b49ec1e34fe Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Thu, 4 Aug 2016 15:09:15 -0400 Subject: [PATCH 317/331] Update E0124 to the new error format --- src/librustc_typeck/collect.rs | 11 ++++++----- src/test/compile-fail/E0124.rs | 4 +++- src/test/compile-fail/struct-fields-decl-dupe.rs | 4 +++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4486748a1f05..921df3db6358 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1010,11 +1010,12 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fid = ccx.tcx.map.local_def_id(f.id); let dup_span = seen_fields.get(&f.name).cloned(); if let Some(prev_span) = dup_span { - let mut err = struct_span_err!(ccx.tcx.sess, f.span, E0124, - "field `{}` is already declared", - f.name); - span_note!(&mut err, prev_span, "previously declared here"); - err.emit(); + struct_span_err!(ccx.tcx.sess, f.span, E0124, + "field `{}` is already declared", + f.name) + .span_label(f.span, &"field already declared") + .span_label(prev_span, &format!("`{}` first declared here", f.name)) + .emit(); } else { seen_fields.insert(f.name, f.span); } diff --git a/src/test/compile-fail/E0124.rs b/src/test/compile-fail/E0124.rs index 414b19ead624..18c507461065 100644 --- a/src/test/compile-fail/E0124.rs +++ b/src/test/compile-fail/E0124.rs @@ -9,8 +9,10 @@ // except according to those terms. struct Foo { + field1: i32, //~ NOTE `field1` first declared here field1: i32, - field1: i32, //~ ERROR E0124 + //~^ ERROR field `field1` is already declared [E0124] + //~| NOTE field already declared } fn main() { diff --git a/src/test/compile-fail/struct-fields-decl-dupe.rs b/src/test/compile-fail/struct-fields-decl-dupe.rs index 049569e8a184..dd9d7d294688 100644 --- a/src/test/compile-fail/struct-fields-decl-dupe.rs +++ b/src/test/compile-fail/struct-fields-decl-dupe.rs @@ -9,8 +9,10 @@ // except according to those terms. struct BuildData { + foo: isize, //~ NOTE `foo` first declared here foo: isize, - foo: isize, //~ ERROR field `foo` is already declared + //~^ ERROR field `foo` is already declared [E0124] + //~| NOTE field already declared } fn main() { From df726a45e18a9e760931f867b995f642131180ad Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Thu, 4 Aug 2016 20:27:11 +0100 Subject: [PATCH 318/331] Update error format for E0137 --- src/librustc/middle/entry.rs | 7 +++++-- src/test/compile-fail/E0137.rs | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 23a261400ed0..0a363fddd531 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -121,8 +121,11 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) { if ctxt.attr_main_fn.is_none() { ctxt.attr_main_fn = Some((item.id, item.span)); } else { - span_err!(ctxt.session, item.span, E0137, - "multiple functions with a #[main] attribute"); + struct_span_err!(ctxt.session, item.span, E0137, + "multiple functions with a #[main] attribute") + .span_label(item.span, &format!("additional #[main] function")) + .span_label(ctxt.attr_main_fn.unwrap().1, &format!("first #[main] function")) + .emit(); } }, EntryPointType::Start => { diff --git a/src/test/compile-fail/E0137.rs b/src/test/compile-fail/E0137.rs index 695ce7995a9a..f45afc9f37bd 100644 --- a/src/test/compile-fail/E0137.rs +++ b/src/test/compile-fail/E0137.rs @@ -11,7 +11,9 @@ #![feature(main)] #[main] -fn foo() {} +fn foo() {} //~ NOTE first #[main] function #[main] -fn f() {} //~ ERROR E0137 +fn f() {} +//~^ ERROR E0137 +//~| NOTE additional #[main] function From 75e2624a51f5e3a4b2da47f59b95b15caae64031 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 4 Aug 2016 15:06:26 +0200 Subject: [PATCH 319/331] track current_item in Deprecated lint pass --- src/librustc_lint/builtin.rs | 57 ++++++++++++++++++++++++++++++++++-- src/librustc_lint/lib.rs | 2 +- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 7547e28625c1..ac33fb610c56 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -567,10 +567,21 @@ declare_lint! { } /// Checks for use of items with `#[deprecated]` or `#[rustc_deprecated]` attributes -#[derive(Copy, Clone)] -pub struct Deprecated; +#[derive(Clone)] +pub struct Deprecated { + /// Tracks the `NodeId` of the current item. + /// + /// This is required since not all node ids are present in the hir map. + current_item: ast::NodeId, +} impl Deprecated { + pub fn new() -> Deprecated { + Deprecated { + current_item: ast::CRATE_NODE_ID, + } + } + fn lint(&self, cx: &LateContext, _id: DefId, span: Span, stability: &Option<&attr::Stability>, deprecation: &Option) { // Deprecated attributes apply in-crate and cross-crate. @@ -591,6 +602,19 @@ impl Deprecated { cx.span_lint(lint, span, &msg); } } + + fn push_item(&mut self, item_id: ast::NodeId) { + self.current_item = item_id; + } + + fn item_post(&mut self, cx: &LateContext, item_id: ast::NodeId) { + assert_eq!(self.current_item, item_id); + self.current_item = cx.tcx.map.get_parent(item_id); + } + + fn parent_def(&self, cx: &LateContext) -> DefId { + cx.tcx.map.local_def_id(self.current_item) + } } impl LintPass for Deprecated { @@ -601,11 +625,16 @@ impl LintPass for Deprecated { impl LateLintPass for Deprecated { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + self.push_item(item.id); stability::check_item(cx.tcx, item, false, &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } + fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) { + self.item_post(cx, item.id); + } + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { stability::check_expr(cx.tcx, e, &mut |id, sp, stab, depr| @@ -629,6 +658,30 @@ impl LateLintPass for Deprecated { &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } + + fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) { + self.push_item(item.id); + } + + fn check_impl_item_post(&mut self, cx: &LateContext, item: &hir::ImplItem) { + self.item_post(cx, item.id); + } + + fn check_trait_item(&mut self, _: &LateContext, item: &hir::TraitItem) { + self.push_item(item.id); + } + + fn check_trait_item_post(&mut self, cx: &LateContext, item: &hir::TraitItem) { + self.item_post(cx, item.id); + } + + fn check_foreign_item(&mut self, _: &LateContext, item: &hir::ForeignItem) { + self.push_item(item.id); + } + + fn check_foreign_item_post(&mut self, cx: &LateContext, item: &hir::ForeignItem) { + self.item_post(cx, item.id); + } } declare_lint! { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 7b0ee91b69ed..43376dfd8c2a 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -124,7 +124,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedAllocation, MissingCopyImplementations, UnstableFeatures, - Deprecated, UnconditionalRecursion, InvalidNoMangleItems, PluginAsLibrary, @@ -133,6 +132,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { ); add_builtin_with_new!(sess, + Deprecated, TypeLimits, MissingDoc, MissingDebugImplementations, From b4c6a39ccf051c9a05956d25e8b075659ae60d1c Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 4 Aug 2016 15:18:36 +0200 Subject: [PATCH 320/331] change depr_map to use DeprecationEntry --- src/librustc/middle/stability.rs | 57 +++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 36268a9de960..209b44e67a1b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -19,7 +19,7 @@ use session::Session; use lint; use middle::cstore::LOCAL_CRATE; use hir::def::Def; -use hir::def_id::{CRATE_DEF_INDEX, DefId}; +use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; @@ -61,12 +61,46 @@ enum AnnotationKind { Container, } +/// An entry in the `depr_map`. +#[derive(Clone)] +pub struct DeprecationEntry { + /// The metadata of the attribute associated with this entry. + pub attr: Deprecation, + /// The def id where the attr was originally attached. `None` for non-local + /// `DefId`'s. + origin: Option, +} + +impl DeprecationEntry { + fn local(attr: Deprecation, id: DefId) -> DeprecationEntry { + assert!(id.is_local()); + DeprecationEntry { + attr: attr, + origin: Some(id.index), + } + } + + fn external(attr: Deprecation) -> DeprecationEntry { + DeprecationEntry { + attr: attr, + origin: None, + } + } + + pub fn same_origin(&self, other: &DeprecationEntry) -> bool { + match (self.origin, other.origin) { + (Some(o1), Some(o2)) => o1 == o2, + _ => false + } + } +} + /// A stability index, giving the stability level for items and methods. pub struct Index<'tcx> { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. stab_map: DefIdMap>, - depr_map: DefIdMap>, + depr_map: DefIdMap>, /// Maps for each crate whether it is part of the staged API. staged_api: FnvHashMap @@ -77,7 +111,7 @@ struct Annotator<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, index: &'a mut Index<'tcx>, parent_stab: Option<&'tcx Stability>, - parent_depr: Option, + parent_depr: Option, access_levels: &'a AccessLevels, in_trait_impl: bool, } @@ -184,14 +218,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // `Deprecation` is just two pointers, no need to intern it let def_id = self.tcx.map.local_def_id(id); - self.index.depr_map.insert(def_id, Some(depr.clone())); + let depr_entry = Some(DeprecationEntry::local(depr, def_id)); + self.index.depr_map.insert(def_id, depr_entry.clone()); - let orig_parent_depr = replace(&mut self.parent_depr, Some(depr)); + let orig_parent_depr = replace(&mut self.parent_depr, depr_entry); visit_children(self); self.parent_depr = orig_parent_depr; - } else if let Some(depr) = self.parent_depr.clone() { + } else if let parent_depr @ Some(_) = self.parent_depr.clone() { let def_id = self.tcx.map.local_def_id(id); - self.index.depr_map.insert(def_id, Some(depr)); + self.index.depr_map.insert(def_id, parent_depr); visit_children(self); } else { visit_children(self); @@ -685,6 +720,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } pub fn lookup_deprecation(self, id: DefId) -> Option { + self.lookup_deprecation_entry(id).map(|depr| depr.attr) + } + + pub fn lookup_deprecation_entry(self, id: DefId) -> Option { if let Some(depr) = self.stability.borrow().depr_map.get(&id) { return depr.clone(); } @@ -703,12 +742,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } } - fn lookup_deprecation_uncached(self, id: DefId) -> Option { + fn lookup_deprecation_uncached(self, id: DefId) -> Option { debug!("lookup(id={:?})", id); if id.is_local() { None // The stability cache is filled partially lazily } else { - self.sess.cstore.deprecation(id) + self.sess.cstore.deprecation(id).map(DeprecationEntry::external) } } } From 76babf9c8ee412b5e4ff492ddd1b5248547c825e Mon Sep 17 00:00:00 2001 From: ubsan Date: Thu, 4 Aug 2016 13:28:24 -0700 Subject: [PATCH 321/331] Fix precedence table in reference --- src/doc/reference.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index a461023642af..f4ffe5774d27 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3049,7 +3049,8 @@ as == != < > <= >= && || -= .. +.. ... += ``` Operators at the same precedence level are evaluated left-to-right. [Unary From 0214ec248b2835a17c845c742d0e7697262ca72e Mon Sep 17 00:00:00 2001 From: trixnz Date: Thu, 4 Aug 2016 22:52:16 +0200 Subject: [PATCH 322/331] Update error format for E0062 --- src/librustc_typeck/check/mod.rs | 20 +++++++++++++++++--- src/test/compile-fail/E0062.rs | 4 +++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6062bd048b3d..4d3dda819930 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3063,6 +3063,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { remaining_fields.insert(field.name, field); } + let mut seen_fields = FnvHashMap(); + let mut error_happened = false; // Typecheck each field. @@ -3071,13 +3073,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(v_field) = remaining_fields.remove(&field.name.node) { expected_field_type = self.field_ty(field.span, v_field, substs); + + seen_fields.insert(field.name.node, field.span); } else { error_happened = true; expected_field_type = tcx.types.err; if let Some(_) = variant.find_field_named(field.name.node) { - span_err!(self.tcx.sess, field.name.span, E0062, - "field `{}` specified more than once", - field.name.node); + let mut err = struct_span_err!(self.tcx.sess, + field.name.span, + E0062, + "field `{}` specified more than once", + field.name.node); + + err.span_label(field.name.span, &format!("used more than once")); + + if let Some(prev_span) = seen_fields.get(&field.name.node) { + err.span_label(*prev_span, &format!("first use of `{}`", field.name.node)); + } + + err.emit(); } else { self.report_unknown_field(adt_ty, variant, field, ast_fields); } diff --git a/src/test/compile-fail/E0062.rs b/src/test/compile-fail/E0062.rs index 86ec7db14b5c..822d93e52d58 100644 --- a/src/test/compile-fail/E0062.rs +++ b/src/test/compile-fail/E0062.rs @@ -14,7 +14,9 @@ struct Foo { fn main() { let x = Foo { + x: 0, //~ NOTE first use of `x` x: 0, - x: 0, //~ ERROR E0062 + //~^ ERROR E0062 + //~| NOTE used more than once }; } From 2f36ecfff0fd6f4d5bd83ba61fc1685c4844dd04 Mon Sep 17 00:00:00 2001 From: Chris Stankus Date: Thu, 4 Aug 2016 15:30:21 -0500 Subject: [PATCH 323/331] E0119 update error format --- src/librustc_typeck/coherence/overlap.rs | 12 +++++++++--- src/test/compile-fail/E0119.rs | 3 ++- src/test/compile-fail/issue-28568.rs | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index dcaa5cfb20a4..54bd141304d7 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -141,12 +141,18 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119, "conflicting implementations of trait `{}`{}:", overlap.trait_desc, - overlap.self_desc.map_or(String::new(), - |ty| format!(" for type `{}`", ty))); + overlap.self_desc.clone().map_or(String::new(), + |ty| format!(" for type `{}`", ty))); match self.tcx.span_of_impl(overlap.with_impl) { Ok(span) => { - err.span_note(span, "conflicting implementation is here:"); + err.span_label(span, + &format!("first implementation here")); + err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(), + &format!("conflicting implementation{}", + overlap.self_desc + .map_or(String::new(), + |ty| format!(" for `{}`", ty)))); } Err(cname) => { err.note(&format!("conflicting implementation in crate `{}`", diff --git a/src/test/compile-fail/E0119.rs b/src/test/compile-fail/E0119.rs index 9528631b3047..56820bcd1840 100644 --- a/src/test/compile-fail/E0119.rs +++ b/src/test/compile-fail/E0119.rs @@ -12,7 +12,7 @@ trait MyTrait { fn get(&self) -> usize; } -impl MyTrait for T { +impl MyTrait for T { //~ NOTE first implementation here fn get(&self) -> usize { 0 } } @@ -21,6 +21,7 @@ struct Foo { } impl MyTrait for Foo { //~ ERROR E0119 + //~| NOTE conflicting implementation for `Foo` fn get(&self) -> usize { self.value } } diff --git a/src/test/compile-fail/issue-28568.rs b/src/test/compile-fail/issue-28568.rs index 7c051784f61a..f03daafc6375 100644 --- a/src/test/compile-fail/issue-28568.rs +++ b/src/test/compile-fail/issue-28568.rs @@ -11,12 +11,13 @@ struct MyStruct; impl Drop for MyStruct { -//~^ NOTE conflicting implementation is here +//~^ NOTE first implementation here fn drop(&mut self) { } } impl Drop for MyStruct { //~^ ERROR conflicting implementations of trait +//~| NOTE conflicting implementation for `MyStruct` fn drop(&mut self) { } } From c17501fea4f9b73134446fbc0700e5d1203909ac Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 4 Aug 2016 20:13:40 +0200 Subject: [PATCH 324/331] ignore deprecation for items deprecated by the same attribute Whenever a node whould be reported as deprecated: - check if the parent item is also deprecated - if it is and both were deprecated by the same attribute - skip the deprecation warning fixes #35128 closes #16490 --- src/librustc/middle/stability.rs | 16 ++++++++-------- src/librustc_lint/builtin.rs | 13 ++++++++++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 209b44e67a1b..cbbc2c4f98f5 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -386,7 +386,7 @@ struct Checker<'a, 'tcx: 'a> { impl<'a, 'tcx> Checker<'a, 'tcx> { fn check(&mut self, id: DefId, span: Span, - stab: &Option<&Stability>, _depr: &Option) { + stab: &Option<&Stability>, _depr: &Option) { if !is_staged_api(self.tcx, id) { return; } @@ -511,7 +511,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, warn_about_defns: bool, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { match item.node { hir::ItemExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. @@ -550,7 +550,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { let span; let id = match e.node { hir::ExprMethodCall(i, _, _) => { @@ -614,7 +614,7 @@ pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &hir::Path, id: ast::NodeId, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { // Paths in import prefixes may have no resolution. match tcx.expect_def_or_none(id) { Some(Def::PrimTy(..)) => {} @@ -630,7 +630,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::PathListItem, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { match tcx.expect_def(item.node.id()) { Def::PrimTy(..) => {} def => { @@ -642,7 +642,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } @@ -673,7 +673,7 @@ fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId, span: Span, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { if is_internal(tcx, span) { debug!("maybe_do_stability_check: \ skipping span={:?} since it is internal", span); @@ -682,7 +682,7 @@ fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (stability, deprecation) = if is_staged_api(tcx, id) { (tcx.lookup_stability(id), None) } else { - (None, tcx.lookup_deprecation(id)) + (None, tcx.lookup_deprecation_entry(id)) }; debug!("maybe_do_stability_check: \ inspecting id={:?} span={:?} of stability={:?}", id, span, stability); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ac33fb610c56..49dad2d0f6d9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -583,13 +583,20 @@ impl Deprecated { } fn lint(&self, cx: &LateContext, _id: DefId, span: Span, - stability: &Option<&attr::Stability>, deprecation: &Option) { + stability: &Option<&attr::Stability>, + deprecation: &Option) { // Deprecated attributes apply in-crate and cross-crate. if let Some(&attr::Stability{rustc_depr: Some(attr::RustcDeprecation{ref reason, ..}), ..}) = *stability { output(cx, DEPRECATED, span, Some(&reason)) - } else if let Some(attr::Deprecation{ref note, ..}) = *deprecation { - output(cx, DEPRECATED, span, note.as_ref().map(|x| &**x)) + } else if let Some(ref depr_entry) = *deprecation { + if let Some(parent_depr) = cx.tcx.lookup_deprecation_entry(self.parent_def(cx)) { + if parent_depr.same_origin(depr_entry) { + return; + } + } + + output(cx, DEPRECATED, span, depr_entry.attr.note.as_ref().map(|x| &**x)) } fn output(cx: &LateContext, lint: &'static Lint, span: Span, note: Option<&str>) { From 98fe30b58bca5ce861eae69e85a28d98f0608505 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 4 Aug 2016 16:56:20 +0200 Subject: [PATCH 325/331] fix existing tests --- src/test/compile-fail/deprecation-lint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/deprecation-lint.rs b/src/test/compile-fail/deprecation-lint.rs index 5fc8f684a66f..edee24206cd3 100644 --- a/src/test/compile-fail/deprecation-lint.rs +++ b/src/test/compile-fail/deprecation-lint.rs @@ -266,14 +266,14 @@ mod this_crate { #[deprecated(since = "1.0.0", note = "text")] fn test_fn_body() { fn fn_in_body() {} - fn_in_body(); //~ ERROR use of deprecated item: text + fn_in_body(); } impl MethodTester { #[deprecated(since = "1.0.0", note = "text")] fn test_method_body(&self) { fn fn_in_body() {} - fn_in_body(); //~ ERROR use of deprecated item: text + fn_in_body(); } } From 627b1e8ec72dfda6944ff247d50d470f8d1d672b Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 4 Aug 2016 18:54:04 +0200 Subject: [PATCH 326/331] add test for nested deprecated --- .../compile-fail/deprecation-lint-nested.rs | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/test/compile-fail/deprecation-lint-nested.rs diff --git a/src/test/compile-fail/deprecation-lint-nested.rs b/src/test/compile-fail/deprecation-lint-nested.rs new file mode 100644 index 000000000000..eedbba59c6f4 --- /dev/null +++ b/src/test/compile-fail/deprecation-lint-nested.rs @@ -0,0 +1,81 @@ +// 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. + +#![deny(deprecated)] +#![allow(warnings)] + +#[deprecated] +fn issue_35128() { + format_args!("foo"); +} + +#[deprecated] +fn issue_35128_minimal() { + static FOO: &'static str = "foo"; + let _ = FOO; +} + +#[deprecated] +mod silent { + type DeprecatedType = u8; + struct DeprecatedStruct; + fn deprecated_fn() {} + trait DeprecatedTrait {} + static DEPRECATED_STATIC: u8 = 0; + const DEPRECATED_CONST: u8 = 1; + + struct Foo(DeprecatedType); + + impl DeprecatedTrait for Foo {} + + impl Foo { + fn bar() { + deprecated_fn(); + } + } + + fn foo() -> u8 { + DEPRECATED_STATIC + + DEPRECATED_CONST + } +} + +#[deprecated] +mod loud { + #[deprecated] + type DeprecatedType = u8; + #[deprecated] + struct DeprecatedStruct; + #[deprecated] + fn deprecated_fn() {} + #[deprecated] + trait DeprecatedTrait {} + #[deprecated] + static DEPRECATED_STATIC: u8 = 0; + #[deprecated] + const DEPRECATED_CONST: u8 = 1; + + struct Foo(DeprecatedType); //~ ERROR use of deprecated item + + impl DeprecatedTrait for Foo {} //~ ERROR use of deprecated item + + impl Foo { + fn bar() { //~ ERROR use of deprecated item + deprecated_fn(); //~ ERROR use of deprecated item + } + } + + fn foo() -> u8 { + DEPRECATED_STATIC + //~ ERROR use of deprecated item + DEPRECATED_CONST //~ ERROR use of deprecated item + } +} + +fn main() {} From b5b3539186b43d1291bcc5367171d9745f6a427f Mon Sep 17 00:00:00 2001 From: Nick Massey Date: Thu, 4 Aug 2016 15:35:43 -0600 Subject: [PATCH 327/331] Update compiler error E0055 to use new error format --- src/librustc_typeck/check/autoderef.rs | 6 ++++-- src/test/compile-fail/E0055.rs | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 3c176744fca5..265422468fe2 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -54,9 +54,11 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { if self.steps.len() == tcx.sess.recursion_limit.get() { // We've reached the recursion limit, error gracefully. - span_err!(tcx.sess, self.span, E0055, + struct_span_err!(tcx.sess, self.span, E0055, "reached the recursion limit while auto-dereferencing {:?}", - self.cur_ty); + self.cur_ty) + .span_label(self.span, &format!("deref recursion limit reached")) + .emit(); return None; } diff --git a/src/test/compile-fail/E0055.rs b/src/test/compile-fail/E0055.rs index f86d7ec114b9..2b2d278ad4cc 100644 --- a/src/test/compile-fail/E0055.rs +++ b/src/test/compile-fail/E0055.rs @@ -18,5 +18,7 @@ impl Foo { fn main() { let foo = Foo; let ref_foo = &&Foo; - ref_foo.foo(); //~ ERROR E0055 + ref_foo.foo(); + //~^ ERROR E0055 + //~| NOTE deref recursion limit reached } From 3b2f1845f3a1d8192a14b4184d5ba66ad7a98ac3 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Thu, 4 Aug 2016 16:10:18 +0100 Subject: [PATCH 328/331] Update error message E0120 --- src/librustc_typeck/coherence/mod.rs | 15 ++++++++++++--- src/test/compile-fail/E0120.rs | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 198e9afd5e12..2d14b0dacf24 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -249,8 +249,17 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) { match tcx.map.find(impl_node_id) { Some(hir_map::NodeItem(item)) => { - span_err!(tcx.sess, item.span, E0120, - "the Drop trait may only be implemented on structures"); + let span = match item.node { + ItemImpl(_, _, _, _, ref ty, _) => { + ty.span + }, + _ => item.span + }; + struct_span_err!(tcx.sess, span, E0120, + "the Drop trait may only be implemented on structures") + .span_label(span, + &format!("implementing Drop requires a struct")) + .emit(); } _ => { bug!("didn't find impl in ast map"); @@ -258,7 +267,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } } else { bug!("found external impl of Drop trait on \ - :omething other than a struct"); + something other than a struct"); } } } diff --git a/src/test/compile-fail/E0120.rs b/src/test/compile-fail/E0120.rs index de084274f6fb..3fdeb7531754 100644 --- a/src/test/compile-fail/E0120.rs +++ b/src/test/compile-fail/E0120.rs @@ -10,7 +10,9 @@ trait MyTrait {} -impl Drop for MyTrait { //~ ERROR E0120 +impl Drop for MyTrait { + //~^ ERROR E0120 + //~| NOTE implementing Drop requires a struct fn drop(&mut self) {} } From 1ca95ae5ba9c0b3974b620399297c3d494d73601 Mon Sep 17 00:00:00 2001 From: William Lee Date: Thu, 4 Aug 2016 23:43:56 -0400 Subject: [PATCH 329/331] Fix for issue #35336 - updating error message for for E0368 to include a span_label --- src/librustc_typeck/check/op.rs | 14 +++++++++----- src/test/compile-fail/issue-5239-1.rs | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d02f87d0b9cd..63487683ec3b 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -176,11 +176,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // error types are considered "builtin" if !lhs_ty.references_error() { if let IsAssign::Yes = is_assign { - span_err!(self.tcx.sess, lhs_expr.span, E0368, - "binary assignment operation `{}=` \ - cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty); + struct_span_err!(self.tcx.sess, lhs_expr.span, E0368, + "binary assignment operation `{}=` \ + cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty) + .span_label(lhs_expr.span, + &format!("cannot use `{}=` on type `{}`", + op.node.as_str(), lhs_ty)) + .emit(); } else { let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369, "binary operation `{}` cannot be applied to type `{}`", diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs index 1ebef06008ff..06e3c9a207b7 100644 --- a/src/test/compile-fail/issue-5239-1.rs +++ b/src/test/compile-fail/issue-5239-1.rs @@ -13,4 +13,5 @@ fn main() { let x = |ref x: isize| -> isize { x += 1; }; //~^ ERROR E0368 + //~| NOTE cannot use `+=` on type `&isize` } From a6ffa42f7d4352babdcea3a43e85fedb5987a402 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Fri, 5 Aug 2016 16:54:37 +0900 Subject: [PATCH 330/331] Update E0391 to new format. --- src/librustc_typeck/collect.rs | 1 + src/test/compile-fail/issue-3907.rs | 1 + src/test/compile-fail/issue-5035.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4486748a1f05..dce4d7f31016 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -184,6 +184,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { let mut err = struct_span_err!(tcx.sess, span, E0391, "unsupported cyclic reference between types/traits detected"); + err.span_label(span, &format!("cyclic reference")); match cycle[0] { AstConvRequest::GetItemTypeScheme(def_id) | diff --git a/src/test/compile-fail/issue-3907.rs b/src/test/compile-fail/issue-3907.rs index cbc09a028c2c..93556577ad34 100644 --- a/src/test/compile-fail/issue-3907.rs +++ b/src/test/compile-fail/issue-3907.rs @@ -18,6 +18,7 @@ struct S { } impl Foo for S { //~ ERROR: `Foo` is not a trait + //~| NOTE: not a trait //~| NOTE: type aliases cannot be used for traits fn bar() { } } diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index 9648d64d1fb6..c2154e8a6c0b 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -11,6 +11,7 @@ trait I {} type K = I; impl K for isize {} //~ ERROR: `K` is not a trait + //~| NOTE: not a trait //~| NOTE: aliases cannot be used for traits use ImportError; //~ ERROR unresolved From 19e140b946010a165373ff4d95ba858b28ff192f Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Fri, 5 Aug 2016 16:59:44 +0900 Subject: [PATCH 331/331] Update E0404 to new format. --- src/librustc_resolve/lib.rs | 8 +++++++- src/test/ui/codemap_tests/two_files.stderr | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c1511b29c9e0..b26e3b3819ce 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -219,7 +219,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, name) } ResolutionError::IsNotATrait(name) => { - struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name) + let mut err = struct_span_err!(resolver.session, + span, + E0404, + "`{}` is not a trait", + name); + err.span_label(span, &format!("not a trait")); + err } ResolutionError::UndeclaredTraitName(name, candidates) => { let mut err = struct_span_err!(resolver.session, diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index cf3f187af933..695601743461 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -2,7 +2,7 @@ error[E0404]: `Bar` is not a trait --> $DIR/two_files.rs:16:6 | 16 | impl Bar for Baz { } - | ^^^ + | ^^^ not a trait | = note: type aliases cannot be used for traits