Auto merge of #57577 - Centril:rollup, r=Centril
Rollup of 4 pull requests Successful merges: - #57004 (Make `TokenStream` less recursive.) - #57102 (NLL: Add union justifications to conflicting borrows.) - #57337 (rustc: Place wasm linker args first instead of last) - #57549 (Add #[must_use] message to Iterator and Future) Failed merges: r? @ghost
This commit is contained in:
commit
2cf736f765
28 changed files with 601 additions and 579 deletions
|
@ -23,7 +23,7 @@ use task::{Poll, LocalWaker};
|
||||||
///
|
///
|
||||||
/// When using a future, you generally won't call `poll` directly, but instead
|
/// When using a future, you generally won't call `poll` directly, but instead
|
||||||
/// `await!` the value.
|
/// `await!` the value.
|
||||||
#[must_use]
|
#[must_use = "futures do nothing unless polled"]
|
||||||
pub trait Future {
|
pub trait Future {
|
||||||
/// The result of the `Future`.
|
/// The result of the `Future`.
|
||||||
type Output;
|
type Output;
|
||||||
|
|
|
@ -88,7 +88,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item=()>) {}
|
||||||
message="`{Self}` is not an iterator"
|
message="`{Self}` is not an iterator"
|
||||||
)]
|
)]
|
||||||
#[doc(spotlight)]
|
#[doc(spotlight)]
|
||||||
#[must_use]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
pub trait Iterator {
|
pub trait Iterator {
|
||||||
/// The type of the elements being iterated over.
|
/// The type of the elements being iterated over.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
|
@ -243,7 +243,7 @@
|
||||||
//! using it. The compiler will warn us about this kind of behavior:
|
//! using it. The compiler will warn us about this kind of behavior:
|
||||||
//!
|
//!
|
||||||
//! ```text
|
//! ```text
|
||||||
//! warning: unused result that must be used: iterator adaptors are lazy and
|
//! warning: unused result that must be used: iterators are lazy and
|
||||||
//! do nothing unless consumed
|
//! do nothing unless consumed
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -404,7 +404,7 @@ impl<R: Try> LoopState<R::Ok, R> {
|
||||||
/// [`rev`]: trait.Iterator.html#method.rev
|
/// [`rev`]: trait.Iterator.html#method.rev
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Rev<T> {
|
pub struct Rev<T> {
|
||||||
iter: T
|
iter: T
|
||||||
|
@ -505,7 +505,7 @@ unsafe impl<I> TrustedLen for Rev<I>
|
||||||
/// [`copied`]: trait.Iterator.html#method.copied
|
/// [`copied`]: trait.Iterator.html#method.copied
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[unstable(feature = "iter_copied", issue = "57127")]
|
#[unstable(feature = "iter_copied", issue = "57127")]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Copied<I> {
|
pub struct Copied<I> {
|
||||||
it: I,
|
it: I,
|
||||||
|
@ -605,7 +605,7 @@ unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
|
||||||
/// [`cloned`]: trait.Iterator.html#method.cloned
|
/// [`cloned`]: trait.Iterator.html#method.cloned
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cloned<I> {
|
pub struct Cloned<I> {
|
||||||
it: I,
|
it: I,
|
||||||
|
@ -717,7 +717,7 @@ unsafe impl<'a, I, T: 'a> TrustedLen for Cloned<I>
|
||||||
/// [`cycle`]: trait.Iterator.html#method.cycle
|
/// [`cycle`]: trait.Iterator.html#method.cycle
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Cycle<I> {
|
pub struct Cycle<I> {
|
||||||
orig: I,
|
orig: I,
|
||||||
|
@ -757,7 +757,7 @@ impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
|
||||||
///
|
///
|
||||||
/// [`step_by`]: trait.Iterator.html#method.step_by
|
/// [`step_by`]: trait.Iterator.html#method.step_by
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "iterator_step_by", since = "1.28.0")]
|
#[stable(feature = "iterator_step_by", since = "1.28.0")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StepBy<I> {
|
pub struct StepBy<I> {
|
||||||
|
@ -849,7 +849,7 @@ impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
|
||||||
/// [`chain`]: trait.Iterator.html#method.chain
|
/// [`chain`]: trait.Iterator.html#method.chain
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Chain<A, B> {
|
pub struct Chain<A, B> {
|
||||||
a: A,
|
a: A,
|
||||||
|
@ -1100,7 +1100,7 @@ unsafe impl<A, B> TrustedLen for Chain<A, B>
|
||||||
/// [`zip`]: trait.Iterator.html#method.zip
|
/// [`zip`]: trait.Iterator.html#method.zip
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Zip<A, B> {
|
pub struct Zip<A, B> {
|
||||||
a: A,
|
a: A,
|
||||||
|
@ -1400,7 +1400,7 @@ unsafe impl<A, B> TrustedLen for Zip<A, B>
|
||||||
/// println!("{:?}", pair);
|
/// println!("{:?}", pair);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Map<I, F> {
|
pub struct Map<I, F> {
|
||||||
|
@ -1511,7 +1511,7 @@ unsafe impl<B, I, F> TrustedRandomAccess for Map<I, F>
|
||||||
///
|
///
|
||||||
/// [`filter`]: trait.Iterator.html#method.filter
|
/// [`filter`]: trait.Iterator.html#method.filter
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Filter<I, P> {
|
pub struct Filter<I, P> {
|
||||||
|
@ -1643,7 +1643,7 @@ impl<I: FusedIterator, P> FusedIterator for Filter<I, P>
|
||||||
///
|
///
|
||||||
/// [`filter_map`]: trait.Iterator.html#method.filter_map
|
/// [`filter_map`]: trait.Iterator.html#method.filter_map
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FilterMap<I, F> {
|
pub struct FilterMap<I, F> {
|
||||||
|
@ -1754,7 +1754,7 @@ impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F>
|
||||||
/// [`enumerate`]: trait.Iterator.html#method.enumerate
|
/// [`enumerate`]: trait.Iterator.html#method.enumerate
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Enumerate<I> {
|
pub struct Enumerate<I> {
|
||||||
iter: I,
|
iter: I,
|
||||||
|
@ -1915,7 +1915,7 @@ unsafe impl<I> TrustedLen for Enumerate<I>
|
||||||
/// [`peekable`]: trait.Iterator.html#method.peekable
|
/// [`peekable`]: trait.Iterator.html#method.peekable
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Peekable<I: Iterator> {
|
pub struct Peekable<I: Iterator> {
|
||||||
iter: I,
|
iter: I,
|
||||||
|
@ -2066,7 +2066,7 @@ impl<I: Iterator> Peekable<I> {
|
||||||
///
|
///
|
||||||
/// [`skip_while`]: trait.Iterator.html#method.skip_while
|
/// [`skip_while`]: trait.Iterator.html#method.skip_while
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SkipWhile<I, P> {
|
pub struct SkipWhile<I, P> {
|
||||||
|
@ -2149,7 +2149,7 @@ impl<I, P> FusedIterator for SkipWhile<I, P>
|
||||||
///
|
///
|
||||||
/// [`take_while`]: trait.Iterator.html#method.take_while
|
/// [`take_while`]: trait.Iterator.html#method.take_while
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TakeWhile<I, P> {
|
pub struct TakeWhile<I, P> {
|
||||||
|
@ -2233,7 +2233,7 @@ impl<I, P> FusedIterator for TakeWhile<I, P>
|
||||||
/// [`skip`]: trait.Iterator.html#method.skip
|
/// [`skip`]: trait.Iterator.html#method.skip
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Skip<I> {
|
pub struct Skip<I> {
|
||||||
iter: I,
|
iter: I,
|
||||||
|
@ -2371,7 +2371,7 @@ impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
|
||||||
/// [`take`]: trait.Iterator.html#method.take
|
/// [`take`]: trait.Iterator.html#method.take
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Take<I> {
|
pub struct Take<I> {
|
||||||
iter: I,
|
iter: I,
|
||||||
|
@ -2458,7 +2458,7 @@ unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
|
||||||
///
|
///
|
||||||
/// [`scan`]: trait.Iterator.html#method.scan
|
/// [`scan`]: trait.Iterator.html#method.scan
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scan<I, St, F> {
|
pub struct Scan<I, St, F> {
|
||||||
|
@ -2518,7 +2518,7 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
|
||||||
///
|
///
|
||||||
/// [`flat_map`]: trait.Iterator.html#method.flat_map
|
/// [`flat_map`]: trait.Iterator.html#method.flat_map
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct FlatMap<I, U: IntoIterator, F> {
|
pub struct FlatMap<I, U: IntoIterator, F> {
|
||||||
inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
|
inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
|
||||||
|
@ -2603,7 +2603,7 @@ impl<I, U, F> FusedIterator for FlatMap<I, U, F>
|
||||||
///
|
///
|
||||||
/// [`flatten`]: trait.Iterator.html#method.flatten
|
/// [`flatten`]: trait.Iterator.html#method.flatten
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "iterator_flatten", since = "1.29.0")]
|
#[stable(feature = "iterator_flatten", since = "1.29.0")]
|
||||||
pub struct Flatten<I: Iterator>
|
pub struct Flatten<I: Iterator>
|
||||||
where I::Item: IntoIterator {
|
where I::Item: IntoIterator {
|
||||||
|
@ -2832,7 +2832,7 @@ impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
|
||||||
/// [`fuse`]: trait.Iterator.html#method.fuse
|
/// [`fuse`]: trait.Iterator.html#method.fuse
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Fuse<I> {
|
pub struct Fuse<I> {
|
||||||
iter: I,
|
iter: I,
|
||||||
|
@ -3056,7 +3056,7 @@ impl<I> ExactSizeIterator for Fuse<I> where I: ExactSizeIterator {
|
||||||
///
|
///
|
||||||
/// [`inspect`]: trait.Iterator.html#method.inspect
|
/// [`inspect`]: trait.Iterator.html#method.inspect
|
||||||
/// [`Iterator`]: trait.Iterator.html
|
/// [`Iterator`]: trait.Iterator.html
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Inspect<I, F> {
|
pub struct Inspect<I, F> {
|
||||||
|
|
|
@ -557,12 +557,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() {
|
if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() {
|
||||||
let nl = self.bccx.loan_path_to_string(&common.unwrap());
|
let nl = self.bccx.loan_path_to_string(&common.unwrap());
|
||||||
let ol = nl.clone();
|
let ol = nl.clone();
|
||||||
let new_loan_msg = format!(" (via `{}`)",
|
let new_loan_msg = self.bccx.loan_path_to_string(&new_loan.loan_path);
|
||||||
self.bccx.loan_path_to_string(
|
let old_loan_msg = self.bccx.loan_path_to_string(&old_loan.loan_path);
|
||||||
&new_loan.loan_path));
|
|
||||||
let old_loan_msg = format!(" (via `{}`)",
|
|
||||||
self.bccx.loan_path_to_string(
|
|
||||||
&old_loan.loan_path));
|
|
||||||
(nl, ol, new_loan_msg, old_loan_msg)
|
(nl, ol, new_loan_msg, old_loan_msg)
|
||||||
} else {
|
} else {
|
||||||
(self.bccx.loan_path_to_string(&new_loan.loan_path),
|
(self.bccx.loan_path_to_string(&new_loan.loan_path),
|
||||||
|
|
|
@ -81,11 +81,7 @@ impl LinkerInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkerFlavor::Lld(LldFlavor::Wasm) => {
|
LinkerFlavor::Lld(LldFlavor::Wasm) => {
|
||||||
Box::new(WasmLd {
|
Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
|
||||||
cmd,
|
|
||||||
sess,
|
|
||||||
info: self
|
|
||||||
}) as Box<dyn Linker>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,6 +872,67 @@ pub struct WasmLd<'a> {
|
||||||
info: &'a LinkerInfo,
|
info: &'a LinkerInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> WasmLd<'a> {
|
||||||
|
fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
|
||||||
|
// There have been reports in the wild (rustwasm/wasm-bindgen#119) of
|
||||||
|
// using threads causing weird hangs and bugs. Disable it entirely as
|
||||||
|
// this isn't yet the bottleneck of compilation at all anyway.
|
||||||
|
cmd.arg("--no-threads");
|
||||||
|
|
||||||
|
// By default LLD only gives us one page of stack (64k) which is a
|
||||||
|
// little small. Default to a larger stack closer to other PC platforms
|
||||||
|
// (1MB) and users can always inject their own link-args to override this.
|
||||||
|
cmd.arg("-z").arg("stack-size=1048576");
|
||||||
|
|
||||||
|
// By default LLD's memory layout is:
|
||||||
|
//
|
||||||
|
// 1. First, a blank page
|
||||||
|
// 2. Next, all static data
|
||||||
|
// 3. Finally, the main stack (which grows down)
|
||||||
|
//
|
||||||
|
// This has the unfortunate consequence that on stack overflows you
|
||||||
|
// corrupt static data and can cause some exceedingly weird bugs. To
|
||||||
|
// help detect this a little sooner we instead request that the stack is
|
||||||
|
// placed before static data.
|
||||||
|
//
|
||||||
|
// This means that we'll generate slightly larger binaries as references
|
||||||
|
// to static data will take more bytes in the ULEB128 encoding, but
|
||||||
|
// stack overflow will be guaranteed to trap as it underflows instead of
|
||||||
|
// corrupting static data.
|
||||||
|
cmd.arg("--stack-first");
|
||||||
|
|
||||||
|
// FIXME we probably shouldn't pass this but instead pass an explicit
|
||||||
|
// whitelist of symbols we'll allow to be undefined. Unfortunately
|
||||||
|
// though we can't handle symbols like `log10` that LLVM injects at a
|
||||||
|
// super late date without actually parsing object files. For now let's
|
||||||
|
// stick to this and hopefully fix it before stabilization happens.
|
||||||
|
cmd.arg("--allow-undefined");
|
||||||
|
|
||||||
|
// For now we just never have an entry symbol
|
||||||
|
cmd.arg("--no-entry");
|
||||||
|
|
||||||
|
// Make the default table accessible
|
||||||
|
cmd.arg("--export-table");
|
||||||
|
|
||||||
|
// Rust code should never have warnings, and warnings are often
|
||||||
|
// indicative of bugs, let's prevent them.
|
||||||
|
cmd.arg("--fatal-warnings");
|
||||||
|
|
||||||
|
// The symbol visibility story is a bit in flux right now with LLD.
|
||||||
|
// It's... not entirely clear to me what's going on, but this looks to
|
||||||
|
// make everything work when `export_symbols` isn't otherwise called for
|
||||||
|
// things like executables.
|
||||||
|
cmd.arg("--export-dynamic");
|
||||||
|
|
||||||
|
// LLD only implements C++-like demangling, which doesn't match our own
|
||||||
|
// mangling scheme. Tell LLD to not demangle anything and leave it up to
|
||||||
|
// us to demangle these symbols later.
|
||||||
|
cmd.arg("--no-demangle");
|
||||||
|
|
||||||
|
WasmLd { cmd, sess, info }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Linker for WasmLd<'a> {
|
impl<'a> Linker for WasmLd<'a> {
|
||||||
fn link_dylib(&mut self, lib: &str) {
|
fn link_dylib(&mut self, lib: &str) {
|
||||||
self.cmd.arg("-l").arg(lib);
|
self.cmd.arg("-l").arg(lib);
|
||||||
|
@ -982,61 +1039,6 @@ impl<'a> Linker for WasmLd<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize(&mut self) -> Command {
|
fn finalize(&mut self) -> Command {
|
||||||
// There have been reports in the wild (rustwasm/wasm-bindgen#119) of
|
|
||||||
// using threads causing weird hangs and bugs. Disable it entirely as
|
|
||||||
// this isn't yet the bottleneck of compilation at all anyway.
|
|
||||||
self.cmd.arg("--no-threads");
|
|
||||||
|
|
||||||
// By default LLD only gives us one page of stack (64k) which is a
|
|
||||||
// little small. Default to a larger stack closer to other PC platforms
|
|
||||||
// (1MB) and users can always inject their own link-args to override this.
|
|
||||||
self.cmd.arg("-z").arg("stack-size=1048576");
|
|
||||||
|
|
||||||
// By default LLD's memory layout is:
|
|
||||||
//
|
|
||||||
// 1. First, a blank page
|
|
||||||
// 2. Next, all static data
|
|
||||||
// 3. Finally, the main stack (which grows down)
|
|
||||||
//
|
|
||||||
// This has the unfortunate consequence that on stack overflows you
|
|
||||||
// corrupt static data and can cause some exceedingly weird bugs. To
|
|
||||||
// help detect this a little sooner we instead request that the stack is
|
|
||||||
// placed before static data.
|
|
||||||
//
|
|
||||||
// This means that we'll generate slightly larger binaries as references
|
|
||||||
// to static data will take more bytes in the ULEB128 encoding, but
|
|
||||||
// stack overflow will be guaranteed to trap as it underflows instead of
|
|
||||||
// corrupting static data.
|
|
||||||
self.cmd.arg("--stack-first");
|
|
||||||
|
|
||||||
// FIXME we probably shouldn't pass this but instead pass an explicit
|
|
||||||
// whitelist of symbols we'll allow to be undefined. Unfortunately
|
|
||||||
// though we can't handle symbols like `log10` that LLVM injects at a
|
|
||||||
// super late date without actually parsing object files. For now let's
|
|
||||||
// stick to this and hopefully fix it before stabilization happens.
|
|
||||||
self.cmd.arg("--allow-undefined");
|
|
||||||
|
|
||||||
// For now we just never have an entry symbol
|
|
||||||
self.cmd.arg("--no-entry");
|
|
||||||
|
|
||||||
// Make the default table accessible
|
|
||||||
self.cmd.arg("--export-table");
|
|
||||||
|
|
||||||
// Rust code should never have warnings, and warnings are often
|
|
||||||
// indicative of bugs, let's prevent them.
|
|
||||||
self.cmd.arg("--fatal-warnings");
|
|
||||||
|
|
||||||
// The symbol visibility story is a bit in flux right now with LLD.
|
|
||||||
// It's... not entirely clear to me what's going on, but this looks to
|
|
||||||
// make everything work when `export_symbols` isn't otherwise called for
|
|
||||||
// things like executables.
|
|
||||||
self.cmd.arg("--export-dynamic");
|
|
||||||
|
|
||||||
// LLD only implements C++-like demangling, which doesn't match our own
|
|
||||||
// mangling scheme. Tell LLD to not demangle anything and leave it up to
|
|
||||||
// us to demangle these symbols later.
|
|
||||||
self.cmd.arg("--no-demangle");
|
|
||||||
|
|
||||||
::std::mem::replace(&mut self.cmd, Command::new(""))
|
::std::mem::replace(&mut self.cmd, Command::new(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -327,10 +327,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
"closure"
|
"closure"
|
||||||
};
|
};
|
||||||
|
|
||||||
let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
|
let (desc_place, msg_place, msg_borrow, union_type_name) =
|
||||||
let tcx = self.infcx.tcx;
|
self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
|
||||||
|
|
||||||
let first_borrow_desc;
|
|
||||||
|
|
||||||
let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None);
|
let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None);
|
||||||
let second_borrow_desc = if explanation.is_explained() {
|
let second_borrow_desc = if explanation.is_explained() {
|
||||||
|
@ -340,6 +338,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: supply non-"" `opt_via` when appropriate
|
// FIXME: supply non-"" `opt_via` when appropriate
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
let first_borrow_desc;
|
||||||
let mut err = match (
|
let mut err = match (
|
||||||
gen_borrow_kind,
|
gen_borrow_kind,
|
||||||
"immutable",
|
"immutable",
|
||||||
|
@ -353,12 +353,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
tcx.cannot_reborrow_already_borrowed(
|
tcx.cannot_reborrow_already_borrowed(
|
||||||
span,
|
span,
|
||||||
&desc_place,
|
&desc_place,
|
||||||
"",
|
&msg_place,
|
||||||
lft,
|
lft,
|
||||||
issued_span,
|
issued_span,
|
||||||
"it",
|
"it",
|
||||||
rgt,
|
rgt,
|
||||||
"",
|
&msg_borrow,
|
||||||
None,
|
None,
|
||||||
Origin::Mir,
|
Origin::Mir,
|
||||||
)
|
)
|
||||||
|
@ -368,12 +368,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
tcx.cannot_reborrow_already_borrowed(
|
tcx.cannot_reborrow_already_borrowed(
|
||||||
span,
|
span,
|
||||||
&desc_place,
|
&desc_place,
|
||||||
"",
|
&msg_place,
|
||||||
lft,
|
lft,
|
||||||
issued_span,
|
issued_span,
|
||||||
"it",
|
"it",
|
||||||
rgt,
|
rgt,
|
||||||
"",
|
&msg_borrow,
|
||||||
None,
|
None,
|
||||||
Origin::Mir,
|
Origin::Mir,
|
||||||
)
|
)
|
||||||
|
@ -384,9 +384,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
tcx.cannot_mutably_borrow_multiply(
|
tcx.cannot_mutably_borrow_multiply(
|
||||||
span,
|
span,
|
||||||
&desc_place,
|
&desc_place,
|
||||||
"",
|
&msg_place,
|
||||||
issued_span,
|
issued_span,
|
||||||
"",
|
&msg_borrow,
|
||||||
None,
|
None,
|
||||||
Origin::Mir,
|
Origin::Mir,
|
||||||
)
|
)
|
||||||
|
@ -510,12 +510,118 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if union_type_name != "" {
|
||||||
|
err.note(&format!(
|
||||||
|
"`{}` is a field of the union `{}`, so it overlaps the field `{}`",
|
||||||
|
msg_place, union_type_name, msg_borrow,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
explanation
|
explanation
|
||||||
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, first_borrow_desc);
|
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, first_borrow_desc);
|
||||||
|
|
||||||
err.buffer(&mut self.errors_buffer);
|
err.buffer(&mut self.errors_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the description of the root place for a conflicting borrow and the full
|
||||||
|
/// descriptions of the places that caused the conflict.
|
||||||
|
///
|
||||||
|
/// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
|
||||||
|
/// attempted while a shared borrow is live, then this function will return:
|
||||||
|
///
|
||||||
|
/// ("x", "", "")
|
||||||
|
///
|
||||||
|
/// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
|
||||||
|
/// a shared borrow of another field `x.y`, then this function will return:
|
||||||
|
///
|
||||||
|
/// ("x", "x.z", "x.y")
|
||||||
|
///
|
||||||
|
/// In the more complex union case, where the union is a field of a struct, then if a mutable
|
||||||
|
/// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
|
||||||
|
/// another field `x.u.y`, then this function will return:
|
||||||
|
///
|
||||||
|
/// ("x.u", "x.u.z", "x.u.y")
|
||||||
|
///
|
||||||
|
/// This is used when creating error messages like below:
|
||||||
|
///
|
||||||
|
/// > cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
|
||||||
|
/// > mutable (via `a.u.s.b`) [E0502]
|
||||||
|
pub(super) fn describe_place_for_conflicting_borrow(
|
||||||
|
&self,
|
||||||
|
first_borrowed_place: &Place<'tcx>,
|
||||||
|
second_borrowed_place: &Place<'tcx>,
|
||||||
|
) -> (String, String, String, String) {
|
||||||
|
// Define a small closure that we can use to check if the type of a place
|
||||||
|
// is a union.
|
||||||
|
let is_union = |place: &Place<'tcx>| -> bool {
|
||||||
|
place.ty(self.mir, self.infcx.tcx)
|
||||||
|
.to_ty(self.infcx.tcx)
|
||||||
|
.ty_adt_def()
|
||||||
|
.map(|adt| adt.is_union())
|
||||||
|
.unwrap_or(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start with an empty tuple, so we can use the functions on `Option` to reduce some
|
||||||
|
// code duplication (particularly around returning an empty description in the failure
|
||||||
|
// case).
|
||||||
|
Some(())
|
||||||
|
.filter(|_| {
|
||||||
|
// If we have a conflicting borrow of the same place, then we don't want to add
|
||||||
|
// an extraneous "via x.y" to our diagnostics, so filter out this case.
|
||||||
|
first_borrowed_place != second_borrowed_place
|
||||||
|
})
|
||||||
|
.and_then(|_| {
|
||||||
|
// We're going to want to traverse the first borrowed place to see if we can find
|
||||||
|
// field access to a union. If we find that, then we will keep the place of the
|
||||||
|
// union being accessed and the field that was being accessed so we can check the
|
||||||
|
// second borrowed place for the same union and a access to a different field.
|
||||||
|
let mut current = first_borrowed_place;
|
||||||
|
while let Place::Projection(box PlaceProjection { base, elem }) = current {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Field(field, _) if is_union(base) => {
|
||||||
|
return Some((base, field));
|
||||||
|
},
|
||||||
|
_ => current = base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.and_then(|(target_base, target_field)| {
|
||||||
|
// With the place of a union and a field access into it, we traverse the second
|
||||||
|
// borrowed place and look for a access to a different field of the same union.
|
||||||
|
let mut current = second_borrowed_place;
|
||||||
|
while let Place::Projection(box PlaceProjection { base, elem }) = current {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Field(field, _) if {
|
||||||
|
is_union(base) && field != target_field && base == target_base
|
||||||
|
} => {
|
||||||
|
let desc_base = self.describe_place(base)
|
||||||
|
.unwrap_or_else(|| "_".to_owned());
|
||||||
|
let desc_first = self.describe_place(first_borrowed_place)
|
||||||
|
.unwrap_or_else(|| "_".to_owned());
|
||||||
|
let desc_second = self.describe_place(second_borrowed_place)
|
||||||
|
.unwrap_or_else(|| "_".to_owned());
|
||||||
|
|
||||||
|
// Also compute the name of the union type, eg. `Foo` so we
|
||||||
|
// can add a helpful note with it.
|
||||||
|
let ty = base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
|
||||||
|
|
||||||
|
return Some((desc_base, desc_first, desc_second, ty.to_string()));
|
||||||
|
},
|
||||||
|
_ => current = base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
// If we didn't find a field access into a union, or both places match, then
|
||||||
|
// only return the description of the first place.
|
||||||
|
let desc_place = self.describe_place(first_borrowed_place)
|
||||||
|
.unwrap_or_else(|| "_".to_owned());
|
||||||
|
(desc_place, "".to_string(), "".to_string(), "".to_string())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
|
/// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
|
||||||
///
|
///
|
||||||
/// This means that some data referenced by `borrow` needs to live
|
/// This means that some data referenced by `borrow` needs to live
|
||||||
|
|
|
@ -138,13 +138,15 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
old_load_end_span: Option<Span>,
|
old_load_end_span: Option<Span>,
|
||||||
o: Origin,
|
o: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
|
let via = |msg: &str|
|
||||||
|
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
E0499,
|
E0499,
|
||||||
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
|
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
|
||||||
desc,
|
desc,
|
||||||
opt_via,
|
via(opt_via),
|
||||||
OGN = o
|
OGN = o
|
||||||
);
|
);
|
||||||
if old_loan_span == new_loan_span {
|
if old_loan_span == new_loan_span {
|
||||||
|
@ -164,11 +166,11 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
} else {
|
} else {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
old_loan_span,
|
old_loan_span,
|
||||||
format!("first mutable borrow occurs here{}", old_opt_via),
|
format!("first mutable borrow occurs here{}", via(old_opt_via)),
|
||||||
);
|
);
|
||||||
err.span_label(
|
err.span_label(
|
||||||
new_loan_span,
|
new_loan_span,
|
||||||
format!("second mutable borrow occurs here{}", opt_via),
|
format!("second mutable borrow occurs here{}", via(opt_via)),
|
||||||
);
|
);
|
||||||
if let Some(old_load_end_span) = old_load_end_span {
|
if let Some(old_load_end_span) = old_load_end_span {
|
||||||
err.span_label(old_load_end_span, "first borrow ends here");
|
err.span_label(old_load_end_span, "first borrow ends here");
|
||||||
|
@ -292,27 +294,46 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
||||||
old_load_end_span: Option<Span>,
|
old_load_end_span: Option<Span>,
|
||||||
o: Origin,
|
o: Origin,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
|
let via = |msg: &str|
|
||||||
|
if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self,
|
self,
|
||||||
span,
|
span,
|
||||||
E0502,
|
E0502,
|
||||||
"cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
|
"cannot borrow `{}`{} as {} because {} is also borrowed \
|
||||||
|
as {}{}{OGN}",
|
||||||
desc_new,
|
desc_new,
|
||||||
msg_new,
|
via(msg_new),
|
||||||
kind_new,
|
kind_new,
|
||||||
noun_old,
|
noun_old,
|
||||||
kind_old,
|
kind_old,
|
||||||
msg_old,
|
via(msg_old),
|
||||||
OGN = o
|
OGN = o
|
||||||
);
|
);
|
||||||
err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
|
|
||||||
err.span_label(
|
if msg_new == "" {
|
||||||
old_span,
|
// If `msg_new` is empty, then this isn't a borrow of a union field.
|
||||||
format!("{} borrow occurs here{}", kind_old, msg_old),
|
err.span_label(span, format!("{} borrow occurs here", kind_new));
|
||||||
);
|
err.span_label(old_span, format!("{} borrow occurs here", kind_old));
|
||||||
|
} else {
|
||||||
|
// If `msg_new` isn't empty, then this a borrow of a union field.
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!(
|
||||||
|
"{} borrow of `{}` -- which overlaps with `{}` -- occurs here",
|
||||||
|
kind_new, msg_new, msg_old,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
err.span_label(
|
||||||
|
old_span,
|
||||||
|
format!("{} borrow occurs here{}", kind_old, via(msg_old)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(old_load_end_span) = old_load_end_span {
|
if let Some(old_load_end_span) = old_load_end_span {
|
||||||
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
|
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cancel_if_wrong_origin(err, o)
|
self.cancel_if_wrong_origin(err, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -472,7 +472,7 @@ impl MetaItem {
|
||||||
Token::from_ast_ident(segment.ident)).into());
|
Token::from_ast_ident(segment.ident)).into());
|
||||||
last_pos = segment.ident.span.hi();
|
last_pos = segment.ident.span.hi();
|
||||||
}
|
}
|
||||||
idents.push(self.node.tokens(self.span));
|
self.node.tokens(self.span).append_to_tree_and_joint_vec(&mut idents);
|
||||||
TokenStream::new(idents)
|
TokenStream::new(idents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +529,9 @@ impl MetaItemKind {
|
||||||
match *self {
|
match *self {
|
||||||
MetaItemKind::Word => TokenStream::empty(),
|
MetaItemKind::Word => TokenStream::empty(),
|
||||||
MetaItemKind::NameValue(ref lit) => {
|
MetaItemKind::NameValue(ref lit) => {
|
||||||
TokenStream::new(vec![TokenTree::Token(span, Token::Eq).into(), lit.tokens()])
|
let mut vec = vec![TokenTree::Token(span, Token::Eq).into()];
|
||||||
|
lit.tokens().append_to_tree_and_joint_vec(&mut vec);
|
||||||
|
TokenStream::new(vec)
|
||||||
}
|
}
|
||||||
MetaItemKind::List(ref list) => {
|
MetaItemKind::List(ref list) => {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
@ -537,7 +539,7 @@ impl MetaItemKind {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
tokens.push(TokenTree::Token(span, Token::Comma).into());
|
tokens.push(TokenTree::Token(span, Token::Comma).into());
|
||||||
}
|
}
|
||||||
tokens.push(item.node.tokens());
|
item.node.tokens().append_to_tree_and_joint_vec(&mut tokens);
|
||||||
}
|
}
|
||||||
TokenTree::Delimited(
|
TokenTree::Delimited(
|
||||||
DelimSpan::from_single(span),
|
DelimSpan::from_single(span),
|
||||||
|
|
|
@ -233,7 +233,7 @@ pub mod rt {
|
||||||
self.span, token::Token::from_ast_ident(segment.ident)
|
self.span, token::Token::from_ast_ident(segment.ident)
|
||||||
).into());
|
).into());
|
||||||
}
|
}
|
||||||
inner.push(self.tokens.clone());
|
self.tokens.clone().append_to_tree_and_joint_vec(&mut inner);
|
||||||
|
|
||||||
let delim_span = DelimSpan::from_single(self.span);
|
let delim_span = DelimSpan::from_single(self.span);
|
||||||
r.push(TokenTree::Delimited(
|
r.push(TokenTree::Delimited(
|
||||||
|
|
|
@ -7,7 +7,7 @@ use fold::noop_fold_tt;
|
||||||
use parse::token::{self, Token, NtTT};
|
use parse::token::{self, Token, NtTT};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
use tokenstream::{TokenStream, TokenTree, DelimSpan};
|
use tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
@ -63,7 +63,7 @@ pub fn transcribe(cx: &ExtCtxt,
|
||||||
let mut stack: SmallVec<[Frame; 1]> = smallvec![Frame::new(src)];
|
let mut stack: SmallVec<[Frame; 1]> = smallvec![Frame::new(src)];
|
||||||
let interpolations = interp.unwrap_or_else(FxHashMap::default); /* just a convenience */
|
let interpolations = interp.unwrap_or_else(FxHashMap::default); /* just a convenience */
|
||||||
let mut repeats = Vec::new();
|
let mut repeats = Vec::new();
|
||||||
let mut result: Vec<TokenStream> = Vec::new();
|
let mut result: Vec<TreeAndJoint> = Vec::new();
|
||||||
let mut result_stack = Vec::new();
|
let mut result_stack = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -78,7 +78,7 @@ pub fn transcribe(cx: &ExtCtxt,
|
||||||
if let Some(sep) = sep.clone() {
|
if let Some(sep) = sep.clone() {
|
||||||
// repeat same span, I guess
|
// repeat same span, I guess
|
||||||
let prev_span = match result.last() {
|
let prev_span = match result.last() {
|
||||||
Some(stream) => stream.trees().next().unwrap().span(),
|
Some((tt, _)) => tt.span(),
|
||||||
None => DUMMY_SP,
|
None => DUMMY_SP,
|
||||||
};
|
};
|
||||||
result.push(TokenTree::Token(prev_span, sep).into());
|
result.push(TokenTree::Token(prev_span, sep).into());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use print::pprust::token_to_string;
|
use print::pprust::token_to_string;
|
||||||
use parse::lexer::StringReader;
|
use parse::lexer::StringReader;
|
||||||
use parse::{token, PResult};
|
use parse::{token, PResult};
|
||||||
use tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree};
|
use tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
|
||||||
|
|
||||||
impl<'a> StringReader<'a> {
|
impl<'a> StringReader<'a> {
|
||||||
// Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
|
// Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
|
||||||
|
@ -33,7 +33,7 @@ impl<'a> StringReader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_token_tree(&mut self) -> PResult<'a, TokenStream> {
|
fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
|
||||||
let sm = self.sess.source_map();
|
let sm = self.sess.source_map();
|
||||||
match self.token {
|
match self.token {
|
||||||
token::Eof => {
|
token::Eof => {
|
||||||
|
@ -156,7 +156,7 @@ impl<'a> StringReader<'a> {
|
||||||
Ok(TokenTree::Delimited(
|
Ok(TokenTree::Delimited(
|
||||||
delim_span,
|
delim_span,
|
||||||
delim,
|
delim,
|
||||||
tts.into(),
|
tts.into()
|
||||||
).into())
|
).into())
|
||||||
},
|
},
|
||||||
token::CloseDelim(_) => {
|
token::CloseDelim(_) => {
|
||||||
|
@ -176,7 +176,7 @@ impl<'a> StringReader<'a> {
|
||||||
let raw = self.span_src_raw;
|
let raw = self.span_src_raw;
|
||||||
self.real_token();
|
self.real_token();
|
||||||
let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
|
let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
|
||||||
Ok(TokenStream::Tree(tt, if is_joint { Joint } else { NonJoint }))
|
Ok((tt, if is_joint { Joint } else { NonJoint }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2914,7 +2914,7 @@ impl<'a> Parser<'a> {
|
||||||
TokenTree::Delimited(
|
TokenTree::Delimited(
|
||||||
frame.span,
|
frame.span,
|
||||||
frame.delim,
|
frame.delim,
|
||||||
frame.tree_cursor.original_stream().into(),
|
frame.tree_cursor.stream.into(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
token::CloseDelim(_) | token::Eof => unreachable!(),
|
token::CloseDelim(_) | token::Eof => unreachable!(),
|
||||||
|
|
|
@ -147,9 +147,11 @@ impl TokenTree {
|
||||||
pub enum TokenStream {
|
pub enum TokenStream {
|
||||||
Empty,
|
Empty,
|
||||||
Tree(TokenTree, IsJoint),
|
Tree(TokenTree, IsJoint),
|
||||||
Stream(Lrc<Vec<TokenStream>>),
|
Stream(Lrc<Vec<TreeAndJoint>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type TreeAndJoint = (TokenTree, IsJoint);
|
||||||
|
|
||||||
// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 32);
|
static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 32);
|
||||||
|
@ -173,16 +175,14 @@ impl TokenStream {
|
||||||
while let Some((pos, ts)) = iter.next() {
|
while let Some((pos, ts)) = iter.next() {
|
||||||
if let Some((_, next)) = iter.peek() {
|
if let Some((_, next)) = iter.peek() {
|
||||||
let sp = match (&ts, &next) {
|
let sp = match (&ts, &next) {
|
||||||
(TokenStream::Tree(TokenTree::Token(_, token::Token::Comma), NonJoint), _) |
|
((TokenTree::Token(_, token::Token::Comma), NonJoint), _) |
|
||||||
(_, TokenStream::Tree(TokenTree::Token(_, token::Token::Comma), NonJoint))
|
(_, (TokenTree::Token(_, token::Token::Comma), NonJoint)) => continue,
|
||||||
=> continue,
|
((TokenTree::Token(sp, _), NonJoint), _) => *sp,
|
||||||
(TokenStream::Tree(TokenTree::Token(sp, _), NonJoint), _) => *sp,
|
((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
|
||||||
(TokenStream::Tree(TokenTree::Delimited(sp, ..), NonJoint), _) =>
|
|
||||||
sp.entire(),
|
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
let sp = sp.shrink_to_hi();
|
let sp = sp.shrink_to_hi();
|
||||||
let comma = TokenStream::Tree(TokenTree::Token(sp, token::Comma), NonJoint);
|
let comma = (TokenTree::Token(sp, token::Comma), NonJoint);
|
||||||
suggestion = Some((pos, comma, sp));
|
suggestion = Some((pos, comma, sp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,8 +200,14 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TokenTree> for TokenStream {
|
impl From<TokenTree> for TokenStream {
|
||||||
fn from(tt: TokenTree) -> TokenStream {
|
fn from(tree: TokenTree) -> TokenStream {
|
||||||
TokenStream::Tree(tt, NonJoint)
|
TokenStream::Tree(tree, NonJoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TokenTree> for TreeAndJoint {
|
||||||
|
fn from(tree: TokenTree) -> TreeAndJoint {
|
||||||
|
(tree, NonJoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,56 +219,7 @@ impl From<Token> for TokenStream {
|
||||||
|
|
||||||
impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
|
impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
|
||||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||||
TokenStream::new(iter.into_iter().map(Into::into).collect::<Vec<_>>())
|
TokenStream::from_streams(iter.into_iter().map(Into::into).collect::<Vec<_>>())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Extend<TokenStream> for TokenStream {
|
|
||||||
fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, iter: I) {
|
|
||||||
let iter = iter.into_iter();
|
|
||||||
let this = mem::replace(self, TokenStream::Empty);
|
|
||||||
|
|
||||||
// Vector of token streams originally in self.
|
|
||||||
let tts: Vec<TokenStream> = match this {
|
|
||||||
TokenStream::Empty => {
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
vec.reserve(iter.size_hint().0);
|
|
||||||
vec
|
|
||||||
}
|
|
||||||
TokenStream::Tree(..) => {
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
vec.reserve(1 + iter.size_hint().0);
|
|
||||||
vec.push(this);
|
|
||||||
vec
|
|
||||||
}
|
|
||||||
TokenStream::Stream(rc_vec) => match Lrc::try_unwrap(rc_vec) {
|
|
||||||
Ok(mut vec) => {
|
|
||||||
// Extend in place using the existing capacity if possible.
|
|
||||||
// This is the fast path for libraries like `quote` that
|
|
||||||
// build a token stream.
|
|
||||||
vec.reserve(iter.size_hint().0);
|
|
||||||
vec
|
|
||||||
}
|
|
||||||
Err(rc_vec) => {
|
|
||||||
// Self is shared so we need to copy and extend that.
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
vec.reserve(rc_vec.len() + iter.size_hint().0);
|
|
||||||
vec.extend_from_slice(&rc_vec);
|
|
||||||
vec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Perform the extend, joining tokens as needed along the way.
|
|
||||||
let mut builder = TokenStreamBuilder(tts);
|
|
||||||
for stream in iter {
|
|
||||||
builder.push(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the resulting token stream. If it contains more than one token,
|
|
||||||
// preserve capacity in the vector in anticipation of the caller
|
|
||||||
// performing additional calls to extend.
|
|
||||||
*self = TokenStream::new(builder.0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,14 +251,43 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(mut streams: Vec<TokenStream>) -> TokenStream {
|
fn from_streams(mut streams: Vec<TokenStream>) -> TokenStream {
|
||||||
match streams.len() {
|
match streams.len() {
|
||||||
0 => TokenStream::empty(),
|
0 => TokenStream::empty(),
|
||||||
1 => streams.pop().unwrap(),
|
1 => streams.pop().unwrap(),
|
||||||
|
_ => {
|
||||||
|
let mut vec = vec![];
|
||||||
|
for stream in streams {
|
||||||
|
match stream {
|
||||||
|
TokenStream::Empty => {},
|
||||||
|
TokenStream::Tree(tree, is_joint) => vec.push((tree, is_joint)),
|
||||||
|
TokenStream::Stream(stream2) => vec.extend(stream2.iter().cloned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenStream::new(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(mut streams: Vec<TreeAndJoint>) -> TokenStream {
|
||||||
|
match streams.len() {
|
||||||
|
0 => TokenStream::empty(),
|
||||||
|
1 => {
|
||||||
|
let (tree, is_joint) = streams.pop().unwrap();
|
||||||
|
TokenStream::Tree(tree, is_joint)
|
||||||
|
}
|
||||||
_ => TokenStream::Stream(Lrc::new(streams)),
|
_ => TokenStream::Stream(Lrc::new(streams)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec<TreeAndJoint>) {
|
||||||
|
match self {
|
||||||
|
TokenStream::Empty => {}
|
||||||
|
TokenStream::Tree(tree, is_joint) => vec.push((tree, is_joint)),
|
||||||
|
TokenStream::Stream(stream) => vec.extend(stream.iter().cloned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn trees(&self) -> Cursor {
|
pub fn trees(&self) -> Cursor {
|
||||||
self.clone().into_trees()
|
self.clone().into_trees()
|
||||||
}
|
}
|
||||||
|
@ -362,54 +348,58 @@ impl TokenStream {
|
||||||
t1.next().is_none() && t2.next().is_none()
|
t1.next().is_none() && t2.next().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precondition: `self` consists of a single token tree.
|
|
||||||
/// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`.
|
|
||||||
pub fn as_tree(self) -> (TokenTree, bool /* joint? */) {
|
|
||||||
match self {
|
|
||||||
TokenStream::Tree(tree, is_joint) => (tree, is_joint == Joint),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
|
pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
|
||||||
let mut trees = self.into_trees();
|
match self {
|
||||||
let mut result = Vec::new();
|
TokenStream::Empty => TokenStream::Empty,
|
||||||
let mut i = 0;
|
TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(0, tree), is_joint),
|
||||||
while let Some(stream) = trees.next_as_stream() {
|
TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new(
|
||||||
result.push(match stream {
|
stream
|
||||||
TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(i, tree), is_joint),
|
.iter()
|
||||||
_ => unreachable!()
|
.enumerate()
|
||||||
});
|
.map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
|
||||||
i += 1;
|
.collect()
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
TokenStream::new(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
|
pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
|
||||||
let mut trees = self.into_trees();
|
match self {
|
||||||
let mut result = Vec::new();
|
TokenStream::Empty => TokenStream::Empty,
|
||||||
while let Some(stream) = trees.next_as_stream() {
|
TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(tree), is_joint),
|
||||||
result.push(match stream {
|
TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new(
|
||||||
TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(tree), is_joint),
|
stream
|
||||||
_ => unreachable!()
|
.iter()
|
||||||
});
|
.map(|(tree, is_joint)| (f(tree.clone()), *is_joint))
|
||||||
|
.collect()
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
TokenStream::new(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_tree_and_joint(&self) -> Option<(TokenTree, IsJoint)> {
|
fn first_tree_and_joint(&self) -> Option<(TokenTree, IsJoint)> {
|
||||||
match self {
|
match self {
|
||||||
TokenStream::Empty => None,
|
TokenStream::Empty => None,
|
||||||
TokenStream::Tree(ref tree, is_joint) => Some((tree.clone(), *is_joint)),
|
TokenStream::Tree(ref tree, is_joint) => Some((tree.clone(), *is_joint)),
|
||||||
TokenStream::Stream(ref stream) => stream.first().unwrap().first_tree_and_joint(),
|
TokenStream::Stream(ref stream) => Some(stream.first().unwrap().clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_tree_if_joint(&self) -> Option<TokenTree> {
|
fn last_tree_if_joint(&self) -> Option<TokenTree> {
|
||||||
match self {
|
match self {
|
||||||
TokenStream::Empty | TokenStream::Tree(_, NonJoint) => None,
|
TokenStream::Empty => None,
|
||||||
TokenStream::Tree(ref tree, Joint) => Some(tree.clone()),
|
TokenStream::Tree(ref tree, is_joint) => {
|
||||||
TokenStream::Stream(ref stream) => stream.last().unwrap().last_tree_if_joint(),
|
if *is_joint == Joint {
|
||||||
|
Some(tree.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenStream::Stream(ref stream) => {
|
||||||
|
if let (tree, Joint) = stream.last().unwrap() {
|
||||||
|
Some(tree.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,13 +432,8 @@ impl TokenStreamBuilder {
|
||||||
self.0.push(stream);
|
self.0.push(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add<T: Into<TokenStream>>(mut self, stream: T) -> Self {
|
|
||||||
self.push(stream);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> TokenStream {
|
pub fn build(self) -> TokenStream {
|
||||||
TokenStream::new(self.0)
|
TokenStream::from_streams(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_all_but_last_tree(&mut self, stream: &TokenStream) {
|
fn push_all_but_last_tree(&mut self, stream: &TokenStream) {
|
||||||
|
@ -456,10 +441,9 @@ impl TokenStreamBuilder {
|
||||||
let len = streams.len();
|
let len = streams.len();
|
||||||
match len {
|
match len {
|
||||||
1 => {}
|
1 => {}
|
||||||
2 => self.0.push(streams[0].clone().into()),
|
2 => self.0.push(TokenStream::Tree(streams[0].0.clone(), streams[0].1)),
|
||||||
_ => self.0.push(TokenStream::new(streams[0 .. len - 1].to_vec())),
|
_ => self.0.push(TokenStream::Stream(Lrc::new(streams[0 .. len - 1].to_vec()))),
|
||||||
}
|
}
|
||||||
self.push_all_but_last_tree(&streams[len - 1])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,154 +452,77 @@ impl TokenStreamBuilder {
|
||||||
let len = streams.len();
|
let len = streams.len();
|
||||||
match len {
|
match len {
|
||||||
1 => {}
|
1 => {}
|
||||||
2 => self.0.push(streams[1].clone().into()),
|
2 => self.0.push(TokenStream::Tree(streams[1].0.clone(), streams[1].1)),
|
||||||
_ => self.0.push(TokenStream::new(streams[1 .. len].to_vec())),
|
_ => self.0.push(TokenStream::Stream(Lrc::new(streams[1 .. len].to_vec()))),
|
||||||
}
|
}
|
||||||
self.push_all_but_first_tree(&streams[0])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Cursor(CursorKind);
|
pub struct Cursor {
|
||||||
|
pub stream: TokenStream,
|
||||||
#[derive(Clone)]
|
|
||||||
enum CursorKind {
|
|
||||||
Empty,
|
|
||||||
Tree(TokenTree, IsJoint, bool /* consumed? */),
|
|
||||||
Stream(StreamCursor),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct StreamCursor {
|
|
||||||
stream: Lrc<Vec<TokenStream>>,
|
|
||||||
index: usize,
|
index: usize,
|
||||||
stack: Vec<(Lrc<Vec<TokenStream>>, usize)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StreamCursor {
|
|
||||||
fn new(stream: Lrc<Vec<TokenStream>>) -> Self {
|
|
||||||
StreamCursor { stream: stream, index: 0, stack: Vec::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_as_stream(&mut self) -> Option<TokenStream> {
|
|
||||||
loop {
|
|
||||||
if self.index < self.stream.len() {
|
|
||||||
self.index += 1;
|
|
||||||
let next = self.stream[self.index - 1].clone();
|
|
||||||
match next {
|
|
||||||
TokenStream::Empty => {}
|
|
||||||
TokenStream::Tree(..) => return Some(next),
|
|
||||||
TokenStream::Stream(stream) => self.insert(stream),
|
|
||||||
}
|
|
||||||
} else if let Some((stream, index)) = self.stack.pop() {
|
|
||||||
self.stream = stream;
|
|
||||||
self.index = index;
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, stream: Lrc<Vec<TokenStream>>) {
|
|
||||||
self.stack.push((mem::replace(&mut self.stream, stream),
|
|
||||||
mem::replace(&mut self.index, 0)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for Cursor {
|
impl Iterator for Cursor {
|
||||||
type Item = TokenTree;
|
type Item = TokenTree;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<TokenTree> {
|
fn next(&mut self) -> Option<TokenTree> {
|
||||||
self.next_as_stream().map(|stream| match stream {
|
self.next_with_joint().map(|(tree, _)| tree)
|
||||||
TokenStream::Tree(tree, _) => tree,
|
|
||||||
_ => unreachable!()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cursor {
|
impl Cursor {
|
||||||
fn new(stream: TokenStream) -> Self {
|
fn new(stream: TokenStream) -> Self {
|
||||||
Cursor(match stream {
|
Cursor { stream, index: 0 }
|
||||||
TokenStream::Empty => CursorKind::Empty,
|
|
||||||
TokenStream::Tree(tree, is_joint) => CursorKind::Tree(tree, is_joint, false),
|
|
||||||
TokenStream::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_as_stream(&mut self) -> Option<TokenStream> {
|
pub fn next_with_joint(&mut self) -> Option<TreeAndJoint> {
|
||||||
let (stream, consumed) = match self.0 {
|
match self.stream {
|
||||||
CursorKind::Tree(ref tree, ref is_joint, ref mut consumed @ false) =>
|
TokenStream::Empty => None,
|
||||||
(TokenStream::Tree(tree.clone(), *is_joint), consumed),
|
TokenStream::Tree(ref tree, ref is_joint) => {
|
||||||
CursorKind::Stream(ref mut cursor) => return cursor.next_as_stream(),
|
if self.index == 0 {
|
||||||
_ => return None,
|
self.index = 1;
|
||||||
};
|
Some((tree.clone(), *is_joint))
|
||||||
|
} else {
|
||||||
*consumed = true;
|
None
|
||||||
Some(stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, stream: TokenStream) {
|
|
||||||
match self.0 {
|
|
||||||
_ if stream.is_empty() => return,
|
|
||||||
CursorKind::Empty => *self = stream.trees(),
|
|
||||||
CursorKind::Tree(_, _, consumed) => {
|
|
||||||
*self = TokenStream::new(vec![self.original_stream(), stream]).trees();
|
|
||||||
if consumed {
|
|
||||||
self.next();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CursorKind::Stream(ref mut cursor) => {
|
TokenStream::Stream(ref stream) => {
|
||||||
cursor.insert(ThinTokenStream::from(stream).0.unwrap());
|
if self.index < stream.len() {
|
||||||
|
self.index += 1;
|
||||||
|
Some(stream[self.index - 1].clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn original_stream(&self) -> TokenStream {
|
pub fn append(&mut self, new_stream: TokenStream) {
|
||||||
match self.0 {
|
if new_stream.is_empty() {
|
||||||
CursorKind::Empty => TokenStream::empty(),
|
return;
|
||||||
CursorKind::Tree(ref tree, ref is_joint, _) =>
|
|
||||||
TokenStream::Tree(tree.clone(), *is_joint),
|
|
||||||
CursorKind::Stream(ref cursor) => TokenStream::Stream(
|
|
||||||
cursor.stack.get(0).cloned().map(|(stream, _)| stream)
|
|
||||||
.unwrap_or_else(|| cursor.stream.clone())
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
let index = self.index;
|
||||||
|
let stream = mem::replace(&mut self.stream, TokenStream::Empty);
|
||||||
|
*self = TokenStream::from_streams(vec![stream, new_stream]).into_trees();
|
||||||
|
self.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
|
pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
|
||||||
fn look_ahead(streams: &[TokenStream], mut n: usize) -> Result<TokenTree, usize> {
|
match self.stream {
|
||||||
for stream in streams {
|
TokenStream::Empty => None,
|
||||||
n = match stream {
|
TokenStream::Tree(ref tree, _) => {
|
||||||
TokenStream::Tree(ref tree, _) if n == 0 => return Ok(tree.clone()),
|
if n == 0 && self.index == 0 {
|
||||||
TokenStream::Tree(..) => n - 1,
|
Some(tree.clone())
|
||||||
TokenStream::Stream(ref stream) => match look_ahead(stream, n) {
|
} else {
|
||||||
Ok(tree) => return Ok(tree),
|
None
|
||||||
Err(n) => n,
|
}
|
||||||
},
|
|
||||||
_ => n,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
Err(n)
|
TokenStream::Stream(ref stream) =>
|
||||||
|
stream[self.index ..].get(n).map(|(tree, _)| tree.clone()),
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.0 {
|
|
||||||
CursorKind::Empty |
|
|
||||||
CursorKind::Tree(_, _, true) => Err(n),
|
|
||||||
CursorKind::Tree(ref tree, _, false) => look_ahead(&[tree.clone().into()], n),
|
|
||||||
CursorKind::Stream(ref cursor) => {
|
|
||||||
look_ahead(&cursor.stream[cursor.index ..], n).or_else(|mut n| {
|
|
||||||
for &(ref stream, index) in cursor.stack.iter().rev() {
|
|
||||||
n = match look_ahead(&stream[index..], n) {
|
|
||||||
Ok(tree) => return Ok(tree),
|
|
||||||
Err(n) => n,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(n)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}.ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +530,7 @@ impl Cursor {
|
||||||
/// `ThinTokenStream` is smaller, but needs to allocate to represent a single `TokenTree`.
|
/// `ThinTokenStream` is smaller, but needs to allocate to represent a single `TokenTree`.
|
||||||
/// We must use `ThinTokenStream` in `TokenTree::Delimited` to avoid infinite size due to recursion.
|
/// We must use `ThinTokenStream` in `TokenTree::Delimited` to avoid infinite size due to recursion.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ThinTokenStream(Option<Lrc<Vec<TokenStream>>>);
|
pub struct ThinTokenStream(Option<Lrc<Vec<TreeAndJoint>>>);
|
||||||
|
|
||||||
impl ThinTokenStream {
|
impl ThinTokenStream {
|
||||||
pub fn stream(&self) -> TokenStream {
|
pub fn stream(&self) -> TokenStream {
|
||||||
|
@ -635,7 +542,7 @@ impl From<TokenStream> for ThinTokenStream {
|
||||||
fn from(stream: TokenStream) -> ThinTokenStream {
|
fn from(stream: TokenStream) -> ThinTokenStream {
|
||||||
ThinTokenStream(match stream {
|
ThinTokenStream(match stream {
|
||||||
TokenStream::Empty => None,
|
TokenStream::Empty => None,
|
||||||
TokenStream::Tree(..) => Some(Lrc::new(vec![stream])),
|
TokenStream::Tree(tree, is_joint) => Some(Lrc::new(vec![(tree, is_joint)])),
|
||||||
TokenStream::Stream(stream) => Some(stream),
|
TokenStream::Stream(stream) => Some(stream),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -742,7 +649,7 @@ mod tests {
|
||||||
let test_res = string_to_ts("foo::bar::baz");
|
let test_res = string_to_ts("foo::bar::baz");
|
||||||
let test_fst = string_to_ts("foo::bar");
|
let test_fst = string_to_ts("foo::bar");
|
||||||
let test_snd = string_to_ts("::baz");
|
let test_snd = string_to_ts("::baz");
|
||||||
let eq_res = TokenStream::new(vec![test_fst, test_snd]);
|
let eq_res = TokenStream::from_streams(vec![test_fst, test_snd]);
|
||||||
assert_eq!(test_res.trees().count(), 5);
|
assert_eq!(test_res.trees().count(), 5);
|
||||||
assert_eq!(eq_res.trees().count(), 5);
|
assert_eq!(eq_res.trees().count(), 5);
|
||||||
assert_eq!(test_res.eq_unspanned(&eq_res), true);
|
assert_eq!(test_res.eq_unspanned(&eq_res), true);
|
||||||
|
@ -827,107 +734,4 @@ mod tests {
|
||||||
assert!(stream.eq_unspanned(&string_to_ts("...")));
|
assert!(stream.eq_unspanned(&string_to_ts("...")));
|
||||||
assert_eq!(stream.trees().count(), 1);
|
assert_eq!(stream.trees().count(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_empty() {
|
|
||||||
with_globals(|| {
|
|
||||||
// Append a token onto an empty token stream.
|
|
||||||
let mut stream = TokenStream::empty();
|
|
||||||
stream.extend(vec![string_to_ts("t")]);
|
|
||||||
|
|
||||||
let expected = string_to_ts("t");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_nothing() {
|
|
||||||
with_globals(|| {
|
|
||||||
// Append nothing onto a token stream containing one token.
|
|
||||||
let mut stream = string_to_ts("t");
|
|
||||||
stream.extend(vec![]);
|
|
||||||
|
|
||||||
let expected = string_to_ts("t");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_single() {
|
|
||||||
with_globals(|| {
|
|
||||||
// Append a token onto token stream containing a single token.
|
|
||||||
let mut stream = string_to_ts("t1");
|
|
||||||
stream.extend(vec![string_to_ts("t2")]);
|
|
||||||
|
|
||||||
let expected = string_to_ts("t1 t2");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_in_place() {
|
|
||||||
with_globals(|| {
|
|
||||||
// Append a token onto token stream containing a reference counted
|
|
||||||
// vec of tokens. The token stream has a reference count of 1 so
|
|
||||||
// this can happen in place.
|
|
||||||
let mut stream = string_to_ts("t1 t2");
|
|
||||||
stream.extend(vec![string_to_ts("t3")]);
|
|
||||||
|
|
||||||
let expected = string_to_ts("t1 t2 t3");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_copy() {
|
|
||||||
with_globals(|| {
|
|
||||||
// Append a token onto token stream containing a reference counted
|
|
||||||
// vec of tokens. The token stream is shared so the extend takes
|
|
||||||
// place on a copy.
|
|
||||||
let mut stream = string_to_ts("t1 t2");
|
|
||||||
let _incref = stream.clone();
|
|
||||||
stream.extend(vec![string_to_ts("t3")]);
|
|
||||||
|
|
||||||
let expected = string_to_ts("t1 t2 t3");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_no_join() {
|
|
||||||
with_globals(|| {
|
|
||||||
let first = TokenTree::Token(DUMMY_SP, Token::Dot);
|
|
||||||
let second = TokenTree::Token(DUMMY_SP, Token::Dot);
|
|
||||||
|
|
||||||
// Append a dot onto a token stream containing a dot, but do not
|
|
||||||
// join them.
|
|
||||||
let mut stream = TokenStream::from(first);
|
|
||||||
stream.extend(vec![TokenStream::from(second)]);
|
|
||||||
|
|
||||||
let expected = string_to_ts(". .");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
|
|
||||||
let unexpected = string_to_ts("..");
|
|
||||||
assert!(!stream.eq_unspanned(&unexpected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extend_join() {
|
|
||||||
with_globals(|| {
|
|
||||||
let first = TokenTree::Token(DUMMY_SP, Token::Dot).joint();
|
|
||||||
let second = TokenTree::Token(DUMMY_SP, Token::Dot);
|
|
||||||
|
|
||||||
// Append a dot onto a token stream containing a dot, forming a
|
|
||||||
// dotdot.
|
|
||||||
let mut stream = first;
|
|
||||||
stream.extend(vec![TokenStream::from(second)]);
|
|
||||||
|
|
||||||
let expected = string_to_ts("..");
|
|
||||||
assert!(stream.eq_unspanned(&expected));
|
|
||||||
|
|
||||||
let unexpected = string_to_ts(". .");
|
|
||||||
assert!(!stream.eq_unspanned(&unexpected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use syntax::ast;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::parse::lexer::comments;
|
use syntax::parse::lexer::comments;
|
||||||
use syntax::parse::{self, token, ParseSess};
|
use syntax::parse::{self, token, ParseSess};
|
||||||
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream};
|
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
|
||||||
use syntax_pos::hygiene::{SyntaxContext, Transparency};
|
use syntax_pos::hygiene::{SyntaxContext, Transparency};
|
||||||
use syntax_pos::symbol::{keywords, Symbol};
|
use syntax_pos::symbol::{keywords, Symbol};
|
||||||
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
|
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
|
||||||
|
@ -46,13 +46,14 @@ impl ToInternal<token::DelimToken> for Delimiter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromInternal<(TokenStream, &'_ ParseSess, &'_ mut Vec<Self>)>
|
impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
|
||||||
for TokenTree<Group, Punct, Ident, Literal>
|
for TokenTree<Group, Punct, Ident, Literal>
|
||||||
{
|
{
|
||||||
fn from_internal((stream, sess, stack): (TokenStream, &ParseSess, &mut Vec<Self>)) -> Self {
|
fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
|
||||||
|
-> Self {
|
||||||
use syntax::parse::token::*;
|
use syntax::parse::token::*;
|
||||||
|
|
||||||
let (tree, joint) = stream.as_tree();
|
let joint = is_joint == Joint;
|
||||||
let (span, token) = match tree {
|
let (span, token) = match tree {
|
||||||
tokenstream::TokenTree::Delimited(span, delim, tts) => {
|
tokenstream::TokenTree::Delimited(span, delim, tts) => {
|
||||||
let delimiter = Delimiter::from_internal(delim);
|
let delimiter = Delimiter::from_internal(delim);
|
||||||
|
@ -450,7 +451,7 @@ impl server::TokenStreamIter for Rustc<'_> {
|
||||||
) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
|
) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
|
||||||
loop {
|
loop {
|
||||||
let tree = iter.stack.pop().or_else(|| {
|
let tree = iter.stack.pop().or_else(|| {
|
||||||
let next = iter.cursor.next_as_stream()?;
|
let next = iter.cursor.next_with_joint()?;
|
||||||
Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
|
Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
|
||||||
})?;
|
})?;
|
||||||
// HACK: The condition "dummy span + group with empty delimiter" represents an AST
|
// HACK: The condition "dummy span + group with empty delimiter" represents an AST
|
||||||
|
@ -461,7 +462,7 @@ impl server::TokenStreamIter for Rustc<'_> {
|
||||||
// and not doing the roundtrip through AST.
|
// and not doing the roundtrip through AST.
|
||||||
if let TokenTree::Group(ref group) = tree {
|
if let TokenTree::Group(ref group) = tree {
|
||||||
if group.delimiter == Delimiter::None && group.span.entire().is_dummy() {
|
if group.delimiter == Delimiter::None && group.span.entire().is_dummy() {
|
||||||
iter.cursor.insert(group.stream.clone());
|
iter.cursor.append(group.stream.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ error[E0502]: cannot borrow `foo` (via `foo.bar2`) as immutable because `foo` is
|
||||||
LL | let bar1 = &mut foo.bar1;
|
LL | let bar1 = &mut foo.bar1;
|
||||||
| -------- mutable borrow occurs here (via `foo.bar1`)
|
| -------- mutable borrow occurs here (via `foo.bar1`)
|
||||||
LL | let _foo1 = &foo.bar2; //~ ERROR cannot borrow
|
LL | let _foo1 = &foo.bar2; //~ ERROR cannot borrow
|
||||||
| ^^^^^^^^ immutable borrow occurs here (via `foo.bar2`)
|
| ^^^^^^^^ immutable borrow of `foo.bar2` -- which overlaps with `foo.bar1` -- occurs here
|
||||||
LL | *bar1;
|
LL | *bar1;
|
||||||
LL | }
|
LL | }
|
||||||
| - mutable borrow ends here
|
| - mutable borrow ends here
|
||||||
|
|
|
@ -61,7 +61,7 @@ error[E0502]: cannot borrow `a` (via `a.y`) as immutable because `a` is also bor
|
||||||
LL | let _x = &mut a.x;
|
LL | let _x = &mut a.x;
|
||||||
| --- mutable borrow occurs here (via `a.x`)
|
| --- mutable borrow occurs here (via `a.x`)
|
||||||
LL | let _y = &a.y; //[ast]~ ERROR cannot borrow
|
LL | let _y = &a.y; //[ast]~ ERROR cannot borrow
|
||||||
| ^^^ immutable borrow occurs here (via `a.y`)
|
| ^^^ immutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
|
||||||
...
|
...
|
||||||
LL | }
|
LL | }
|
||||||
| - mutable borrow ends here
|
| - mutable borrow ends here
|
||||||
|
@ -72,7 +72,7 @@ error[E0502]: cannot borrow `a` (via `a.y`) as mutable because `a` is also borro
|
||||||
LL | let _x = &a.x;
|
LL | let _x = &a.x;
|
||||||
| --- immutable borrow occurs here (via `a.x`)
|
| --- immutable borrow occurs here (via `a.x`)
|
||||||
LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow
|
LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow
|
||||||
| ^^^ mutable borrow occurs here (via `a.y`)
|
| ^^^ mutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
|
||||||
...
|
...
|
||||||
LL | }
|
LL | }
|
||||||
| - immutable borrow ends here
|
| - immutable borrow ends here
|
||||||
|
|
|
@ -83,14 +83,14 @@ fn borrow_after_mut_borrow() {
|
||||||
let mut a: Box<_> = box A { x: box 0, y: 1 };
|
let mut a: Box<_> = box A { x: box 0, y: 1 };
|
||||||
let _x = &mut a.x;
|
let _x = &mut a.x;
|
||||||
let _y = &a.y; //[ast]~ ERROR cannot borrow
|
let _y = &a.y; //[ast]~ ERROR cannot borrow
|
||||||
//[ast]~^ immutable borrow occurs here (via `a.y`)
|
//[ast]~^ immutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
|
||||||
use_mut(_x);
|
use_mut(_x);
|
||||||
}
|
}
|
||||||
fn mut_borrow_after_borrow() {
|
fn mut_borrow_after_borrow() {
|
||||||
let mut a: Box<_> = box A { x: box 0, y: 1 };
|
let mut a: Box<_> = box A { x: box 0, y: 1 };
|
||||||
let _x = &a.x;
|
let _x = &a.x;
|
||||||
let _y = &mut a.y; //[ast]~ ERROR cannot borrow
|
let _y = &mut a.y; //[ast]~ ERROR cannot borrow
|
||||||
//[ast]~^ mutable borrow occurs here (via `a.y`)
|
//[ast]~^ mutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
|
||||||
use_imm(_x);
|
use_imm(_x);
|
||||||
}
|
}
|
||||||
fn copy_after_move_nested() {
|
fn copy_after_move_nested() {
|
||||||
|
|
|
@ -1,132 +1,127 @@
|
||||||
error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
||||||
--> $DIR/borrowck-union-borrow.rs:27:23
|
--> $DIR/borrowck-union-borrow.rs:25:23
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| ---- immutable borrow occurs here
|
| ---- immutable borrow occurs here
|
||||||
LL | let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
LL | let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
||||||
| ^^^^^^^^ mutable borrow occurs here
|
| ^^^^^^^^ mutable borrow occurs here
|
||||||
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
|
||||||
LL | drop(ra);
|
LL | drop(ra);
|
||||||
| -- immutable borrow later used here
|
| -- immutable borrow later used here
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.a` because it is borrowed
|
error[E0506]: cannot assign to `u.a` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:33:13
|
--> $DIR/borrowck-union-borrow.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| ---- borrow of `u.a` occurs here
|
| ---- borrow of `u.a` occurs here
|
||||||
LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
|
LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
||||||
LL | //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
|
|
||||||
LL | drop(ra);
|
LL | drop(ra);
|
||||||
| -- borrow later used here
|
| -- borrow later used here
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u.b` as mutable because it is also borrowed as immutable
|
error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`)
|
||||||
--> $DIR/borrowck-union-borrow.rs:50:23
|
--> $DIR/borrowck-union-borrow.rs:46:23
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| ---- immutable borrow occurs here
|
| ---- immutable borrow occurs here (via `u.a`)
|
||||||
LL | let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
LL | let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
||||||
| ^^^^^^^^ mutable borrow occurs here
|
| ^^^^^^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
|
||||||
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
|
|
||||||
LL | drop(ra);
|
LL | drop(ra);
|
||||||
| -- immutable borrow later used here
|
| -- immutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.b` because it is borrowed
|
error[E0506]: cannot assign to `u.b` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:56:13
|
--> $DIR/borrowck-union-borrow.rs:51:13
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| ---- borrow of `u.b` occurs here
|
| ---- borrow of `u.b` occurs here
|
||||||
LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
|
LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
||||||
LL | //[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
|
|
||||||
LL | drop(ra);
|
LL | drop(ra);
|
||||||
| -- borrow later used here
|
| -- borrow later used here
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
||||||
--> $DIR/borrowck-union-borrow.rs:63:22
|
--> $DIR/borrowck-union-borrow.rs:57:22
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| -------- mutable borrow occurs here
|
| -------- mutable borrow occurs here
|
||||||
LL | let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
LL | let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
||||||
| ^^^^ immutable borrow occurs here
|
| ^^^^ immutable borrow occurs here
|
||||||
LL | //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
|
||||||
LL | drop(rma);
|
LL | drop(rma);
|
||||||
| --- mutable borrow later used here
|
| --- mutable borrow later used here
|
||||||
|
|
||||||
error[E0503]: cannot use `u.a` because it was mutably borrowed
|
error[E0503]: cannot use `u.a` because it was mutably borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:69:21
|
--> $DIR/borrowck-union-borrow.rs:62:21
|
||||||
|
|
|
|
||||||
LL | let ra = &mut u.a;
|
LL | let ra = &mut u.a;
|
||||||
| -------- borrow of `u.a` occurs here
|
| -------- borrow of `u.a` occurs here
|
||||||
LL | let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
|
LL | let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
|
||||||
| ^^^ use of borrowed `u.a`
|
| ^^^ use of borrowed `u.a`
|
||||||
LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
|
|
||||||
LL | drop(ra);
|
LL | drop(ra);
|
||||||
| -- borrow later used here
|
| -- borrow later used here
|
||||||
|
|
||||||
error[E0499]: cannot borrow `u.a` as mutable more than once at a time
|
error[E0499]: cannot borrow `u.a` as mutable more than once at a time
|
||||||
--> $DIR/borrowck-union-borrow.rs:75:24
|
--> $DIR/borrowck-union-borrow.rs:67:24
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| -------- first mutable borrow occurs here
|
| -------- first mutable borrow occurs here
|
||||||
LL | let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
LL | let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
||||||
| ^^^^^^^^ second mutable borrow occurs here
|
| ^^^^^^^^ second mutable borrow occurs here
|
||||||
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
|
|
||||||
LL | drop(rma);
|
LL | drop(rma);
|
||||||
| --- first borrow later used here
|
| --- first borrow later used here
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.a` because it is borrowed
|
error[E0506]: cannot assign to `u.a` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:81:13
|
--> $DIR/borrowck-union-borrow.rs:72:13
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| -------- borrow of `u.a` occurs here
|
| -------- borrow of `u.a` occurs here
|
||||||
LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
|
LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
||||||
LL | //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
|
|
||||||
LL | drop(rma);
|
LL | drop(rma);
|
||||||
| --- borrow later used here
|
| --- borrow later used here
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u.b` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`)
|
||||||
--> $DIR/borrowck-union-borrow.rs:88:22
|
--> $DIR/borrowck-union-borrow.rs:78:22
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| -------- mutable borrow occurs here
|
| -------- mutable borrow occurs here (via `u.a`)
|
||||||
LL | let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
LL | let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
||||||
| ^^^^ immutable borrow occurs here
|
| ^^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
|
||||||
LL | //[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
|
|
||||||
LL | drop(rma);
|
LL | drop(rma);
|
||||||
| --- mutable borrow later used here
|
| --- mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
|
||||||
|
|
||||||
error[E0503]: cannot use `u.b` because it was mutably borrowed
|
error[E0503]: cannot use `u.b` because it was mutably borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:94:21
|
--> $DIR/borrowck-union-borrow.rs:83:21
|
||||||
|
|
|
|
||||||
LL | let ra = &mut u.a;
|
LL | let ra = &mut u.a;
|
||||||
| -------- borrow of `u.a` occurs here
|
| -------- borrow of `u.a` occurs here
|
||||||
LL | let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed
|
LL | let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
|
||||||
| ^^^ use of borrowed `u.a`
|
| ^^^ use of borrowed `u.a`
|
||||||
...
|
LL |
|
||||||
LL | drop(ra);
|
LL | drop(ra);
|
||||||
| -- borrow later used here
|
| -- borrow later used here
|
||||||
|
|
||||||
error[E0499]: cannot borrow `u.b` as mutable more than once at a time
|
error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
||||||
--> $DIR/borrowck-union-borrow.rs:101:24
|
--> $DIR/borrowck-union-borrow.rs:89:24
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| -------- first mutable borrow occurs here
|
| -------- first mutable borrow occurs here (via `u.a`)
|
||||||
LL | let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
LL | let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
||||||
| ^^^^^^^^ second mutable borrow occurs here
|
| ^^^^^^^^ second mutable borrow occurs here (via `u.b`)
|
||||||
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
|
|
||||||
LL | drop(rma);
|
LL | drop(rma);
|
||||||
| --- first borrow later used here
|
| --- first borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.b` because it is borrowed
|
error[E0506]: cannot assign to `u.b` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:107:13
|
--> $DIR/borrowck-union-borrow.rs:94:13
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| -------- borrow of `u.b` occurs here
|
| -------- borrow of `u.b` occurs here
|
||||||
LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
|
LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
||||||
LL | //[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
|
|
||||||
LL | drop(rma);
|
LL | drop(rma);
|
||||||
| --- borrow later used here
|
| --- borrow later used here
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
// revisions: ast mir
|
|
||||||
//[mir]compile-flags: -Z borrowck=mir
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
union U {
|
union U {
|
||||||
|
@ -24,14 +22,12 @@ fn main() {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ra = &u.a;
|
let ra = &u.a;
|
||||||
let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
||||||
//[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
|
||||||
drop(ra);
|
drop(ra);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ra = &u.a;
|
let ra = &u.a;
|
||||||
u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
|
u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||||
//[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
|
|
||||||
drop(ra);
|
drop(ra);
|
||||||
}
|
}
|
||||||
// Imm borrow, other field
|
// Imm borrow, other field
|
||||||
|
@ -47,65 +43,55 @@ fn main() {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ra = &u.a;
|
let ra = &u.a;
|
||||||
let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
||||||
//[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
|
|
||||||
drop(ra);
|
drop(ra);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ra = &u.a;
|
let ra = &u.a;
|
||||||
u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
|
u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||||
//[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
|
|
||||||
drop(ra);
|
drop(ra);
|
||||||
}
|
}
|
||||||
// Mut borrow, same field
|
// Mut borrow, same field
|
||||||
{
|
{
|
||||||
let rma = &mut u.a;
|
let rma = &mut u.a;
|
||||||
let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
||||||
//[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
|
||||||
drop(rma);
|
drop(rma);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ra = &mut u.a;
|
let ra = &mut u.a;
|
||||||
let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
|
let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
|
||||||
//[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
|
|
||||||
drop(ra);
|
drop(ra);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let rma = &mut u.a;
|
let rma = &mut u.a;
|
||||||
let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
||||||
//[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
|
|
||||||
drop(rma);
|
drop(rma);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let rma = &mut u.a;
|
let rma = &mut u.a;
|
||||||
u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
|
u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||||
//[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
|
|
||||||
drop(rma);
|
drop(rma);
|
||||||
}
|
}
|
||||||
// Mut borrow, other field
|
// Mut borrow, other field
|
||||||
{
|
{
|
||||||
let rma = &mut u.a;
|
let rma = &mut u.a;
|
||||||
let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
||||||
//[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
|
|
||||||
drop(rma);
|
drop(rma);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let ra = &mut u.a;
|
let ra = &mut u.a;
|
||||||
let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed
|
let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
|
||||||
//[mir]~^ ERROR cannot use `u.b` because it was mutably borrowed
|
|
||||||
|
|
||||||
drop(ra);
|
drop(ra);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let rma = &mut u.a;
|
let rma = &mut u.a;
|
||||||
let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
||||||
//[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
|
|
||||||
drop(rma);
|
drop(rma);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let rma = &mut u.a;
|
let rma = &mut u.a;
|
||||||
u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
|
u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||||
//[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
|
|
||||||
drop(rma);
|
drop(rma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,115 +1,115 @@
|
||||||
error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
||||||
--> $DIR/borrowck-union-borrow.rs:27:28
|
--> $DIR/borrowck-union-borrow.rs:25:28
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| --- immutable borrow occurs here
|
| --- immutable borrow occurs here
|
||||||
LL | let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
LL | let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
|
||||||
| ^^^ mutable borrow occurs here
|
| ^^^ mutable borrow occurs here
|
||||||
...
|
LL | drop(ra);
|
||||||
LL | }
|
LL | }
|
||||||
| - immutable borrow ends here
|
| - immutable borrow ends here
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.a` because it is borrowed
|
error[E0506]: cannot assign to `u.a` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:33:13
|
--> $DIR/borrowck-union-borrow.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| --- borrow of `u.a` occurs here
|
| --- borrow of `u.a` occurs here
|
||||||
LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
|
LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
error[E0502]: cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
||||||
--> $DIR/borrowck-union-borrow.rs:50:28
|
--> $DIR/borrowck-union-borrow.rs:46:28
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| --- immutable borrow occurs here (via `u.a`)
|
| --- immutable borrow occurs here (via `u.a`)
|
||||||
LL | let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
LL | let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
|
||||||
| ^^^ mutable borrow occurs here (via `u.b`)
|
| ^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
|
||||||
...
|
LL | drop(ra);
|
||||||
LL | }
|
LL | }
|
||||||
| - immutable borrow ends here
|
| - immutable borrow ends here
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.b` because it is borrowed
|
error[E0506]: cannot assign to `u.b` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:56:13
|
--> $DIR/borrowck-union-borrow.rs:51:13
|
||||||
|
|
|
|
||||||
LL | let ra = &u.a;
|
LL | let ra = &u.a;
|
||||||
| --- borrow of `u.b` occurs here
|
| --- borrow of `u.b` occurs here
|
||||||
LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
|
LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
||||||
--> $DIR/borrowck-union-borrow.rs:63:23
|
--> $DIR/borrowck-union-borrow.rs:57:23
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| --- mutable borrow occurs here
|
| --- mutable borrow occurs here
|
||||||
LL | let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
LL | let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
|
||||||
| ^^^ immutable borrow occurs here
|
| ^^^ immutable borrow occurs here
|
||||||
...
|
LL | drop(rma);
|
||||||
LL | }
|
LL | }
|
||||||
| - mutable borrow ends here
|
| - mutable borrow ends here
|
||||||
|
|
||||||
error[E0503]: cannot use `u.a` because it was mutably borrowed
|
error[E0503]: cannot use `u.a` because it was mutably borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:69:17
|
--> $DIR/borrowck-union-borrow.rs:62:17
|
||||||
|
|
|
|
||||||
LL | let ra = &mut u.a;
|
LL | let ra = &mut u.a;
|
||||||
| --- borrow of `u.a` occurs here
|
| --- borrow of `u.a` occurs here
|
||||||
LL | let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
|
LL | let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
|
||||||
| ^ use of borrowed `u.a`
|
| ^ use of borrowed `u.a`
|
||||||
|
|
||||||
error[E0499]: cannot borrow `u.a` as mutable more than once at a time
|
error[E0499]: cannot borrow `u.a` as mutable more than once at a time
|
||||||
--> $DIR/borrowck-union-borrow.rs:75:29
|
--> $DIR/borrowck-union-borrow.rs:67:29
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| --- first mutable borrow occurs here
|
| --- first mutable borrow occurs here
|
||||||
LL | let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
LL | let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
|
||||||
| ^^^ second mutable borrow occurs here
|
| ^^^ second mutable borrow occurs here
|
||||||
...
|
LL | drop(rma);
|
||||||
LL | }
|
LL | }
|
||||||
| - first borrow ends here
|
| - first borrow ends here
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.a` because it is borrowed
|
error[E0506]: cannot assign to `u.a` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:81:13
|
--> $DIR/borrowck-union-borrow.rs:72:13
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| --- borrow of `u.a` occurs here
|
| --- borrow of `u.a` occurs here
|
||||||
LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
|
LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
| ^^^^^^^ assignment to borrowed `u.a` occurs here
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
error[E0502]: cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
||||||
--> $DIR/borrowck-union-borrow.rs:88:23
|
--> $DIR/borrowck-union-borrow.rs:78:23
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| --- mutable borrow occurs here (via `u.a`)
|
| --- mutable borrow occurs here (via `u.a`)
|
||||||
LL | let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
LL | let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
|
||||||
| ^^^ immutable borrow occurs here (via `u.b`)
|
| ^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
|
||||||
...
|
LL | drop(rma);
|
||||||
LL | }
|
LL | }
|
||||||
| - mutable borrow ends here
|
| - mutable borrow ends here
|
||||||
|
|
||||||
error[E0503]: cannot use `u.b` because it was mutably borrowed
|
error[E0503]: cannot use `u.b` because it was mutably borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:94:17
|
--> $DIR/borrowck-union-borrow.rs:83:17
|
||||||
|
|
|
|
||||||
LL | let ra = &mut u.a;
|
LL | let ra = &mut u.a;
|
||||||
| --- borrow of `u.a` occurs here
|
| --- borrow of `u.a` occurs here
|
||||||
LL | let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed
|
LL | let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
|
||||||
| ^ use of borrowed `u.a`
|
| ^ use of borrowed `u.a`
|
||||||
|
|
||||||
error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
||||||
--> $DIR/borrowck-union-borrow.rs:101:29
|
--> $DIR/borrowck-union-borrow.rs:89:29
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| --- first mutable borrow occurs here (via `u.a`)
|
| --- first mutable borrow occurs here (via `u.a`)
|
||||||
LL | let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
LL | let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
|
||||||
| ^^^ second mutable borrow occurs here (via `u.b`)
|
| ^^^ second mutable borrow occurs here (via `u.b`)
|
||||||
...
|
LL | drop(rma);
|
||||||
LL | }
|
LL | }
|
||||||
| - first borrow ends here
|
| - first borrow ends here
|
||||||
|
|
||||||
error[E0506]: cannot assign to `u.b` because it is borrowed
|
error[E0506]: cannot assign to `u.b` because it is borrowed
|
||||||
--> $DIR/borrowck-union-borrow.rs:107:13
|
--> $DIR/borrowck-union-borrow.rs:94:13
|
||||||
|
|
|
|
||||||
LL | let rma = &mut u.a;
|
LL | let rma = &mut u.a;
|
||||||
| --- borrow of `u.b` occurs here
|
| --- borrow of `u.b` occurs here
|
||||||
LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
|
LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
|
||||||
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
| ^^^^^^^ assignment to borrowed `u.b` occurs here
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error: aborting due to 12 previous errors
|
|
@ -13,7 +13,7 @@ error[E0502]: cannot borrow `foo` (via `foo.b`) as immutable because `foo` is al
|
||||||
--> $DIR/issue-17263.rs:21:32
|
--> $DIR/issue-17263.rs:21:32
|
||||||
|
|
|
|
||||||
LL | let (c, d) = (&mut foo.a, &foo.b);
|
LL | let (c, d) = (&mut foo.a, &foo.b);
|
||||||
| ----- ^^^^^ immutable borrow occurs here (via `foo.b`)
|
| ----- ^^^^^ immutable borrow of `foo.b` -- which overlaps with `foo.a` -- occurs here
|
||||||
| |
|
| |
|
||||||
| mutable borrow occurs here (via `foo.a`)
|
| mutable borrow occurs here (via `foo.a`)
|
||||||
...
|
...
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
|
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
struct S {
|
struct S {
|
||||||
a: u8,
|
a: u8,
|
||||||
|
@ -25,8 +27,7 @@ fn main() {
|
||||||
*mref = 22;
|
*mref = 22;
|
||||||
|
|
||||||
let nref = &u.z.c;
|
let nref = &u.z.c;
|
||||||
//~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
|
//~^ ERROR cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`) [E0502]
|
||||||
println!("{} {}", mref, nref)
|
println!("{} {}", mref, nref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
error[E0502]: cannot borrow `u.z.c` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`)
|
||||||
--> $DIR/issue-45157.rs:27:20
|
--> $DIR/issue-45157.rs:29:20
|
||||||
|
|
|
|
||||||
LL | let mref = &mut u.s.a;
|
LL | let mref = &mut u.s.a;
|
||||||
| ---------- mutable borrow occurs here
|
| ---------- mutable borrow occurs here (via `u.s.a`)
|
||||||
...
|
...
|
||||||
LL | let nref = &u.z.c;
|
LL | let nref = &u.z.c;
|
||||||
| ^^^^^^ immutable borrow occurs here
|
| ^^^^^^ immutable borrow of `u.z.c` -- which overlaps with `u.s.a` -- occurs here
|
||||||
LL | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
|
LL | //~^ ERROR cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`) [E0502]
|
||||||
LL | println!("{} {}", mref, nref)
|
LL | println!("{} {}", mref, nref)
|
||||||
| ---- mutable borrow later used here
|
| ---- mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.z.c` is a field of the union `U`, so it overlaps the field `u.s.a`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
69
src/test/ui/nll/issue-57100.rs
Normal file
69
src/test/ui/nll/issue-57100.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
#![feature(nll)]
|
||||||
|
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
// This tests the error messages for borrows of union fields when the unions are embedded in other
|
||||||
|
// structs or unions.
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
struct Leaf {
|
||||||
|
l1_u8: u8,
|
||||||
|
l2_u8: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
union First {
|
||||||
|
f1_leaf: Leaf,
|
||||||
|
f2_leaf: Leaf,
|
||||||
|
f3_union: Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
union Second {
|
||||||
|
s1_leaf: Leaf,
|
||||||
|
s2_leaf: Leaf,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Root {
|
||||||
|
r1_u8: u8,
|
||||||
|
r2_union: First,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borrow a different field of the nested union.
|
||||||
|
fn nested_union() {
|
||||||
|
unsafe {
|
||||||
|
let mut r = Root {
|
||||||
|
r1_u8: 3,
|
||||||
|
r2_union: First { f3_union: Second { s2_leaf: Leaf { l1_u8: 8, l2_u8: 4 } } }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mref = &mut r.r2_union.f3_union.s1_leaf.l1_u8;
|
||||||
|
// ^^^^^^^
|
||||||
|
*mref = 22;
|
||||||
|
let nref = &r.r2_union.f3_union.s2_leaf.l1_u8;
|
||||||
|
// ^^^^^^^
|
||||||
|
//~^^ ERROR cannot borrow `r.r2_union.f3_union` (via `r.r2_union.f3_union.s2_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f3_union.s1_leaf.l1_u8`) [E0502]
|
||||||
|
println!("{} {}", mref, nref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borrow a different field of the first union.
|
||||||
|
fn first_union() {
|
||||||
|
unsafe {
|
||||||
|
let mut r = Root {
|
||||||
|
r1_u8: 3,
|
||||||
|
r2_union: First { f3_union: Second { s2_leaf: Leaf { l1_u8: 8, l2_u8: 4 } } }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mref = &mut r.r2_union.f2_leaf.l1_u8;
|
||||||
|
// ^^^^^^^
|
||||||
|
*mref = 22;
|
||||||
|
let nref = &r.r2_union.f1_leaf.l1_u8;
|
||||||
|
// ^^^^^^^
|
||||||
|
//~^^ ERROR cannot borrow `r.r2_union` (via `r.r2_union.f1_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f2_leaf.l1_u8`) [E0502]
|
||||||
|
println!("{} {}", mref, nref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
31
src/test/ui/nll/issue-57100.stderr
Normal file
31
src/test/ui/nll/issue-57100.stderr
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
error[E0502]: cannot borrow `r.r2_union.f3_union` (via `r.r2_union.f3_union.s2_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f3_union.s1_leaf.l1_u8`)
|
||||||
|
--> $DIR/issue-57100.rs:44:20
|
||||||
|
|
|
||||||
|
LL | let mref = &mut r.r2_union.f3_union.s1_leaf.l1_u8;
|
||||||
|
| -------------------------------------- mutable borrow occurs here (via `r.r2_union.f3_union.s1_leaf.l1_u8`)
|
||||||
|
...
|
||||||
|
LL | let nref = &r.r2_union.f3_union.s2_leaf.l1_u8;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow of `r.r2_union.f3_union.s2_leaf.l1_u8` -- which overlaps with `r.r2_union.f3_union.s1_leaf.l1_u8` -- occurs here
|
||||||
|
...
|
||||||
|
LL | println!("{} {}", mref, nref)
|
||||||
|
| ---- mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `r.r2_union.f3_union.s2_leaf.l1_u8` is a field of the union `Second`, so it overlaps the field `r.r2_union.f3_union.s1_leaf.l1_u8`
|
||||||
|
|
||||||
|
error[E0502]: cannot borrow `r.r2_union` (via `r.r2_union.f1_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f2_leaf.l1_u8`)
|
||||||
|
--> $DIR/issue-57100.rs:62:20
|
||||||
|
|
|
||||||
|
LL | let mref = &mut r.r2_union.f2_leaf.l1_u8;
|
||||||
|
| ----------------------------- mutable borrow occurs here (via `r.r2_union.f2_leaf.l1_u8`)
|
||||||
|
...
|
||||||
|
LL | let nref = &r.r2_union.f1_leaf.l1_u8;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow of `r.r2_union.f1_leaf.l1_u8` -- which overlaps with `r.r2_union.f2_leaf.l1_u8` -- occurs here
|
||||||
|
...
|
||||||
|
LL | println!("{} {}", mref, nref)
|
||||||
|
| ---- mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `r.r2_union.f1_leaf.l1_u8` is a field of the union `First`, so it overlaps the field `r.r2_union.f2_leaf.l1_u8`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0502`.
|
|
@ -28,7 +28,7 @@ fn foo<T>(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /*
|
||||||
|
|
||||||
// Full example of enumerate iterator
|
// Full example of enumerate iterator
|
||||||
|
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
struct StreamEnumerate<I> {
|
struct StreamEnumerate<I> {
|
||||||
iter: I,
|
iter: I,
|
||||||
count: usize,
|
count: usize,
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
error[E0502]: cannot borrow `u.y` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
|
||||||
--> $DIR/union-borrow-move-parent-sibling.rs:15:13
|
--> $DIR/union-borrow-move-parent-sibling.rs:15:13
|
||||||
|
|
|
|
||||||
LL | let a = &mut u.x.0;
|
LL | let a = &mut u.x.0;
|
||||||
| ---------- mutable borrow occurs here
|
| ---------- mutable borrow occurs here (via `u.x.0`)
|
||||||
LL | let b = &u.y; //~ ERROR cannot borrow `u.y`
|
LL | let b = &u.y; //~ ERROR cannot borrow `u.y`
|
||||||
| ^^^^ immutable borrow occurs here
|
| ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
|
||||||
LL | use_borrow(a);
|
LL | use_borrow(a);
|
||||||
| - mutable borrow later used here
|
| - mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
|
||||||
|
|
||||||
error[E0382]: use of moved value: `u`
|
error[E0382]: use of moved value: `u`
|
||||||
--> $DIR/union-borrow-move-parent-sibling.rs:22:13
|
--> $DIR/union-borrow-move-parent-sibling.rs:22:13
|
||||||
|
@ -18,15 +20,17 @@ LL | let b = u.y; //~ ERROR use of moved value: `u.y`
|
||||||
|
|
|
|
||||||
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u.y` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
|
||||||
--> $DIR/union-borrow-move-parent-sibling.rs:28:13
|
--> $DIR/union-borrow-move-parent-sibling.rs:28:13
|
||||||
|
|
|
|
||||||
LL | let a = &mut (u.x.0).0;
|
LL | let a = &mut (u.x.0).0;
|
||||||
| -------------- mutable borrow occurs here
|
| -------------- mutable borrow occurs here (via `u.x.0.0`)
|
||||||
LL | let b = &u.y; //~ ERROR cannot borrow `u.y`
|
LL | let b = &u.y; //~ ERROR cannot borrow `u.y`
|
||||||
| ^^^^ immutable borrow occurs here
|
| ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
|
||||||
LL | use_borrow(a);
|
LL | use_borrow(a);
|
||||||
| - mutable borrow later used here
|
| - mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
|
||||||
|
|
||||||
error[E0382]: use of moved value: `u`
|
error[E0382]: use of moved value: `u`
|
||||||
--> $DIR/union-borrow-move-parent-sibling.rs:35:13
|
--> $DIR/union-borrow-move-parent-sibling.rs:35:13
|
||||||
|
@ -38,15 +42,17 @@ LL | let b = u.y; //~ ERROR use of moved value: `u.y`
|
||||||
|
|
|
|
||||||
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||||
|
|
||||||
error[E0502]: cannot borrow `u.x` as immutable because it is also borrowed as mutable
|
error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`)
|
||||||
--> $DIR/union-borrow-move-parent-sibling.rs:41:13
|
--> $DIR/union-borrow-move-parent-sibling.rs:41:13
|
||||||
|
|
|
|
||||||
LL | let a = &mut *u.y;
|
LL | let a = &mut *u.y;
|
||||||
| --------- mutable borrow occurs here
|
| --------- mutable borrow occurs here (via `*u.y`)
|
||||||
LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
|
LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
|
||||||
| ^^^^ immutable borrow occurs here
|
| ^^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here
|
||||||
LL | use_borrow(a);
|
LL | use_borrow(a);
|
||||||
| - mutable borrow later used here
|
| - mutable borrow later used here
|
||||||
|
|
|
||||||
|
= note: `u.x` is a field of the union `U`, so it overlaps the field `*u.y`
|
||||||
|
|
||||||
error[E0382]: use of moved value: `u`
|
error[E0382]: use of moved value: `u`
|
||||||
--> $DIR/union-borrow-move-parent-sibling.rs:48:13
|
--> $DIR/union-borrow-move-parent-sibling.rs:48:13
|
||||||
|
|
|
@ -46,7 +46,7 @@ error[E0502]: cannot borrow `u` (via `u.x`) as immutable because `u` is also bor
|
||||||
LL | let a = &mut *u.y;
|
LL | let a = &mut *u.y;
|
||||||
| ---- mutable borrow occurs here (via `*u.y`)
|
| ---- mutable borrow occurs here (via `*u.y`)
|
||||||
LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
|
LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
|
||||||
| ^^^ immutable borrow occurs here (via `u.x`)
|
| ^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here
|
||||||
LL | use_borrow(a);
|
LL | use_borrow(a);
|
||||||
LL | }
|
LL | }
|
||||||
| - mutable borrow ends here
|
| - mutable borrow ends here
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue