Auto merge of #54575 - pietroalbini:rollup, r=pietroalbini

Rollup of 12 pull requests

Successful merges:

 - #53518 (Add doc for impl From in char_convert)
 - #54058 (Introduce the partition_dedup/by/by_key methods for slices)
 - #54281 (Search box)
 - #54368 (Reduce code block sides padding)
 - #54498 (The project moved under the Mozilla umbrella)
 - #54518 (resolve: Do not block derive helper resolutions on single import resolutions)
 - #54522 (Fixed three small typos.)
 - #54529 (aarch64-pc-windows-msvc: Don't link libpanic_unwind to libtest.)
 - #54537 (Rename slice::exact_chunks() to slice::chunks_exact())
 - #54539 (Fix js error)
 - #54557 (incr.comp.: Don't automatically enable -Zshare-generics for incr. comp. builds.)
 - #54558 (Improvements to finding LLVM's FileCheck)

Failed merges:

r? @ghost
This commit is contained in:
bors 2018-09-25 22:52:16 +00:00
commit 92aff72a05
27 changed files with 538 additions and 224 deletions

View file

@ -322,6 +322,7 @@
# Flag indicating whether codegen tests will be run or not. If you get an error
# saying that the FileCheck executable is missing, you may want to disable this.
# Also see the target's llvm-filecheck option.
#codegen-tests = true
# Flag indicating whether git info will be retrieved from .git automatically.
@ -416,6 +417,10 @@
# target.
#llvm-config = "../path/to/llvm/root/bin/llvm-config"
# Normally the build system can find LLVM's FileCheck utility, but if
# not, you can specify an explicit file name for it.
#llvm-filecheck = "/path/to/FileCheck"
# Path to the custom jemalloc static library to link into the standard library
# by default. This is only used if jemalloc is still enabled above
#jemalloc = "/path/to/jemalloc/libjemalloc_pic.a"

View file

@ -162,6 +162,8 @@ pub struct Config {
pub struct Target {
/// Some(path to llvm-config) if using an external LLVM.
pub llvm_config: Option<PathBuf>,
/// Some(path to FileCheck) if one was specified.
pub llvm_filecheck: Option<PathBuf>,
pub jemalloc: Option<PathBuf>,
pub cc: Option<PathBuf>,
pub cxx: Option<PathBuf>,
@ -330,6 +332,7 @@ struct Rust {
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct TomlTarget {
llvm_config: Option<String>,
llvm_filecheck: Option<String>,
jemalloc: Option<String>,
cc: Option<String>,
cxx: Option<String>,
@ -583,6 +586,9 @@ impl Config {
if let Some(ref s) = cfg.llvm_config {
target.llvm_config = Some(config.src.join(s));
}
if let Some(ref s) = cfg.llvm_filecheck {
target.llvm_filecheck = Some(config.src.join(s));
}
if let Some(ref s) = cfg.jemalloc {
target.jemalloc = Some(config.src.join(s));
}

View file

@ -95,6 +95,8 @@ v("docdir", "install.docdir", "install documentation in PATH")
v("bindir", "install.bindir", "install binaries")
v("llvm-root", None, "set LLVM root")
v("llvm-config", None, "set path to llvm-config")
v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
v("python", "build.python", "set path to python")
v("jemalloc-root", None, "set directory where libjemalloc_pic.a is located")
v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
@ -323,6 +325,10 @@ for key in known_args:
set('build.cargo', value + '/bin/cargo')
elif option.name == 'llvm-root':
set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
elif option.name == 'llvm-config':
set('target.{}.llvm-config'.format(build()), value)
elif option.name == 'llvm-filecheck':
set('target.{}.llvm-filecheck'.format(build()), value)
elif option.name == 'jemalloc-root':
set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
elif option.name == 'tools':

View file

@ -641,9 +641,28 @@ impl Build {
/// Returns the path to `FileCheck` binary for the specified target
fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
let target_config = self.config.target_config.get(&target);
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
s.to_path_buf()
} else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
let llvm_bindir = output(Command::new(s).arg("--bindir"));
Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target));
if filecheck.exists() {
filecheck
} else {
// On Fedora the system LLVM installs FileCheck in the
// llvm subdirectory of the libdir.
let llvm_libdir = output(Command::new(s).arg("--libdir"));
let lib_filecheck = Path::new(llvm_libdir.trim())
.join("llvm").join(exe("FileCheck", &*target));
if lib_filecheck.exists() {
lib_filecheck
} else {
// Return the most normal file name, even though
// it doesn't exist, so that any error message
// refers to that.
filecheck
}
}
} else {
let base = self.llvm_out(self.config.build).join("build");
let base = if !self.config.ninja && self.config.build.contains("msvc") {

View file

@ -4,6 +4,23 @@
nav {
display: none;
}
#search-input {
width: calc(100% - 58px);
}
#search-but {
cursor: pointer;
}
#search-but, #search-input {
padding: 4px;
border: 1px solid #ccc;
border-radius: 3px;
outline: none;
font-size: 0.7em;
background-color: #fff;
}
#search-but:hover, #search-input:focus {
border-color: #55a9ff;
}
</style>
Welcome to an overview of the documentation provided by the Rust project.
@ -45,8 +62,9 @@ accomplishing various tasks.
<div>
<form action="std/index.html" method="get">
<input type="search" name="search"/>
<button>Search</button>
<input id="search-input" type="search" name="search"
placeholder="Search through the standard library"/>
<button id="search-but">Search</button>
</form>
</div>

View file

@ -18,4 +18,4 @@ cargo run
```
Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created.
You can parse them with [llvm-cov gcov](http://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/marco-c/grcov).
You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov).

View file

@ -116,9 +116,10 @@
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
#![feature(exact_chunks)]
#![feature(chunks_exact)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit)]
// Allow testing this library

View file

@ -123,8 +123,8 @@ pub use core::slice::{from_raw_parts, from_raw_parts_mut};
pub use core::slice::{from_ref, from_mut};
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[unstable(feature = "exact_chunks", issue = "47115")]
pub use core::slice::{ExactChunks, ExactChunksMut};
#[unstable(feature = "chunks_exact", issue = "47115")]
pub use core::slice::{ChunksExact, ChunksExactMut};
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods

View file

@ -20,7 +20,7 @@
#![feature(str_escape)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(exact_chunks)]
#![feature(chunks_exact)]
#![feature(repeat_generic_slice)]
extern crate alloc_system;

View file

@ -975,27 +975,27 @@ fn test_chunksator_0() {
}
#[test]
fn test_exact_chunksator() {
fn test_chunks_exactator() {
let v = &[1, 2, 3, 4, 5];
assert_eq!(v.exact_chunks(2).len(), 2);
assert_eq!(v.chunks_exact(2).len(), 2);
let chunks: &[&[_]] = &[&[1, 2], &[3, 4]];
assert_eq!(v.exact_chunks(2).collect::<Vec<_>>(), chunks);
assert_eq!(v.chunks_exact(2).collect::<Vec<_>>(), chunks);
let chunks: &[&[_]] = &[&[1, 2, 3]];
assert_eq!(v.exact_chunks(3).collect::<Vec<_>>(), chunks);
assert_eq!(v.chunks_exact(3).collect::<Vec<_>>(), chunks);
let chunks: &[&[_]] = &[];
assert_eq!(v.exact_chunks(6).collect::<Vec<_>>(), chunks);
assert_eq!(v.chunks_exact(6).collect::<Vec<_>>(), chunks);
let chunks: &[&[_]] = &[&[3, 4], &[1, 2]];
assert_eq!(v.exact_chunks(2).rev().collect::<Vec<_>>(), chunks);
assert_eq!(v.chunks_exact(2).rev().collect::<Vec<_>>(), chunks);
}
#[test]
#[should_panic]
fn test_exact_chunksator_0() {
fn test_chunks_exactator_0() {
let v = &[1, 2, 3, 4];
let _it = v.exact_chunks(0);
let _it = v.chunks_exact(0);
}
#[test]
@ -1235,10 +1235,10 @@ fn test_mut_chunks_0() {
}
#[test]
fn test_mut_exact_chunks() {
fn test_mut_chunks_exact() {
let mut v = [0, 1, 2, 3, 4, 5, 6];
assert_eq!(v.exact_chunks_mut(2).len(), 3);
for (i, chunk) in v.exact_chunks_mut(3).enumerate() {
assert_eq!(v.chunks_exact_mut(2).len(), 3);
for (i, chunk) in v.chunks_exact_mut(3).enumerate() {
for x in chunk {
*x = i as u8;
}
@ -1248,9 +1248,9 @@ fn test_mut_exact_chunks() {
}
#[test]
fn test_mut_exact_chunks_rev() {
fn test_mut_chunks_exact_rev() {
let mut v = [0, 1, 2, 3, 4, 5, 6];
for (i, chunk) in v.exact_chunks_mut(3).rev().enumerate() {
for (i, chunk) in v.chunks_exact_mut(3).rev().enumerate() {
for x in chunk {
*x = i as u8;
}
@ -1261,9 +1261,9 @@ fn test_mut_exact_chunks_rev() {
#[test]
#[should_panic]
fn test_mut_exact_chunks_0() {
fn test_mut_chunks_exact_0() {
let mut v = [1, 2, 3, 4];
let _it = v.exact_chunks_mut(0);
let _it = v.chunks_exact_mut(0);
}
#[test]

View file

@ -947,10 +947,9 @@ impl<T> Vec<T> {
/// Removes all but the first of consecutive elements in the vector satisfying a given equality
/// relation.
///
/// The `same_bucket` function is passed references to two elements from the vector, and
/// returns `true` if the elements compare equal, or `false` if they do not. The elements are
/// passed in opposite order from their order in the vector, so if `same_bucket(a, b)` returns
/// `true`, `a` is removed.
/// The `same_bucket` function is passed references to two elements from the vector and
/// must determine if the elements compare equal. The elements are passed in opposite order
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
///
/// If the vector is sorted, this removes all duplicates.
///
@ -964,90 +963,12 @@ impl<T> Vec<T> {
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
/// ```
#[stable(feature = "dedup_by", since = "1.16.0")]
pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
unsafe {
// Although we have a mutable reference to `self`, we cannot make
// *arbitrary* changes. The `same_bucket` calls could panic, so we
// must ensure that the vector is in a valid state at all time.
//
// The way that we handle this is by using swaps; we iterate
// over all the elements, swapping as we go so that at the end
// the elements we wish to keep are in the front, and those we
// wish to reject are at the back. We can then truncate the
// vector. This operation is still O(n).
//
// Example: We start in this state, where `r` represents "next
// read" and `w` represents "next_write`.
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate, so
// we swap self[r] and self[w] (no effect as r==w) and then increment both
// r and w, leaving us with:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this value is a duplicate,
// so we increment `r` but leave everything else unchanged:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate,
// so swap self[r] and self[w] and advance r and w:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 1 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Not a duplicate, repeat:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 3 | 1 | 3 |
// +---+---+---+---+---+---+
// w
//
// Duplicate, advance r. End of vec. Truncate to w.
let ln = self.len();
if ln <= 1 {
return;
}
// Avoid bounds checks by using raw pointers.
let p = self.as_mut_ptr();
let mut r: usize = 1;
let mut w: usize = 1;
while r < ln {
let p_r = p.add(r);
let p_wm1 = p.add(w - 1);
if !same_bucket(&mut *p_r, &mut *p_wm1) {
if r != w {
let p_w = p_wm1.offset(1);
mem::swap(&mut *p_r, &mut *p_w);
}
w += 1;
}
r += 1;
}
self.truncate(w);
}
pub fn dedup_by<F>(&mut self, same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
let len = {
let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
dedup.len()
};
self.truncate(len);
}
/// Appends an element to the back of a collection.
@ -1533,7 +1454,8 @@ impl<'a> Drop for SetLenOnDrop<'a> {
}
impl<T: PartialEq> Vec<T> {
/// Removes consecutive repeated elements in the vector.
/// Removes consecutive repeated elements in the vector according to the
/// [`PartialEq`] trait implementation.
///
/// If the vector is sorted, this removes all duplicates.
///

View file

@ -115,6 +115,19 @@ pub unsafe fn from_u32_unchecked(i: u32) -> char {
#[stable(feature = "char_convert", since = "1.13.0")]
impl From<char> for u32 {
/// Converts a [`char`] into a [`u32`].
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// fn main() {
/// let c = 'c';
/// let u = u32::from(c);
/// assert!(4 == mem::size_of_val(&u))
/// }
/// ```
#[inline]
fn from(c: char) -> Self {
c as u32
@ -141,6 +154,19 @@ impl From<char> for u32 {
/// C0 and C1 control codes.
#[stable(feature = "char_convert", since = "1.13.0")]
impl From<u8> for char {
/// Converts a [`u8`] into a [`char`].
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// fn main() {
/// let u = 32 as u8;
/// let c = char::from(u);
/// assert!(4 == mem::size_of_val(&c))
/// }
/// ```
#[inline]
fn from(i: u8) -> Self {
i as char

View file

@ -624,7 +624,7 @@ impl<T> [T] {
/// not divide the length of the slice, then the last chunk will
/// not have length `chunk_size`.
///
/// See [`exact_chunks`] for a variant of this iterator that returns chunks
/// See [`chunks_exact`] for a variant of this iterator that returns chunks
/// of always exactly `chunk_size` elements.
///
/// # Panics
@ -642,7 +642,7 @@ impl<T> [T] {
/// assert!(iter.next().is_none());
/// ```
///
/// [`exact_chunks`]: #method.exact_chunks
/// [`chunks_exact`]: #method.chunks_exact
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
@ -655,7 +655,7 @@ impl<T> [T] {
/// not divide the length of the slice, then the last chunk will not
/// have length `chunk_size`.
///
/// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks
/// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks
/// of always exactly `chunk_size` elements.
///
/// # Panics
@ -677,7 +677,7 @@ impl<T> [T] {
/// assert_eq!(v, &[1, 1, 2, 2, 3]);
/// ```
///
/// [`exact_chunks_mut`]: #method.exact_chunks_mut
/// [`chunks_exact_mut`]: #method.chunks_exact_mut
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
@ -702,24 +702,24 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(exact_chunks)]
/// #![feature(chunks_exact)]
///
/// let slice = ['l', 'o', 'r', 'e', 'm'];
/// let mut iter = slice.exact_chunks(2);
/// let mut iter = slice.chunks_exact(2);
/// assert_eq!(iter.next().unwrap(), &['l', 'o']);
/// assert_eq!(iter.next().unwrap(), &['r', 'e']);
/// assert!(iter.next().is_none());
/// ```
///
/// [`chunks`]: #method.chunks
#[unstable(feature = "exact_chunks", issue = "47115")]
#[unstable(feature = "chunks_exact", issue = "47115")]
#[inline]
pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<T> {
assert!(chunk_size != 0);
let rem = self.len() % chunk_size;
let len = self.len() - rem;
let (fst, snd) = self.split_at(len);
ExactChunks { v: fst, rem: snd, chunk_size }
ChunksExact { v: fst, rem: snd, chunk_size }
}
/// Returns an iterator over `chunk_size` elements of the slice at a time.
@ -739,12 +739,12 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(exact_chunks)]
/// #![feature(chunks_exact)]
///
/// let v = &mut [0, 0, 0, 0, 0];
/// let mut count = 1;
///
/// for chunk in v.exact_chunks_mut(2) {
/// for chunk in v.chunks_exact_mut(2) {
/// for elem in chunk.iter_mut() {
/// *elem += count;
/// }
@ -754,14 +754,14 @@ impl<T> [T] {
/// ```
///
/// [`chunks_mut`]: #method.chunks_mut
#[unstable(feature = "exact_chunks", issue = "47115")]
#[unstable(feature = "chunks_exact", issue = "47115")]
#[inline]
pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<T> {
assert!(chunk_size != 0);
let rem = self.len() % chunk_size;
let len = self.len() - rem;
let (fst, snd) = self.split_at_mut(len);
ExactChunksMut { v: fst, rem: snd, chunk_size }
ChunksExactMut { v: fst, rem: snd, chunk_size }
}
/// Divides one slice into two at an index.
@ -1402,6 +1402,178 @@ impl<T> [T] {
sort::quicksort(self, |a, b| f(a).lt(&f(b)));
}
/// Moves all consecutive repeated elements to the end of the slice according to the
/// [`PartialEq`] trait implementation.
///
/// Returns two slices. The first contains no consecutive repeated elements.
/// The second contains all the duplicates in no specified order.
///
/// If the slice is sorted, the first returned slice contains no duplicates.
///
/// # Examples
///
/// ```
/// #![feature(slice_partition_dedup)]
///
/// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1];
///
/// let (dedup, duplicates) = slice.partition_dedup();
///
/// assert_eq!(dedup, [1, 2, 3, 2, 1]);
/// assert_eq!(duplicates, [2, 3, 1]);
/// ```
#[unstable(feature = "slice_partition_dedup", issue = "54279")]
#[inline]
pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T])
where T: PartialEq
{
self.partition_dedup_by(|a, b| a == b)
}
/// Moves all but the first of consecutive elements to the end of the slice satisfying
/// a given equality relation.
///
/// Returns two slices. The first contains no consecutive repeated elements.
/// The second contains all the duplicates in no specified order.
///
/// The `same_bucket` function is passed references to two elements from the slice and
/// must determine if the elements compare equal. The elements are passed in opposite order
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is moved
/// at the end of the slice.
///
/// If the slice is sorted, the first returned slice contains no duplicates.
///
/// # Examples
///
/// ```
/// #![feature(slice_partition_dedup)]
///
/// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"];
///
/// let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
///
/// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]);
/// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]);
/// ```
#[unstable(feature = "slice_partition_dedup", issue = "54279")]
#[inline]
pub fn partition_dedup_by<F>(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T])
where F: FnMut(&mut T, &mut T) -> bool
{
// Although we have a mutable reference to `self`, we cannot make
// *arbitrary* changes. The `same_bucket` calls could panic, so we
// must ensure that the slice is in a valid state at all times.
//
// The way that we handle this is by using swaps; we iterate
// over all the elements, swapping as we go so that at the end
// the elements we wish to keep are in the front, and those we
// wish to reject are at the back. We can then split the slice.
// This operation is still O(n).
//
// Example: We start in this state, where `r` represents "next
// read" and `w` represents "next_write`.
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate, so
// we swap self[r] and self[w] (no effect as r==w) and then increment both
// r and w, leaving us with:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this value is a duplicate,
// so we increment `r` but leave everything else unchanged:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate,
// so swap self[r] and self[w] and advance r and w:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 1 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Not a duplicate, repeat:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 3 | 1 | 3 |
// +---+---+---+---+---+---+
// w
//
// Duplicate, advance r. End of slice. Split at w.
let len = self.len();
if len <= 1 {
return (self, &mut [])
}
let ptr = self.as_mut_ptr();
let mut next_read: usize = 1;
let mut next_write: usize = 1;
unsafe {
// Avoid bounds checks by using raw pointers.
while next_read < len {
let ptr_read = ptr.add(next_read);
let prev_ptr_write = ptr.add(next_write - 1);
if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) {
if next_read != next_write {
let ptr_write = prev_ptr_write.offset(1);
mem::swap(&mut *ptr_read, &mut *ptr_write);
}
next_write += 1;
}
next_read += 1;
}
}
self.split_at_mut(next_write)
}
/// Moves all but the first of consecutive elements to the end of the slice that resolve
/// to the same key.
///
/// Returns two slices. The first contains no consecutive repeated elements.
/// The second contains all the duplicates in no specified order.
///
/// If the slice is sorted, the first returned slice contains no duplicates.
///
/// # Examples
///
/// ```
/// #![feature(slice_partition_dedup)]
///
/// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13];
///
/// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10);
///
/// assert_eq!(dedup, [10, 20, 30, 20, 11]);
/// assert_eq!(duplicates, [21, 30, 13]);
/// ```
#[unstable(feature = "slice_partition_dedup", issue = "54279")]
#[inline]
pub fn partition_dedup_by_key<K, F>(&mut self, mut key: F) -> (&mut [T], &mut [T])
where F: FnMut(&mut T) -> K,
K: PartialEq,
{
self.partition_dedup_by(|a, b| key(a) == key(b))
}
/// Rotates the slice in-place such that the first `mid` elements of the
/// slice move to the end while the last `self.len() - mid` elements move to
/// the front. After calling `rotate_left`, the element previously at index
@ -3657,21 +3829,21 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
/// the [`remainder`] function from the iterator.
///
/// This struct is created by the [`exact_chunks`] method on [slices].
/// This struct is created by the [`chunks_exact`] method on [slices].
///
/// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks
/// [`remainder`]: ../../std/slice/struct.ExactChunks.html#method.remainder
/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact
/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder
/// [slices]: ../../std/primitive.slice.html
#[derive(Debug)]
#[unstable(feature = "exact_chunks", issue = "47115")]
pub struct ExactChunks<'a, T:'a> {
#[unstable(feature = "chunks_exact", issue = "47115")]
pub struct ChunksExact<'a, T:'a> {
v: &'a [T],
rem: &'a [T],
chunk_size: usize
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> ExactChunks<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> ChunksExact<'a, T> {
/// Return the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
@ -3681,10 +3853,10 @@ impl<'a, T> ExactChunks<'a, T> {
}
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> Clone for ExactChunks<'a, T> {
fn clone(&self) -> ExactChunks<'a, T> {
ExactChunks {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> Clone for ChunksExact<'a, T> {
fn clone(&self) -> ChunksExact<'a, T> {
ChunksExact {
v: self.v,
rem: self.rem,
chunk_size: self.chunk_size,
@ -3692,8 +3864,8 @@ impl<'a, T> Clone for ExactChunks<'a, T> {
}
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> Iterator for ExactChunks<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> Iterator for ChunksExact<'a, T> {
type Item = &'a [T];
#[inline]
@ -3737,8 +3909,8 @@ impl<'a, T> Iterator for ExactChunks<'a, T> {
}
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> DoubleEndedIterator for ExactChunks<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a [T]> {
if self.v.len() < self.chunk_size {
@ -3751,21 +3923,21 @@ impl<'a, T> DoubleEndedIterator for ExactChunks<'a, T> {
}
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> ExactSizeIterator for ChunksExact<'a, T> {
fn is_empty(&self) -> bool {
self.v.is_empty()
}
}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<'a, T> TrustedLen for ExactChunks<'a, T> {}
unsafe impl<'a, T> TrustedLen for ChunksExact<'a, T> {}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> FusedIterator for ExactChunks<'a, T> {}
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> FusedIterator for ChunksExact<'a, T> {}
#[doc(hidden)]
unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
let start = i * self.chunk_size;
from_raw_parts(self.v.as_ptr().add(start), self.chunk_size)
@ -3780,21 +3952,21 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
/// `chunk_size-1` elements will be omitted but can be retrieved from the
/// [`into_remainder`] function from the iterator.
///
/// This struct is created by the [`exact_chunks_mut`] method on [slices].
/// This struct is created by the [`chunks_exact_mut`] method on [slices].
///
/// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut
/// [`into_remainder`]: ../../std/slice/struct.ExactChunksMut.html#method.into_remainder
/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut
/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder
/// [slices]: ../../std/primitive.slice.html
#[derive(Debug)]
#[unstable(feature = "exact_chunks", issue = "47115")]
pub struct ExactChunksMut<'a, T:'a> {
#[unstable(feature = "chunks_exact", issue = "47115")]
pub struct ChunksExactMut<'a, T:'a> {
v: &'a mut [T],
rem: &'a mut [T],
chunk_size: usize
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> ExactChunksMut<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> ChunksExactMut<'a, T> {
/// Return the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
@ -3803,8 +3975,8 @@ impl<'a, T> ExactChunksMut<'a, T> {
}
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> Iterator for ExactChunksMut<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> Iterator for ChunksExactMut<'a, T> {
type Item = &'a mut [T];
#[inline]
@ -3850,8 +4022,8 @@ impl<'a, T> Iterator for ExactChunksMut<'a, T> {
}
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> DoubleEndedIterator for ExactChunksMut<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a mut [T]> {
if self.v.len() < self.chunk_size {
@ -3866,21 +4038,21 @@ impl<'a, T> DoubleEndedIterator for ExactChunksMut<'a, T> {
}
}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> {
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> ExactSizeIterator for ChunksExactMut<'a, T> {
fn is_empty(&self) -> bool {
self.v.is_empty()
}
}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<'a, T> TrustedLen for ExactChunksMut<'a, T> {}
unsafe impl<'a, T> TrustedLen for ChunksExactMut<'a, T> {}
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {}
#[unstable(feature = "chunks_exact", issue = "47115")]
impl<'a, T> FusedIterator for ChunksExactMut<'a, T> {}
#[doc(hidden)]
unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> {
unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
let start = i * self.chunk_size;
from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size)

View file

@ -33,12 +33,13 @@
#![feature(trusted_len)]
#![feature(try_from)]
#![feature(try_trait)]
#![feature(exact_chunks)]
#![feature(chunks_exact)]
#![feature(align_offset)]
#![feature(reverse_bits)]
#![feature(inner_deref)]
#![feature(slice_internals)]
#![feature(option_replace)]
#![feature(slice_partition_dedup)]
#![feature(copy_within)]
extern crate core;

View file

@ -221,115 +221,115 @@ fn test_chunks_mut_zip() {
}
#[test]
fn test_exact_chunks_count() {
fn test_chunks_exact_count() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
let c = v.exact_chunks(3);
let c = v.chunks_exact(3);
assert_eq!(c.count(), 2);
let v2: &[i32] = &[0, 1, 2, 3, 4];
let c2 = v2.exact_chunks(2);
let c2 = v2.chunks_exact(2);
assert_eq!(c2.count(), 2);
let v3: &[i32] = &[];
let c3 = v3.exact_chunks(2);
let c3 = v3.chunks_exact(2);
assert_eq!(c3.count(), 0);
}
#[test]
fn test_exact_chunks_nth() {
fn test_chunks_exact_nth() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
let mut c = v.exact_chunks(2);
let mut c = v.chunks_exact(2);
assert_eq!(c.nth(1).unwrap(), &[2, 3]);
assert_eq!(c.next().unwrap(), &[4, 5]);
let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
let mut c2 = v2.exact_chunks(3);
let mut c2 = v2.chunks_exact(3);
assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
assert_eq!(c2.next(), None);
}
#[test]
fn test_exact_chunks_last() {
fn test_chunks_exact_last() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
let c = v.exact_chunks(2);
let c = v.chunks_exact(2);
assert_eq!(c.last().unwrap(), &[4, 5]);
let v2: &[i32] = &[0, 1, 2, 3, 4];
let c2 = v2.exact_chunks(2);
let c2 = v2.chunks_exact(2);
assert_eq!(c2.last().unwrap(), &[2, 3]);
}
#[test]
fn test_exact_chunks_remainder() {
fn test_chunks_exact_remainder() {
let v: &[i32] = &[0, 1, 2, 3, 4];
let c = v.exact_chunks(2);
let c = v.chunks_exact(2);
assert_eq!(c.remainder(), &[4]);
}
#[test]
fn test_exact_chunks_zip() {
fn test_chunks_exact_zip() {
let v1: &[i32] = &[0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
let res = v1.exact_chunks(2)
.zip(v2.exact_chunks(2))
let res = v1.chunks_exact(2)
.zip(v2.chunks_exact(2))
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
.collect::<Vec<_>>();
assert_eq!(res, vec![14, 22]);
}
#[test]
fn test_exact_chunks_mut_count() {
fn test_chunks_exact_mut_count() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
let c = v.exact_chunks_mut(3);
let c = v.chunks_exact_mut(3);
assert_eq!(c.count(), 2);
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
let c2 = v2.exact_chunks_mut(2);
let c2 = v2.chunks_exact_mut(2);
assert_eq!(c2.count(), 2);
let v3: &mut [i32] = &mut [];
let c3 = v3.exact_chunks_mut(2);
let c3 = v3.chunks_exact_mut(2);
assert_eq!(c3.count(), 0);
}
#[test]
fn test_exact_chunks_mut_nth() {
fn test_chunks_exact_mut_nth() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
let mut c = v.exact_chunks_mut(2);
let mut c = v.chunks_exact_mut(2);
assert_eq!(c.nth(1).unwrap(), &[2, 3]);
assert_eq!(c.next().unwrap(), &[4, 5]);
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
let mut c2 = v2.exact_chunks_mut(3);
let mut c2 = v2.chunks_exact_mut(3);
assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
assert_eq!(c2.next(), None);
}
#[test]
fn test_exact_chunks_mut_last() {
fn test_chunks_exact_mut_last() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
let c = v.exact_chunks_mut(2);
let c = v.chunks_exact_mut(2);
assert_eq!(c.last().unwrap(), &[4, 5]);
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
let c2 = v2.exact_chunks_mut(2);
let c2 = v2.chunks_exact_mut(2);
assert_eq!(c2.last().unwrap(), &[2, 3]);
}
#[test]
fn test_exact_chunks_mut_remainder() {
fn test_chunks_exact_mut_remainder() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
let c = v.exact_chunks_mut(2);
let c = v.chunks_exact_mut(2);
assert_eq!(c.into_remainder(), &[4]);
}
#[test]
fn test_exact_chunks_mut_zip() {
fn test_chunks_exact_mut_zip() {
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
for (a, b) in v1.exact_chunks_mut(2).zip(v2.exact_chunks(2)) {
for (a, b) in v1.chunks_exact_mut(2).zip(v2.chunks_exact(2)) {
let sum = b.iter().sum::<i32>();
for v in a {
*v += sum;
@ -1001,6 +1001,65 @@ fn test_align_to_empty_mid() {
}
}
#[test]
fn test_slice_partition_dedup_by() {
let mut slice: [i32; 9] = [1, -1, 2, 3, 1, -5, 5, -2, 2];
let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.abs() == b.abs());
assert_eq!(dedup, [1, 2, 3, 1, -5, -2]);
assert_eq!(duplicates, [5, -1, 2]);
}
#[test]
fn test_slice_partition_dedup_empty() {
let mut slice: [i32; 0] = [];
let (dedup, duplicates) = slice.partition_dedup();
assert_eq!(dedup, []);
assert_eq!(duplicates, []);
}
#[test]
fn test_slice_partition_dedup_one() {
let mut slice = [12];
let (dedup, duplicates) = slice.partition_dedup();
assert_eq!(dedup, [12]);
assert_eq!(duplicates, []);
}
#[test]
fn test_slice_partition_dedup_multiple_ident() {
let mut slice = [12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11];
let (dedup, duplicates) = slice.partition_dedup();
assert_eq!(dedup, [12, 11]);
assert_eq!(duplicates, [12, 12, 12, 12, 11, 11, 11, 11, 11]);
}
#[test]
fn test_slice_partition_dedup_partialeq() {
#[derive(Debug)]
struct Foo(i32, i32);
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
self.0 == other.0
}
}
let mut slice = [Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)];
let (dedup, duplicates) = slice.partition_dedup();
assert_eq!(dedup, [Foo(0, 1), Foo(1, 7)]);
assert_eq!(duplicates, [Foo(0, 5), Foo(1, 9)]);
}
#[test]
fn test_copy_within() {
// Start to end, with a RangeTo.

View file

@ -646,7 +646,6 @@ impl Options {
match self.debugging_opts.share_generics {
Some(setting) => setting,
None => {
self.incremental.is_some() ||
match self.optimize {
OptLevel::No |
OptLevel::Less |

View file

@ -575,6 +575,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// 5. Standard library prelude (de-facto closed, controlled).
// 6. Language prelude (closed, controlled).
// (Macro NS)
// 0. Derive helpers (open, not controlled). All ambiguities with other names
// are currently reported as errors. They should be higher in priority than preludes
// and probably even names in modules according to the "general principles" above. They
// also should be subject to restricted shadowing because are effectively produced by
// derives (you need to resolve the derive first to add helpers into scope), but they
// should be available before the derive is expanded for compatibility.
// It's mess in general, so we are being conservative for now.
// 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// (open, not controlled).
// 2. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
@ -583,13 +590,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
// 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
// 4. Language prelude: builtin attributes (closed, controlled).
// N (unordered). Derive helpers (open, not controlled). All ambiguities with other names
// are currently reported as errors. They should be higher in priority than preludes
// and maybe even names in modules according to the "general principles" above. They
// also should be subject to restricted shadowing because are effectively produced by
// derives (you need to resolve the derive first to add helpers into scope), but they
// should be available before the derive is expanded for compatibility.
// It's mess in general, so we are being conservative for now.
assert!(ns == TypeNS || ns == MacroNS);
assert!(force || !record_used); // `record_used` implies `force`
@ -621,7 +621,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = WhereToResolve::Module(parent_scope.module);
let mut where_to_resolve = WhereToResolve::DeriveHelpers;
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
loop {
let result = match where_to_resolve {
@ -751,8 +751,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
WhereToResolve::BuiltinAttrs => WhereToResolve::DeriveHelpers,
WhereToResolve::DeriveHelpers => break, // nowhere else to search
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
WhereToResolve::DeriveHelpers => WhereToResolve::Module(parent_scope.module),
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,

View file

@ -1991,8 +1991,11 @@
}
};
if (getCurrentValue('rustdoc-trait-implementations') !== "false") {
onEach(document.getElementById('implementations-list')
.getElementsByClassName("collapse-toggle"), collapser);
var impl_list = document.getElementById('implementations-list');
if (impl_list !== null) {
onEach(impl_list.getElementsByClassName("collapse-toggle"), collapser);
}
}
if (getCurrentValue('rustdoc-method-docs') !== "false") {
var implItems = document.getElementsByClassName('impl-items');

View file

@ -139,7 +139,7 @@ code, pre {
}
.docblock code, .docblock-short code {
border-radius: 3px;
padding: 0 0.2em;
padding: 0 0.1em;
}
.docblock pre code, .docblock-short pre code, .docblock code.spotlight {
padding: 0;

View file

@ -208,7 +208,7 @@ mod prim_bool { }
/// # `!` and traits
///
/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
/// which doesn't `panic!`. As is turns out, most traits can have an `impl` for `!`. Take [`Debug`]
/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`]
/// for example:
///
/// ```
@ -228,9 +228,9 @@ mod prim_bool { }
/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
/// called (because there is no value of type `!` for it to be called with). Writing `*self`
/// essentially tells the compiler "We know that this code can never be run, so just treat the
/// entire function body has having type [`fmt::Result`]". This pattern can be used a lot when
/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when
/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
/// parameter should have such as impl.
/// parameter should have such an impl.
///
/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
///

View file

@ -45,9 +45,17 @@
extern crate getopts;
#[cfg(any(unix, target_os = "cloudabi"))]
extern crate libc;
extern crate panic_unwind;
extern crate term;
// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
// on aarch64-pc-windows-msvc, so we don't link libtest against
// libunwind (for the time being), even though it means that
// libtest won't be fully functional on this platform.
//
// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
#[cfg(not(all(windows, target_arch = "aarch64")))]
extern crate panic_unwind;
pub use self::TestFn::*;
pub use self::ColorConfig::*;
pub use self::TestResult::*;

View file

@ -11,13 +11,11 @@
// aux-build:derive-b.rs
// ignore-stage1
#![allow(warnings)]
#[macro_use]
extern crate derive_b;
#[B] //~ ERROR `B` is a derive mode
#[C]
#[B]
#[C] //~ ERROR attribute `C` is currently unknown to the compiler
#[B(D)]
#[B(E = "foo")]
#[B(arbitrary tokens)]

View file

@ -25,3 +25,13 @@ pub fn derive_foo(input: TokenStream) -> TokenStream {
pub fn derive_bar(input: TokenStream) -> TokenStream {
panic!("lolnope");
}
#[proc_macro_derive(WithHelper, attributes(helper))]
pub fn with_helper(input: TokenStream) -> TokenStream {
TokenStream::new()
}
#[proc_macro_attribute]
pub fn helper(_: TokenStream, input: TokenStream) -> TokenStream {
input
}

View file

@ -0,0 +1,13 @@
// aux-build:plugin.rs
// ignore-stage1
#[macro_use(WithHelper)]
extern crate plugin;
use plugin::helper;
#[derive(WithHelper)]
#[helper] //~ ERROR `helper` is ambiguous
struct S;
fn main() {}

View file

@ -0,0 +1,20 @@
error[E0659]: `helper` is ambiguous
--> $DIR/helper-attr-blocked-by-import-ambig.rs:10:3
|
LL | #[helper] //~ ERROR `helper` is ambiguous
| ^^^^^^ ambiguous name
|
note: `helper` could refer to the name defined here
--> $DIR/helper-attr-blocked-by-import-ambig.rs:9:10
|
LL | #[derive(WithHelper)]
| ^^^^^^^^^^
note: `helper` could also refer to the name imported here
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:5
|
LL | use plugin::helper;
| ^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0659`.

View file

@ -0,0 +1,29 @@
// compile-pass
// aux-build:plugin.rs
// ignore-stage1
#[macro_use(WithHelper)]
extern crate plugin;
use self::one::*;
use self::two::*;
mod helper {}
mod one {
use helper;
#[derive(WithHelper)]
#[helper]
struct One;
}
mod two {
use helper;
#[derive(WithHelper)]
#[helper]
struct Two;
}
fn main() {}

View file

@ -4,17 +4,16 @@ error[E0659]: `my_attr` is ambiguous
LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
| ^^^^^^^ ambiguous name
|
note: `my_attr` could refer to the name imported here
--> $DIR/derive-helper-shadowing.rs:4:5
|
LL | use derive_helper_shadowing::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: `my_attr` could also refer to the name defined here
note: `my_attr` could refer to the name defined here
--> $DIR/derive-helper-shadowing.rs:7:10
|
LL | #[derive(MyTrait)]
| ^^^^^^^
= note: consider adding an explicit import of `my_attr` to disambiguate
note: `my_attr` could also refer to the name imported here
--> $DIR/derive-helper-shadowing.rs:4:5
|
LL | use derive_helper_shadowing::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error