Merge branch 'master' into redox_builder

This commit is contained in:
Artyom Pavlov 2019-08-20 10:08:57 +00:00 committed by GitHub
commit e500fc3171
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
207 changed files with 4819 additions and 3251 deletions

View file

@ -70,7 +70,7 @@ for details on how to format and write long error codes.
[librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/error_codes.rs),
[librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/error_codes.rs),
[librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/error_codes.rs),
[librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs),
[librustc_plugin_impl](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs),
[librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/error_codes.rs).
* Explanations have full markdown support. Use it, especially to highlight
code with backticks.

View file

@ -0,0 +1,36 @@
# `or_patterns`
The tracking issue for this feature is: [#54883]
[#54883]: https://github.com/rust-lang/rust/issues/54883
------------------------
The `or_pattern` language feature allows `|` to be arbitrarily nested within
a pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern.
## Examples
```rust,ignore
#![feature(or_patterns)]
pub enum Foo {
Bar,
Baz,
Quux,
}
pub fn example(maybe_foo: Option<Foo>) {
match maybe_foo {
Some(Foo::Bar | Foo::Baz) => {
println!("The value contained `Bar` or `Baz`");
}
Some(_) => {
println!("The value did not contain `Bar` or `Baz`");
}
None => {
println!("The value was `None`");
}
}
}
```

View file

@ -18,7 +18,7 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc.
A plugin is a dynamic library crate with a designated *registrar* function that
registers extensions with `rustc`. Other crates can load these extensions using
the crate attribute `#![plugin(...)]`. See the
`rustc_plugin` documentation for more about the
`rustc_driver::plugin` documentation for more about the
mechanics of defining and loading a plugin.
If present, arguments passed as `#![plugin(foo(... args ...))]` are not
@ -54,13 +54,13 @@ that implements Roman numeral integer literals.
extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
extern crate rustc_driver;
use syntax::parse::token::{self, Token};
use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax_pos::Span;
use rustc_plugin::Registry;
use rustc_driver::plugin::Registry;
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
-> Box<dyn MacResult + 'static> {
@ -180,11 +180,11 @@ extern crate syntax;
// Load rustc as a plugin to get macros
#[macro_use]
extern crate rustc;
extern crate rustc_plugin;
extern crate rustc_driver;
use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
EarlyLintPassObject, LintArray};
use rustc_plugin::Registry;
use rustc_driver::plugin::Registry;
use syntax::ast;
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");

View file

@ -91,8 +91,10 @@ use core::ops::{
CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
};
use core::ptr::{self, NonNull, Unique};
use core::slice;
use core::task::{Context, Poll};
use crate::alloc::{self, Global, Alloc};
use crate::vec::Vec;
use crate::raw_vec::RawVec;
use crate::str::from_boxed_utf8_unchecked;
@ -121,6 +123,34 @@ impl<T> Box<T> {
box x
}
/// Constructs a new box with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
let ptr = unsafe {
Global.alloc(layout)
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
};
Box(ptr.cast().into())
}
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
/// `x` will be pinned in memory and unable to be moved.
#[stable(feature = "pin", since = "1.33.0")]
@ -130,6 +160,111 @@ impl<T> Box<T> {
}
}
impl<T> Box<[T]> {
/// Constructs a new boxed slice with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// values[0].as_mut_ptr().write(1);
/// values[1].as_mut_ptr().write(2);
/// values[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
let ptr = unsafe { alloc::alloc(layout) };
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) };
Box(Unique::from(slice))
}
}
impl<T> Box<mem::MaybeUninit<T>> {
/// Converts to `Box<T>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five: Box<u32> = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Box<T> {
Box(Box::into_unique(self).cast())
}
}
impl<T> Box<[mem::MaybeUninit<T>]> {
/// Converts to `Box<[T]>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the values
/// really are in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// values[0].as_mut_ptr().write(1);
/// values[1].as_mut_ptr().write(2);
/// values[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Box<[T]> {
Box(Unique::new_unchecked(Box::into_raw(self) as _))
}
}
impl<T: ?Sized> Box<T> {
/// Constructs a box from a raw pointer.
///

View file

@ -1199,6 +1199,31 @@ impl<T> VecDeque<T> {
}
}
/// Removes the last element from the `VecDeque` and returns it, or `None` if
/// it is empty.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// assert_eq!(buf.pop_back(), None);
/// buf.push_back(1);
/// buf.push_back(3);
/// assert_eq!(buf.pop_back(), Some(3));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pop_back(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
self.head = self.wrap_sub(self.head, 1);
let head = self.head;
unsafe { Some(self.buffer_read(head)) }
}
}
/// Prepends an element to the `VecDeque`.
///
/// # Examples
@ -1243,71 +1268,11 @@ impl<T> VecDeque<T> {
unsafe { self.buffer_write(head, value) }
}
/// Removes the last element from the `VecDeque` and returns it, or `None` if
/// it is empty.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// assert_eq!(buf.pop_back(), None);
/// buf.push_back(1);
/// buf.push_back(3);
/// assert_eq!(buf.pop_back(), Some(3));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pop_back(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
self.head = self.wrap_sub(self.head, 1);
let head = self.head;
unsafe { Some(self.buffer_read(head)) }
}
}
#[inline]
fn is_contiguous(&self) -> bool {
self.tail <= self.head
}
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
/// last element.
///
/// This does not preserve ordering, but is O(1).
///
/// Returns `None` if `index` is out of bounds.
///
/// Element at index 0 is the front of the queue.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// assert_eq!(buf.swap_remove_back(0), None);
/// buf.push_back(1);
/// buf.push_back(2);
/// buf.push_back(3);
/// assert_eq!(buf, [1, 2, 3]);
///
/// assert_eq!(buf.swap_remove_back(0), Some(1));
/// assert_eq!(buf, [3, 2]);
/// ```
#[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
let length = self.len();
if length > 0 && index < length - 1 {
self.swap(index, length - 1);
} else if index >= length {
return None;
}
self.pop_back()
}
/// Removes an element from anywhere in the `VecDeque` and returns it,
/// replacing it with the first element.
///
@ -1343,6 +1308,41 @@ impl<T> VecDeque<T> {
self.pop_front()
}
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
/// last element.
///
/// This does not preserve ordering, but is O(1).
///
/// Returns `None` if `index` is out of bounds.
///
/// Element at index 0 is the front of the queue.
///
/// # Examples
///
/// ```
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// assert_eq!(buf.swap_remove_back(0), None);
/// buf.push_back(1);
/// buf.push_back(2);
/// buf.push_back(3);
/// assert_eq!(buf, [1, 2, 3]);
///
/// assert_eq!(buf.swap_remove_back(0), Some(1));
/// assert_eq!(buf, [3, 2]);
/// ```
#[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
let length = self.len();
if length > 0 && index < length - 1 {
self.swap(index, length - 1);
} else if index >= length {
return None;
}
self.pop_back()
}
/// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices
/// greater than or equal to `index` towards the back.
///

View file

@ -327,6 +327,37 @@ impl<T> Rc<T> {
}))
}
/// Constructs a new `Rc` with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut five = Rc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
unsafe {
Rc::from_ptr(Rc::allocate_for_layout(
Layout::new::<T>(),
|mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
))
}
}
/// Constructs a new `Pin<Rc<T>>`. If `T` does not implement `Unpin`, then
/// `value` will be pinned in memory and unable to be moved.
#[stable(feature = "pin", since = "1.33.0")]
@ -377,6 +408,118 @@ impl<T> Rc<T> {
}
}
impl<T> Rc<[T]> {
/// Constructs a new reference-counted slice with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
unsafe {
Rc::from_ptr(Rc::allocate_for_slice(len))
}
}
}
impl<T> Rc<mem::MaybeUninit<T>> {
/// Converts to `Rc<T>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut five = Rc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Rc<T> {
Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
}
}
impl<T> Rc<[mem::MaybeUninit<T>]> {
/// Converts to `Rc<[T]>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Rc<[T]> {
Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
}
}
impl<T: ?Sized> Rc<T> {
/// Consumes the `Rc`, returning the wrapped pointer.
///
@ -560,13 +703,46 @@ impl<T: ?Sized> Rc<T> {
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
if Rc::is_unique(this) {
unsafe {
Some(&mut this.ptr.as_mut().value)
Some(Rc::get_mut_unchecked(this))
}
} else {
None
}
}
/// Returns a mutable reference to the inner value,
/// without any check.
///
/// See also [`get_mut`], which is safe and does appropriate checks.
///
/// [`get_mut`]: struct.Rc.html#method.get_mut
///
/// # Safety
///
/// Any other `Rc` or [`Weak`] pointers to the same value must not be dereferenced
/// for the duration of the returned borrow.
/// This is trivially the case if no such pointers exist,
/// for example immediately after `Rc::new`.
///
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut x = Rc::new(String::new());
/// unsafe {
/// Rc::get_mut_unchecked(&mut x).push_str("foo")
/// }
/// assert_eq!(*x, "foo");
/// ```
#[inline]
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
&mut this.ptr.as_mut().value
}
#[inline]
#[stable(feature = "ptr_eq", since = "1.17.0")]
/// Returns `true` if the two `Rc`s point to the same value (not
@ -704,11 +880,11 @@ impl Rc<dyn Any> {
impl<T: ?Sized> Rc<T> {
/// Allocates an `RcBox<T>` with sufficient space for
/// an unsized value where the value has the layout provided.
/// a possibly-unsized value where the value has the layout provided.
///
/// The function `mem_to_rcbox` is called with the data pointer
/// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
unsafe fn allocate_for_unsized(
unsafe fn allocate_for_layout(
value_layout: Layout,
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>
) -> *mut RcBox<T> {
@ -737,7 +913,7 @@ impl<T: ?Sized> Rc<T> {
/// Allocates an `RcBox<T>` with sufficient space for an unsized value
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
// Allocate for the `RcBox<T>` using the given value.
Self::allocate_for_unsized(
Self::allocate_for_layout(
Layout::for_value(&*ptr),
|mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>,
)
@ -768,7 +944,7 @@ impl<T: ?Sized> Rc<T> {
impl<T> Rc<[T]> {
/// Allocates an `RcBox<[T]>` with the given length.
unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
Self::allocate_for_unsized(
Self::allocate_for_layout(
Layout::array::<T>(len).unwrap(),
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>,
)

View file

@ -107,10 +107,6 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
/// // a, b, and foo are all Arcs that point to the same memory location
/// ```
///
/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly
/// the meaning of the code. In the example above, this syntax makes it easier to see that
/// this code is creating a new reference rather than copying the whole content of foo.
///
/// ## `Deref` behavior
///
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
@ -311,6 +307,37 @@ impl<T> Arc<T> {
Self::from_inner(Box::into_raw_non_null(x))
}
/// Constructs a new `Arc` with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut five = Arc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
unsafe {
Arc::from_ptr(Arc::allocate_for_layout(
Layout::new::<T>(),
|mem| mem as *mut ArcInner<mem::MaybeUninit<T>>,
))
}
}
/// Constructs a new `Pin<Arc<T>>`. If `T` does not implement `Unpin`, then
/// `data` will be pinned in memory and unable to be moved.
#[stable(feature = "pin", since = "1.33.0")]
@ -361,6 +388,118 @@ impl<T> Arc<T> {
}
}
impl<T> Arc<[T]> {
/// Constructs a new reference-counted slice with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
/// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
/// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
unsafe {
Arc::from_ptr(Arc::allocate_for_slice(len))
}
}
}
impl<T> Arc<mem::MaybeUninit<T>> {
/// Converts to `Arc<T>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut five = Arc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Arc<T> {
Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
}
}
impl<T> Arc<[mem::MaybeUninit<T>]> {
/// Converts to `Arc<[T]>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
/// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
/// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Arc<[T]> {
Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
}
}
impl<T: ?Sized> Arc<T> {
/// Consumes the `Arc`, returning the wrapped pointer.
///
@ -593,11 +732,11 @@ impl<T: ?Sized> Arc<T> {
impl<T: ?Sized> Arc<T> {
/// Allocates an `ArcInner<T>` with sufficient space for
/// an unsized value where the value has the layout provided.
/// a possibly-unsized value where the value has the layout provided.
///
/// The function `mem_to_arcinner` is called with the data pointer
/// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
unsafe fn allocate_for_unsized(
unsafe fn allocate_for_layout(
value_layout: Layout,
mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>
) -> *mut ArcInner<T> {
@ -625,7 +764,7 @@ impl<T: ?Sized> Arc<T> {
/// Allocates an `ArcInner<T>` with sufficient space for an unsized value.
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
// Allocate for the `ArcInner<T>` using the given value.
Self::allocate_for_unsized(
Self::allocate_for_layout(
Layout::for_value(&*ptr),
|mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>,
)
@ -656,7 +795,7 @@ impl<T: ?Sized> Arc<T> {
impl<T> Arc<[T]> {
/// Allocates an `ArcInner<[T]>` with the given length.
unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
Self::allocate_for_unsized(
Self::allocate_for_layout(
Layout::array::<T>(len).unwrap(),
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>,
)
@ -945,13 +1084,46 @@ impl<T: ?Sized> Arc<T> {
// the Arc itself to be `mut`, so we're returning the only possible
// reference to the inner data.
unsafe {
Some(&mut this.ptr.as_mut().data)
Some(Arc::get_mut_unchecked(this))
}
} else {
None
}
}
/// Returns a mutable reference to the inner value,
/// without any check.
///
/// See also [`get_mut`], which is safe and does appropriate checks.
///
/// [`get_mut`]: struct.Arc.html#method.get_mut
///
/// # Safety
///
/// Any other `Arc` or [`Weak`] pointers to the same value must not be dereferenced
/// for the duration of the returned borrow.
/// This is trivially the case if no such pointers exist,
/// for example immediately after `Arc::new`.
///
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut x = Arc::new(String::new());
/// unsafe {
/// Arc::get_mut_unchecked(&mut x).push_str("foo")
/// }
/// assert_eq!(*x, "foo");
/// ```
#[inline]
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
&mut this.ptr.as_mut().data
}
/// Determine whether this is the unique reference (including weak refs) to
/// the underlying data.
///

View file

@ -122,6 +122,14 @@ impl<T: ?Sized> Unique<T> {
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}
/// Casts to a pointer of another type.
#[inline]
pub const fn cast<U>(self) -> Unique<U> {
unsafe {
Unique::new_unchecked(self.as_ptr() as *mut U)
}
}
}
#[unstable(feature = "ptr_internals", issue = "0")]

View file

@ -468,6 +468,14 @@ pub enum ProcMacro {
}
impl ProcMacro {
pub fn name(&self) -> &'static str {
match self {
ProcMacro::CustomDerive { trait_name, .. } => trait_name,
ProcMacro::Attr { name, .. } => name,
ProcMacro::Bang { name, ..} => name
}
}
pub const fn custom_derive(
trait_name: &'static str,
attributes: &'static [&'static str],

View file

@ -140,6 +140,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
}
PatKind::Or(ref pats) => {
let branches: Vec<_> = pats.iter().map(|p| self.pat(p, pred)).collect();
self.add_ast_node(pat.hir_id.local_id, &branches)
}
PatKind::Slice(ref pre, ref vec, ref post) => {
let pre_exit = self.pats_all(pre.iter(), pred);
let vec_exit = self.pats_all(vec.iter(), pre_exit);

View file

@ -1,5 +1,4 @@
use crate::ty::{self, TyCtxt};
use crate::hir::map::definitions::FIRST_FREE_DEF_INDEX;
use rustc_data_structures::indexed_vec::Idx;
use std::fmt;
use std::u32;
@ -102,31 +101,6 @@ newtype_index! {
}
}
impl DefIndex {
// Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
// function maps the index of the macro within the crate (which is also the
// index of the macro in the CrateMetadata::proc_macros array) to the
// corresponding DefIndex.
pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex {
// DefIndex for proc macros start from FIRST_FREE_DEF_INDEX,
// because the first FIRST_FREE_DEF_INDEX indexes are reserved
// for internal use.
let def_index = DefIndex::from(
proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX)
.expect("integer overflow adding `proc_macro_index`"));
assert!(def_index != CRATE_DEF_INDEX);
def_index
}
// This function is the reverse of from_proc_macro_index() above.
pub fn to_proc_macro_index(self: DefIndex) -> usize {
self.index().checked_sub(FIRST_FREE_DEF_INDEX)
.unwrap_or_else(|| {
bug!("using local index {:?} as proc-macro index", self)
})
}
}
impl rustc_serialize::UseSpecializedEncodable for DefIndex {}
impl rustc_serialize::UseSpecializedDecodable for DefIndex {}

View file

@ -433,6 +433,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
LifetimeName::Static |
LifetimeName::Error |
LifetimeName::Implicit |
LifetimeName::ImplicitObjectLifetimeDefault |
LifetimeName::Underscore => {}
}
}
@ -709,6 +710,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
visitor.visit_pat(&field.pat)
}
}
PatKind::Or(ref pats) => walk_list!(visitor, visit_pat, pats),
PatKind::Tuple(ref tuple_elements, _) => {
walk_list!(visitor, visit_pat, tuple_elements);
}

View file

@ -72,7 +72,7 @@ use syntax::symbol::{kw, sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::parse::token::{self, Token};
use syntax::visit::{self, Visitor};
use syntax_pos::{DUMMY_SP, Span};
use syntax_pos::Span;
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
@ -322,7 +322,7 @@ enum ParenthesizedGenericArgs {
/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
/// everything into HIR lowering.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
enum AnonymousLifetimeMode {
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
@ -715,10 +715,16 @@ impl<'a> LoweringContext<'a> {
anonymous_lifetime_mode: AnonymousLifetimeMode,
op: impl FnOnce(&mut Self) -> R,
) -> R {
debug!(
"with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
anonymous_lifetime_mode,
);
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
let result = op(self);
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
old_anonymous_lifetime_mode);
result
}
@ -1033,13 +1039,14 @@ impl<'a> LoweringContext<'a> {
/// ```
///
/// returns a `hir::TypeBinding` representing `Item`.
fn lower_assoc_ty_constraint(&mut self,
c: &AssocTyConstraint,
itctx: ImplTraitContext<'_>)
-> hir::TypeBinding {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocTyConstraint,
itctx: ImplTraitContext<'_>,
) -> hir::TypeBinding {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
let kind = match c.kind {
let kind = match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => hir::TypeBindingKind::Equality {
ty: self.lower_ty(ty, itctx)
},
@ -1094,7 +1101,7 @@ impl<'a> LoweringContext<'a> {
impl_trait_node_id,
DefPathData::ImplTrait,
ExpnId::root(),
DUMMY_SP
constraint.span,
);
self.with_dyn_type_scope(false, |this| {
@ -1102,7 +1109,7 @@ impl<'a> LoweringContext<'a> {
&Ty {
id: this.sess.next_node_id(),
node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
span: DUMMY_SP,
span: constraint.span,
},
itctx,
);
@ -1124,10 +1131,10 @@ impl<'a> LoweringContext<'a> {
};
hir::TypeBinding {
hir_id: self.lower_node_id(c.id),
ident: c.ident,
hir_id: self.lower_node_id(constraint.id),
ident: constraint.ident,
kind,
span: c.span,
span: constraint.span,
}
}
@ -1355,6 +1362,13 @@ impl<'a> LoweringContext<'a> {
opaque_ty_node_id: NodeId,
lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
) -> hir::TyKind {
debug!(
"lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
fn_def_id,
opaque_ty_node_id,
span,
);
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
// desugaring that explicitly states that we don't want to track that.
@ -1382,6 +1396,14 @@ impl<'a> LoweringContext<'a> {
&hir_bounds,
);
debug!(
"lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,
);
debug!(
"lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,
);
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
let opaque_ty_item = hir::OpaqueTy {
generics: hir::Generics {
@ -1397,7 +1419,7 @@ impl<'a> LoweringContext<'a> {
origin: hir::OpaqueTyOrigin::FnReturn,
};
trace!("exist ty from impl trait def-index: {:#?}", opaque_ty_def_index);
trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
let opaque_ty_id = lctx.generate_opaque_type(
opaque_ty_node_id,
opaque_ty_item,
@ -1445,6 +1467,13 @@ impl<'a> LoweringContext<'a> {
parent_index: DefIndex,
bounds: &hir::GenericBounds,
) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
debug!(
"lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
parent_index={:?}, \
bounds={:#?})",
opaque_ty_id, parent_index, bounds,
);
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
// appear in the bounds, excluding lifetimes that are created within the bounds.
// E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
@ -1532,6 +1561,11 @@ impl<'a> LoweringContext<'a> {
}
}
hir::LifetimeName::Param(_) => lifetime.name,
// Refers to some other lifetime that is "in
// scope" within the type.
hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
};
@ -2182,6 +2216,14 @@ impl<'a> LoweringContext<'a> {
fn_def_id: DefId,
opaque_ty_node_id: NodeId,
) -> hir::FunctionRetTy {
debug!(
"lower_async_fn_ret_ty(\
output={:?}, \
fn_def_id={:?}, \
opaque_ty_node_id={:?})",
output, fn_def_id, opaque_ty_node_id,
);
let span = output.span();
let opaque_ty_span = self.mark_span_with_reason(
@ -2264,6 +2306,8 @@ impl<'a> LoweringContext<'a> {
),
);
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
// Calculate all the lifetimes that should be captured
// by the opaque type. This should include all in-scope
// lifetime parameters, including those defined in-band.
@ -2512,6 +2556,12 @@ impl<'a> LoweringContext<'a> {
hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
span_bug!(
param.ident.span,
"object-lifetime-default should not occur here",
);
}
hir::LifetimeName::Error => ParamName::Error,
};
@ -2524,15 +2574,6 @@ impl<'a> LoweringContext<'a> {
(param_name, kind)
}
GenericParamKind::Type { ref default, .. } => {
// Don't expose `Self` (recovered "keyword used as ident" parse error).
// `rustc::ty` expects `Self` to be only used for a trait's `Self`.
// Instead, use `gensym("Self")` to create a distinct name that looks the same.
let ident = if param.ident.name == kw::SelfUpper {
param.ident.gensym()
} else {
param.ident
};
let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
if !add_bounds.is_empty() {
let params = self.lower_param_bounds(add_bounds, itctx.reborrow()).into_iter();
@ -2551,7 +2592,7 @@ impl<'a> LoweringContext<'a> {
.next(),
};
(hir::ParamName::Plain(ident), kind)
(hir::ParamName::Plain(param.ident), kind)
}
GenericParamKind::Const { ref ty } => {
(hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const {
@ -2669,6 +2710,9 @@ impl<'a> LoweringContext<'a> {
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
hir::PatKind::TupleStruct(qpath, pats, ddpos)
}
PatKind::Or(ref pats) => {
hir::PatKind::Or(pats.iter().map(|x| self.lower_pat(x)).collect())
}
PatKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
p.id,
@ -3261,7 +3305,13 @@ impl<'a> LoweringContext<'a> {
AnonymousLifetimeMode::PassThrough => {}
}
self.new_implicit_lifetime(span)
let r = hir::Lifetime {
hir_id: self.next_id(),
span,
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
};
debug!("elided_dyn_bound: r={:?}", r);
r
}
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {

View file

@ -74,7 +74,7 @@ impl<'a> DefCollector<'a> {
})
}
fn visit_macro_invoc(&mut self, id: NodeId) {
pub fn visit_macro_invoc(&mut self, id: NodeId) {
self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
}
}

View file

@ -411,10 +411,6 @@ impl Definitions {
}
/// Adds a root definition (no parent) and a few other reserved definitions.
///
/// After the initial definitions are created the first `FIRST_FREE_DEF_INDEX` indexes
/// are taken, so the "user" indexes will be allocated starting with `FIRST_FREE_DEF_INDEX`
/// in ascending order.
pub fn create_root_def(&mut self,
crate_name: &str,
crate_disambiguator: CrateDisambiguator)
@ -589,19 +585,6 @@ impl DefPathData {
}
}
/// Evaluates to the number of tokens passed to it.
///
/// Logarithmic counting: every one or two recursive expansions, the number of
/// tokens to count is divided by two, instead of being reduced by one.
/// Therefore, the recursion depth is the binary logarithm of the number of
/// tokens to count, and the expanded tree is likewise very small.
macro_rules! count {
() => (0usize);
($one:tt) => (1usize);
($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
}
// We define the GlobalMetaDataKind enum with this macro because we want to
// make sure that we exhaustively iterate over all variants when registering
// the corresponding DefIndices in the DefTable.
@ -614,8 +597,6 @@ macro_rules! define_global_metadata_kind {
$($variant),*
}
pub const FIRST_FREE_DEF_INDEX: usize = 1 + count!($($variant)*);
impl GlobalMetaDataKind {
fn allocate_def_indices(definitions: &mut Definitions) {
$({

View file

@ -221,6 +221,19 @@ pub enum LifetimeName {
/// User wrote nothing (e.g., the lifetime in `&u32`).
Implicit,
/// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the
/// lifetime that they default to must appear elsewhere within the
/// enclosing type. This means that, in an `impl Trait` context, we
/// don't have to create a parameter for them. That is, `impl
/// Trait<Item = &u32>` expands to an opaque type like `type
/// Foo<'a> = impl Trait<Item = &'a u32>`, but `impl Trait<item =
/// dyn Bar>` expands to `type Foo = impl Trait<Item = dyn Bar +
/// 'static>`. The latter uses `ImplicitObjectLifetimeDefault` so
/// that surrounding code knows not to create a lifetime
/// parameter.
ImplicitObjectLifetimeDefault,
/// Indicates an error during lowering (usually `'_` in wrong place)
/// that was already reported.
Error,
@ -235,7 +248,9 @@ pub enum LifetimeName {
impl LifetimeName {
pub fn ident(&self) -> Ident {
match *self {
LifetimeName::Implicit | LifetimeName::Error => Ident::invalid(),
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit
| LifetimeName::Error => Ident::invalid(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
LifetimeName::Param(param_name) => param_name.ident(),
@ -244,7 +259,9 @@ impl LifetimeName {
pub fn is_elided(&self) -> bool {
match self {
LifetimeName::Implicit | LifetimeName::Underscore => true,
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit
| LifetimeName::Underscore => true,
// It might seem surprising that `Fresh(_)` counts as
// *not* elided -- but this is because, as far as the code
@ -881,6 +898,7 @@ impl Pat {
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
s.iter().all(|p| p.walk_(it))
}
PatKind::Or(ref pats) => pats.iter().all(|p| p.walk_(it)),
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
s.walk_(it)
}
@ -975,6 +993,10 @@ pub enum PatKind {
/// `0 <= position <= subpats.len()`
TupleStruct(QPath, HirVec<P<Pat>>, Option<usize>),
/// An or-pattern `A | B | C`.
/// Invariant: `pats.len() >= 2`.
Or(HirVec<P<Pat>>),
/// A path pattern for an unit struct/variant or a (maybe-associated) constant.
Path(QPath),

View file

@ -1687,6 +1687,9 @@ impl<'a> State<'a> {
self.s.space();
self.s.word("}");
}
PatKind::Or(ref pats) => {
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(&p));
}
PatKind::Tuple(ref elts, ddpos) => {
self.popen();
if let Some(ddpos) = ddpos {

View file

@ -1329,7 +1329,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let generics = self.tcx.generics_of(did);
// Account for the case where `did` corresponds to `Self`, which doesn't have
// the expected type argument.
if !param.is_self() {
if !(generics.has_self && param.index == 0) {
let type_param = generics.type_param(param, self.tcx);
let hir = &self.tcx.hir();
hir.as_local_hir_id(type_param.def_id).map(|id| {
@ -1337,7 +1337,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
// instead we suggest `T: 'a + 'b` in that case.
let mut has_bounds = false;
if let Node::GenericParam(ref param) = hir.get(id) {
if let Node::GenericParam(param) = hir.get(id) {
has_bounds = !param.bounds.is_empty();
}
let sp = hir.span(id);

View file

@ -127,8 +127,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
debug!(
"instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
param_env={:?})",
value, parent_def_id, body_id, param_env,
param_env={:?}, value_span={:?})",
value, parent_def_id, body_id, param_env, value_span,
);
let mut instantiator = Instantiator {
infcx: self,
@ -1108,9 +1108,11 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
// Use the same type variable if the exact same opaque type appears more
// than once in the return type (e.g., if it's passed to a type alias).
if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
return opaque_defn.concrete_ty;
}
let span = tcx.def_span(def_id);
debug!("fold_opaque_ty {:?} {:?}", self.value_span, span);
let ty_var = infcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });

View file

@ -1290,6 +1290,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
PatKind::Or(ref pats) => {
for pat in pats {
self.cat_pattern_(cmt.clone(), &pat, op)?;
}
}
PatKind::Binding(.., Some(ref subpat)) => {
self.cat_pattern_(cmt, &subpat, op)?;
}

View file

@ -5,6 +5,8 @@
//! used between functions, and they operate in a purely top-down
//! way. Therefore, we break lifetime name resolution into a separate pass.
// ignore-tidy-filelength
use crate::hir::def::{Res, DefKind};
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use crate::hir::map::Map;
@ -556,6 +558,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty);
debug!("visit_ty: ty.node={:?}", ty.node);
match ty.node {
hir::TyKind::BareFn(ref c) => {
let next_early_index = self.next_early_index();
@ -585,11 +588,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.is_in_fn_syntax = was_in_fn_syntax;
}
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime);
for bound in bounds {
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
}
match lifetime.name {
LifetimeName::Implicit => {
// For types like `dyn Foo`, we should
// generate a special form of elided.
span_bug!(
ty.span,
"object-lifetime-default expected, not implict",
);
}
LifetimeName::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we
// use the object lifetime defaulting
// rules. So e.g., `Box<dyn Debug>` becomes
@ -897,6 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref);
if lifetime_ref.is_elided() {
self.resolve_elided_lifetimes(vec![lifetime_ref]);
return;
@ -1911,6 +1924,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
fn visit_segment_args(&mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs) {
debug!(
"visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
res,
depth,
generic_args,
);
if generic_args.parenthesized {
let was_in_fn_syntax = self.is_in_fn_syntax;
self.is_in_fn_syntax = true;
@ -1964,6 +1984,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
_ => None,
};
debug!("visit_segment_args: type_def_id={:?}", type_def_id);
// Compute a vector of defaults, one for each type parameter,
// per the rules given in RFCs 599 and 1156. Example:
//
// ```rust
// struct Foo<'a, T: 'a, U> { }
// ```
//
// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
// and `dyn Baz` to `dyn Baz + 'static` (because there is no
// such bound).
//
// Therefore, we would compute `object_lifetime_defaults` to a
// vector like `['x, 'static]`. Note that the vector only
// includes type parameters.
let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
let in_body = {
let mut scope = self.scope;
@ -2003,6 +2040,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
.collect()
})
};
debug!("visit_segment_args: unsubst={:?}", unsubst);
unsubst
.iter()
.map(|set| match *set {
@ -2023,6 +2061,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
.collect()
});
debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
let mut i = 0;
for arg in &generic_args.args {
match arg {
@ -2045,8 +2085,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
// Hack: when resolving the type `XX` in binding like `dyn
// Foo<'b, Item = XX>`, the current object-lifetime default
// would be to examine the trait `Foo` to check whether it has
// a lifetime bound declared on `Item`. e.g., if `Foo` is
// declared like so, then the default object lifetime bound in
// `XX` should be `'b`:
//
// ```rust
// trait Foo<'a> {
// type Item: 'a;
// }
// ```
//
// but if we just have `type Item;`, then it would be
// `'static`. However, we don't get all of this logic correct.
//
// Instead, we do something hacky: if there are no lifetime parameters
// to the trait, then we simply use a default object lifetime
// bound of `'static`, because there is no other possibility. On the other hand,
// if there ARE lifetime parameters, then we require the user to give an
// explicit bound for now.
//
// This is intended to leave room for us to implement the
// correct behavior in the future.
let has_lifetime_parameter = generic_args
.args
.iter()
.any(|arg| match arg {
GenericArg::Lifetime(_) => true,
_ => false,
});
// Resolve lifetimes found in the type `XX` from `Item = XX` bindings.
for b in &generic_args.bindings {
self.visit_assoc_type_binding(b);
let scope = Scope::ObjectLifetimeDefault {
lifetime: if has_lifetime_parameter {
None
} else {
Some(Region::Static)
},
s: self.scope,
};
self.with(scope, |_, this| this.visit_assoc_type_binding(b));
}
}
@ -2347,6 +2428,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) {
debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs);
if lifetime_refs.is_empty() {
return;
}
@ -2539,6 +2622,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
let mut late_depth = 0;
let mut scope = self.scope;
let lifetime = loop {
@ -2638,6 +2722,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
self.resolve_lifetime_ref(lt);
}
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
self.tcx.sess.delay_span_bug(
lt.span,
"lowering generated `ImplicitObjectLifetimeDefault` \
outside of an object type",
)
}
hir::LifetimeName::Error => {
// No need to do anything, error already reported.
}

View file

@ -306,7 +306,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
///
/// zsts can't be read out of two reasons:
/// * byteorder cannot work with zero element buffers
/// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
/// * in order to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
/// being valid for ZSTs
///
/// It is the caller's responsibility to check bounds and alignment beforehand.

View file

@ -530,7 +530,7 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
pub fn not_undef(self) -> InterpResult<'static, Scalar<Tag>> {
match self {
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::from_bytes(0))),
ScalarMaybeUndef::Undef => throw_unsup!(ReadUndefBytes(Size::ZERO)),
}
}

View file

@ -248,10 +248,10 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
/// This is always inlined, despite its size, because it has a single
/// callsite and it is called *very* frequently.
#[inline(always)]
fn process_obligation(&mut self,
pending_obligation: &mut Self::Obligation)
-> ProcessResult<Self::Obligation, Self::Error>
{
fn process_obligation(
&mut self,
pending_obligation: &mut Self::Obligation,
) -> ProcessResult<Self::Obligation, Self::Error> {
// if we were stalled on some unresolved variables, first check
// whether any of them have been resolved; if not, don't bother
// doing more work yet
@ -277,7 +277,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate);
}
debug!("process_obligation: obligation = {:?}", obligation);
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
match obligation.predicate {
ty::Predicate::Trait(ref data) => {
@ -425,10 +425,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
ty::Predicate::WellFormed(ty) => {
match ty::wf::obligations(self.selcx.infcx(),
obligation.param_env,
obligation.cause.body_id,
ty, obligation.cause.span) {
match ty::wf::obligations(
self.selcx.infcx(),
obligation.param_env,
obligation.cause.body_id,
ty,
obligation.cause.span,
) {
None => {
pending_obligation.stalled_on = vec![ty];
ProcessResult::Unchanged

View file

@ -91,6 +91,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation>
{
debug_assert!(self.generics_of(trait_def_id).has_self);
let violations = traits::supertrait_def_ids(self, trait_def_id)
.filter(|&def_id| self.predicates_reference_self(def_id, true))
.map(|_| ObjectSafetyViolation::SupertraitSelf)
@ -106,6 +107,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn object_safety_violations(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation>
{
debug_assert!(self.generics_of(trait_def_id).has_self);
debug!("object_safety_violations: {:?}", trait_def_id);
traits::supertrait_def_ids(self, trait_def_id)
@ -113,9 +115,25 @@ impl<'tcx> TyCtxt<'tcx> {
.collect()
}
fn object_safety_violations_for_trait(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation>
{
/// We say a method is *vtable safe* if it can be invoked on a trait
/// object. Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self:Sized` or
/// otherwise ensure that they cannot be used when `Self=Trait`.
pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
debug_assert!(self.generics_of(trait_def_id).has_self);
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self : Sized` requisite can't be called.
if self.generics_require_sized_self(method.def_id) {
return false;
}
match self.virtual_call_violation_for_method(trait_def_id, method) {
None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
Some(_) => false,
}
}
fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
// Check methods for violations.
let mut violations: Vec<_> = self.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssocKind::Method)
@ -163,14 +181,16 @@ impl<'tcx> TyCtxt<'tcx> {
fn predicates_reference_self(
self,
trait_def_id: DefId,
supertraits_only: bool) -> bool
{
supertraits_only: bool,
) -> bool {
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
let predicates = if supertraits_only {
self.super_predicates_of(trait_def_id)
} else {
self.predicates_of(trait_def_id)
};
let self_ty = self.types.self_param;
let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty);
predicates
.predicates
.iter()
@ -179,7 +199,7 @@ impl<'tcx> TyCtxt<'tcx> {
match predicate {
ty::Predicate::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
data.skip_binder().input_types().skip(1).any(has_self_ty)
}
ty::Predicate::Projection(ref data) => {
// And similarly for projections. This should be redundant with
@ -199,7 +219,7 @@ impl<'tcx> TyCtxt<'tcx> {
.trait_ref(self)
.input_types()
.skip(1)
.any(|t| t.has_self_ty())
.any(has_self_ty)
}
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
@ -229,11 +249,11 @@ impl<'tcx> TyCtxt<'tcx> {
let predicates = predicates.instantiate_identity(self).predicates;
elaborate_predicates(self, predicates)
.any(|predicate| match predicate {
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
trait_pred.skip_binder().self_ty().is_self()
ty::Predicate::Trait(ref trait_pred) => {
trait_pred.def_id() == sized_def_id
&& trait_pred.skip_binder().self_ty().is_param(0)
}
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Subtype(..) |
ty::Predicate::RegionOutlives(..) |
ty::Predicate::WellFormed(..) |
@ -248,11 +268,11 @@ impl<'tcx> TyCtxt<'tcx> {
}
/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method(self,
trait_def_id: DefId,
method: &ty::AssocItem)
-> Option<MethodViolationCode>
{
fn object_safety_violation_for_method(
self,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self : Sized` requisite is otherwise
// exempt from the regulations.
@ -263,36 +283,15 @@ impl<'tcx> TyCtxt<'tcx> {
self.virtual_call_violation_for_method(trait_def_id, method)
}
/// We say a method is *vtable safe* if it can be invoked on a trait
/// object. Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self:Sized` or
/// otherwise ensure that they cannot be used when `Self=Trait`.
pub fn is_vtable_safe_method(self,
trait_def_id: DefId,
method: &ty::AssocItem)
-> bool
{
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
// Any method that has a `Self : Sized` requisite can't be called.
if self.generics_require_sized_self(method.def_id) {
return false;
}
match self.virtual_call_violation_for_method(trait_def_id, method) {
None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
Some(_) => false,
}
}
/// Returns `Some(_)` if this method cannot be called on a trait
/// object; this does not necessarily imply that the enclosing trait
/// is not object safe, because the method might have a where clause
/// `Self:Sized`.
fn virtual_call_violation_for_method(self,
trait_def_id: DefId,
method: &ty::AssocItem)
-> Option<MethodViolationCode>
{
fn virtual_call_violation_for_method(
self,
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
// The method's first parameter must be named `self`
if !method.method_has_self_argument {
return Some(MethodViolationCode::StaticMethod);
@ -323,7 +322,9 @@ impl<'tcx> TyCtxt<'tcx> {
.collect::<Vec<_>>()
// Do a shallow visit so that `contains_illegal_self_type_reference`
// may apply it's custom visiting.
.visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) {
.visit_tys_shallow(|t| {
self.contains_illegal_self_type_reference(trait_def_id, t)
}) {
let span = self.def_span(method.def_id);
return Some(MethodViolationCode::WhereClauseReferencesSelf(span));
}
@ -337,7 +338,7 @@ impl<'tcx> TyCtxt<'tcx> {
// However, this is already considered object-safe. We allow it as a special case here.
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`
if receiver_ty != self.mk_self_type() {
if receiver_ty != self.types.self_param {
if !self.receiver_is_dispatchable(method, receiver_ty) {
return Some(MethodViolationCode::UndispatchableReceiver);
} else {
@ -404,7 +405,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// Performs a type substitution to produce the version of receiver_ty when `Self = self_ty`
/// e.g., for receiver_ty = `Rc<Self>` and self_ty = `Foo`, returns `Rc<Foo>`.
fn receiver_for_self_ty(
self, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId
self,
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
method_def_id: DefId,
) -> Ty<'tcx> {
debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
let substs = InternalSubsts::for_item(self, method_def_id, |param, _| {
@ -555,7 +559,7 @@ impl<'tcx> TyCtxt<'tcx> {
// Self: Unsize<U>
let unsize_predicate = ty::TraitRef {
def_id: unsize_did,
substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]),
substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]),
}.to_predicate();
// U: Trait<Arg1, ..., ArgN>
@ -608,11 +612,11 @@ impl<'tcx> TyCtxt<'tcx> {
})
}
fn contains_illegal_self_type_reference(self,
trait_def_id: DefId,
ty: Ty<'tcx>)
-> bool
{
fn contains_illegal_self_type_reference(
self,
trait_def_id: DefId,
ty: Ty<'tcx>,
) -> bool {
// This is somewhat subtle. In general, we want to forbid
// references to `Self` in the argument and return types,
// since the value of `Self` is erased. However, there is one
@ -654,10 +658,11 @@ impl<'tcx> TyCtxt<'tcx> {
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
let mut error = false;
let self_ty = self.types.self_param;
ty.maybe_walk(|ty| {
match ty.sty {
ty::Param(ref param_ty) => {
if param_ty.is_self() {
ty::Param(_) => {
if ty == self_ty {
error = true;
}

View file

@ -173,6 +173,7 @@ pub struct CommonTypes<'tcx> {
pub f32: Ty<'tcx>,
pub f64: Ty<'tcx>,
pub never: Ty<'tcx>,
pub self_param: Ty<'tcx>,
pub err: Ty<'tcx>,
/// Dummy type used for the `Self` of a `TraitRef` created for converting
@ -915,6 +916,10 @@ impl<'tcx> CommonTypes<'tcx> {
u128: mk(Uint(ast::UintTy::U128)),
f32: mk(Float(ast::FloatTy::F32)),
f64: mk(Float(ast::FloatTy::F64)),
self_param: mk(ty::Param(ty::ParamTy {
index: 0,
name: kw::SelfUpper.as_interned_str(),
})),
trait_object_dummy_self: mk(Infer(ty::FreshTy(0))),
}
@ -2566,10 +2571,6 @@ impl<'tcx> TyCtxt<'tcx> {
})
}
#[inline]
pub fn mk_self_type(self) -> Ty<'tcx> {
self.mk_ty_param(0, kw::SelfUpper.as_interned_str())
}
pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> Kind<'tcx> {
match param.kind {

View file

@ -239,13 +239,7 @@ impl<'tcx> ty::TyS<'tcx> {
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
ty::Projection(_) => "associated type".into(),
ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
ty::Param(ref p) => {
if p.is_self() {
"Self".into()
} else {
"type parameter".into()
}
}
ty::Param(_) => "type parameter".into(),
ty::Opaque(..) => "opaque type".into(),
ty::Error => "type error".into(),
}

View file

@ -1,5 +1,5 @@
use crate::ty::subst::{SubstsRef, UnpackedKind};
use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst};
use crate::ty::{self, Ty, TypeFlags, InferConst};
use crate::mir::interpret::ConstValue;
#[derive(Debug)]
@ -86,13 +86,9 @@ impl FlagComputation {
self.add_flags(TypeFlags::HAS_TY_ERR)
}
&ty::Param(ref p) => {
&ty::Param(_) => {
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
if p.is_self() {
self.add_flags(TypeFlags::HAS_SELF);
} else {
self.add_flags(TypeFlags::HAS_PARAMS);
}
self.add_flags(TypeFlags::HAS_PARAMS);
}
&ty::Generator(_, ref substs, _) => {
@ -143,11 +139,6 @@ impl FlagComputation {
}
&ty::Projection(ref data) => {
// currently we can't normalize projections that
// include bound regions, so track those separately.
if !data.has_escaping_bound_vars() {
self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
}
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_projection_ty(data);
}
@ -243,7 +234,7 @@ impl FlagComputation {
match c.val {
ConstValue::Unevaluated(_, substs) => {
self.add_substs(substs);
self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION);
self.add_flags(TypeFlags::HAS_PROJECTION);
},
ConstValue::Infer(infer) => {
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER);

View file

@ -85,9 +85,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn has_param_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PARAMS)
}
fn has_self_ty(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_SELF)
}
fn has_infer_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_INFER)
}

View file

@ -298,8 +298,9 @@ impl<'tcx> Instance<'tcx> {
) -> Option<Instance<'tcx>> {
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
let fn_sig = tcx.fn_sig(def_id);
let is_vtable_shim =
fn_sig.inputs().skip_binder().len() > 0 && fn_sig.input(0).skip_binder().is_self();
let is_vtable_shim = fn_sig.inputs().skip_binder().len() > 0
&& fn_sig.input(0).skip_binder().is_param(0)
&& tcx.generics_of(def_id).has_self;
if is_vtable_shim {
debug!(" => associated item with unsizeable self: Self");
Some(Instance {

View file

@ -1601,7 +1601,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// resulting from the final codegen session.
if
layout.ty.has_param_types() ||
layout.ty.has_self_ty() ||
!self.param_env.caller_bounds.is_empty()
{
return;
@ -1767,7 +1766,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.sty {
ty::Param(_) | ty::Projection(_) => {
debug_assert!(tail.has_param_types() || tail.has_self_ty());
debug_assert!(tail.has_param_types());
Ok(SizeSkeleton::Pointer {
non_zero,
tail: tcx.erase_regions(&tail)

View file

@ -414,61 +414,53 @@ pub struct CReaderCacheKey {
bitflags! {
pub struct TypeFlags: u32 {
const HAS_PARAMS = 1 << 0;
const HAS_SELF = 1 << 1;
const HAS_TY_INFER = 1 << 2;
const HAS_RE_INFER = 1 << 3;
const HAS_RE_PLACEHOLDER = 1 << 4;
const HAS_TY_INFER = 1 << 1;
const HAS_RE_INFER = 1 << 2;
const HAS_RE_PLACEHOLDER = 1 << 3;
/// Does this have any `ReEarlyBound` regions? Used to
/// determine whether substitition is required, since those
/// represent regions that are bound in a `ty::Generics` and
/// hence may be substituted.
const HAS_RE_EARLY_BOUND = 1 << 5;
const HAS_RE_EARLY_BOUND = 1 << 4;
/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReLateBound` and `ReErased`.
const HAS_FREE_REGIONS = 1 << 6;
const HAS_FREE_REGIONS = 1 << 5;
/// Is an error type reachable?
const HAS_TY_ERR = 1 << 7;
const HAS_PROJECTION = 1 << 8;
const HAS_TY_ERR = 1 << 6;
const HAS_PROJECTION = 1 << 7;
// FIXME: Rename this to the actual property since it's used for generators too
const HAS_TY_CLOSURE = 1 << 9;
const HAS_TY_CLOSURE = 1 << 8;
/// `true` if there are "names" of types and regions and so forth
/// that are local to a particular fn
const HAS_FREE_LOCAL_NAMES = 1 << 10;
const HAS_FREE_LOCAL_NAMES = 1 << 9;
/// Present if the type belongs in a local type context.
/// Only set for Infer other than Fresh.
const KEEP_IN_LOCAL_TCX = 1 << 11;
// Is there a projection that does not involve a bound region?
// Currently we can't normalize projections w/ bound regions.
const HAS_NORMALIZABLE_PROJECTION = 1 << 12;
const KEEP_IN_LOCAL_TCX = 1 << 10;
/// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate.
const HAS_RE_LATE_BOUND = 1 << 13;
const HAS_RE_LATE_BOUND = 1 << 11;
const HAS_TY_PLACEHOLDER = 1 << 14;
const HAS_TY_PLACEHOLDER = 1 << 12;
const HAS_CT_INFER = 1 << 15;
const HAS_CT_PLACEHOLDER = 1 << 16;
const HAS_CT_INFER = 1 << 13;
const HAS_CT_PLACEHOLDER = 1 << 14;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits;
/// Flags representing the nominal content of a type,
/// computed by FlagsComputation. If you add a new nominal
/// flag, it should be added here too.
const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_TY_INFER.bits |
TypeFlags::HAS_RE_INFER.bits |
TypeFlags::HAS_CT_INFER.bits |
TypeFlags::HAS_RE_PLACEHOLDER.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits |
TypeFlags::HAS_FREE_REGIONS.bits |
@ -479,6 +471,7 @@ bitflags! {
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits |
TypeFlags::HAS_TY_PLACEHOLDER.bits |
TypeFlags::HAS_CT_INFER.bits |
TypeFlags::HAS_CT_PLACEHOLDER.bits;
}
}
@ -1734,7 +1727,6 @@ impl<'tcx> ParamEnv<'tcx> {
if value.has_placeholders()
|| value.needs_infer()
|| value.has_param_types()
|| value.has_self_ty()
{
ParamEnvAnd {
param_env: self,

View file

@ -1141,13 +1141,6 @@ impl<'tcx> ParamTy {
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
tcx.mk_ty_param(self.index, self.name)
}
pub fn is_self(&self) -> bool {
// FIXME(#50125): Ignoring `Self` with `index != 0` might lead to weird behavior elsewhere,
// but this should only be possible when using `-Z continue-parse-after-error` like
// `compile-fail/issue-36638.rs`.
self.name.as_symbol() == kw::SelfUpper && self.index == 0
}
}
#[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable,
@ -1789,14 +1782,6 @@ impl<'tcx> TyS<'tcx> {
}
}
#[inline]
pub fn is_self(&self) -> bool {
match self.sty {
Param(ref p) => p.is_self(),
_ => false,
}
}
#[inline]
pub fn is_slice(&self) -> bool {
match self.sty {

View file

@ -333,15 +333,21 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
offset: Size,
) -> PlaceRef<'tcx, &'ll Value> {
assert_eq!(alloc.align, layout.align.abi);
let init = const_alloc_to_llvm(self, alloc);
let base_addr = self.static_addr_of(init, alloc.align, None);
let llty = self.type_ptr_to(layout.llvm_type(self));
let llval = if layout.size == Size::ZERO {
let llval = self.const_usize(alloc.align.bytes());
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
} else {
let init = const_alloc_to_llvm(self, alloc);
let base_addr = self.static_addr_of(init, alloc.align, None);
let llval = unsafe { llvm::LLVMConstInBoundsGEP(
self.const_bitcast(base_addr, self.type_i8p()),
&self.const_usize(offset.bytes()),
1,
)};
let llval = self.const_bitcast(llval, self.type_ptr_to(layout.llvm_type(self)));
let llval = unsafe { llvm::LLVMConstInBoundsGEP(
self.const_bitcast(base_addr, self.type_i8p()),
&self.const_usize(offset.bytes()),
1,
)};
self.const_bitcast(llval, llty)
};
PlaceRef::new_sized(llval, layout, alloc.align)
}

View file

@ -20,6 +20,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_metadata = { path = "../librustc_metadata" }
rustc_mir = { path = "../librustc_mir" }
rustc_plugin_impl = { path = "../librustc_plugin" }
rustc_save_analysis = { path = "../librustc_save_analysis" }
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
rustc_interface = { path = "../librustc_interface" }

View file

@ -22,6 +22,8 @@ extern crate libc;
#[macro_use]
extern crate log;
pub extern crate rustc_plugin_impl as plugin;
use pretty::{PpMode, UserIdentifiedItem};
//use rustc_resolve as resolve;

View file

@ -30,7 +30,7 @@ rustc_passes = { path = "../librustc_passes" }
rustc_typeck = { path = "../librustc_typeck" }
rustc_lint = { path = "../librustc_lint" }
rustc_errors = { path = "../librustc_errors" }
rustc_plugin = { path = "../librustc_plugin" }
rustc_plugin = { path = "../librustc_plugin", package = "rustc_plugin_impl" }
rustc_privacy = { path = "../librustc_privacy" }
rustc_resolve = { path = "../librustc_resolve" }
tempfile = "3.0.5"

View file

@ -352,7 +352,6 @@ impl Cursor<'_> {
loop {
match self.nth_char(0) {
'\n' => break,
'\r' if self.nth_char(1) == '\n' => break,
EOF_CHAR if self.is_eof() => break,
_ => {
self.bump();
@ -525,7 +524,6 @@ impl Cursor<'_> {
match self.nth_char(0) {
'/' if !first => break,
'\n' if self.nth_char(1) != '\'' => break,
'\r' if self.nth_char(1) == '\n' => break,
EOF_CHAR if self.is_eof() => break,
'\'' => {
self.bump();

View file

@ -128,11 +128,7 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result<ch
if first_char != '\\' {
return match first_char {
'\t' | '\n' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(if chars.clone().next() == Some('\n') {
EscapeError::EscapeOnlyChar
} else {
EscapeError::BareCarriageReturn
}),
'\r' => Err(EscapeError::BareCarriageReturn),
'\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar),
'"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar),
_ => {
@ -244,27 +240,15 @@ where
let unescaped_char = match first_char {
'\\' => {
let (second_char, third_char) = {
let mut chars = chars.clone();
(chars.next(), chars.next())
};
match (second_char, third_char) {
(Some('\n'), _) | (Some('\r'), Some('\n')) => {
let second_char = chars.clone().next();
match second_char {
Some('\n') => {
skip_ascii_whitespace(&mut chars);
continue;
}
_ => scan_escape(first_char, &mut chars, mode),
}
}
'\r' => {
let second_char = chars.clone().next();
if second_char == Some('\n') {
chars.next();
Ok('\n')
} else {
scan_escape(first_char, &mut chars, mode)
}
}
'\n' => Ok('\n'),
'\t' => Ok('\t'),
_ => scan_escape(first_char, &mut chars, mode),
@ -298,15 +282,11 @@ where
while let Some(curr) = chars.next() {
let start = initial_len - chars.as_str().len() - curr.len_utf8();
let result = match (curr, chars.clone().next()) {
('\r', Some('\n')) => {
chars.next();
Ok('\n')
},
('\r', _) => Err(EscapeError::BareCarriageReturnInRawString),
(c, _) if mode.is_bytes() && !c.is_ascii() =>
let result = match curr {
'\r' => Err(EscapeError::BareCarriageReturnInRawString),
c if mode.is_bytes() && !c.is_ascii() =>
Err(EscapeError::NonAsciiCharInByteString),
(c, _) => Ok(c),
c => Ok(c),
};
let end = initial_len - chars.as_str().len();

View file

@ -11,7 +11,6 @@ fn test_unescape_char_bad() {
check(r"\", EscapeError::LoneSlash);
check("\n", EscapeError::EscapeOnlyChar);
check("\r\n", EscapeError::EscapeOnlyChar);
check("\t", EscapeError::EscapeOnlyChar);
check("'", EscapeError::EscapeOnlyChar);
check("\r", EscapeError::BareCarriageReturn);
@ -31,6 +30,7 @@ fn test_unescape_char_bad() {
check(r"\v", EscapeError::InvalidEscape);
check(r"\💩", EscapeError::InvalidEscape);
check(r"\●", EscapeError::InvalidEscape);
check("\\\r", EscapeError::InvalidEscape);
check(r"\x", EscapeError::TooShortHexEscape);
check(r"\x0", EscapeError::TooShortHexEscape);
@ -116,10 +116,9 @@ fn test_unescape_str_good() {
check("foo", "foo");
check("", "");
check(" \t\n\r\n", " \t\n\n");
check(" \t\n", " \t\n");
check("hello \\\n world", "hello world");
check("hello \\\r\n world", "hello world");
check("thread's", "thread's")
}
@ -134,7 +133,6 @@ fn test_unescape_byte_bad() {
check(r"\", EscapeError::LoneSlash);
check("\n", EscapeError::EscapeOnlyChar);
check("\r\n", EscapeError::EscapeOnlyChar);
check("\t", EscapeError::EscapeOnlyChar);
check("'", EscapeError::EscapeOnlyChar);
check("\r", EscapeError::BareCarriageReturn);
@ -238,10 +236,9 @@ fn test_unescape_byte_str_good() {
check("foo", b"foo");
check("", b"");
check(" \t\n\r\n", b" \t\n\n");
check(" \t\n", b" \t\n");
check("hello \\\n world", b"hello world");
check("hello \\\r\n world", b"hello world");
check("thread's", b"thread's")
}
@ -253,7 +250,6 @@ fn test_unescape_raw_str() {
assert_eq!(unescaped, expected);
}
check("\r\n", &[(0..2, Ok('\n'))]);
check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]);
}
@ -266,7 +262,6 @@ fn test_unescape_raw_byte_str() {
assert_eq!(unescaped, expected);
}
check("\r\n", &[(0..2, Ok(byte_from_char('\n')))]);
check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]);
check(

View file

@ -1876,16 +1876,70 @@ declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) {
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
#[derive(Debug, Copy, Clone, PartialEq)]
enum InitKind { Zeroed, Uninit };
/// Information about why a type cannot be initialized this way.
/// Contains an error message and optionally a span to point at.
type InitError = (String, Option<Span>);
/// Test if this constant is all-0.
fn is_zero(expr: &hir::Expr) -> bool {
use hir::ExprKind::*;
use syntax::ast::LitKind::*;
match &expr.node {
Lit(lit) =>
if let Int(i, _) = lit.node {
i == 0
} else {
false
},
Tup(tup) =>
tup.iter().all(is_zero),
_ =>
false
}
}
/// Determine if this expression is a "dangerous initialization".
fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<InitKind> {
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
// `transmute` is inside an anonymous module (the `extern` block?);
// `Invalid` represents the empty string and matches that.
const TRANSMUTE_PATH: &[Symbol] =
&[sym::core, sym::intrinsics, kw::Invalid, sym::transmute];
if let hir::ExprKind::Call(ref path_expr, ref args) = expr.node {
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
if cx.match_def_path(def_id, ZEROED_PATH) {
return Some(InitKind::Zeroed);
}
if cx.match_def_path(def_id, UININIT_PATH) {
return Some(InitKind::Uninit);
}
if cx.match_def_path(def_id, TRANSMUTE_PATH) {
if is_zero(&args[0]) {
return Some(InitKind::Zeroed);
}
}
// FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and
// `MaybeUninit::uninit().assume_init()`.
}
}
None
}
/// Return `Some` only if we are sure this type does *not*
/// allow zero initialization.
fn ty_find_init_error<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<InitError> {
fn ty_find_init_error<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
init: InitKind,
) -> Option<InitError> {
use rustc::ty::TyKind::*;
match ty.sty {
// Primitive types that don't like 0 as a value.
@ -1893,8 +1947,30 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)),
FnPtr(..) => Some((format!("Function pointers must be non-null"), None)),
Never => Some((format!("The never type (`!`) has no valid value"), None)),
// Recurse for some compound types.
// Primitive types with other constraints.
Bool if init == InitKind::Uninit =>
Some((format!("Booleans must be `true` or `false`"), None)),
Char if init == InitKind::Uninit =>
Some((format!("Characters must be a valid unicode codepoint"), None)),
// Recurse and checks for some compound types.
Adt(adt_def, substs) if !adt_def.is_union() => {
// First check f this ADT has a layout attribute (like `NonNull` and friends).
use std::ops::Bound;
match tcx.layout_scalar_valid_range(adt_def.did) {
// We exploit here that `layout_scalar_valid_range` will never
// return `Bound::Excluded`. (And we have tests checking that we
// handle the attribute correctly.)
(Bound::Included(lo), _) if lo > 0 =>
return Some((format!("{} must be non-null", ty), None)),
(Bound::Included(_), _) | (_, Bound::Included(_))
if init == InitKind::Uninit =>
return Some((
format!("{} must be initialized inside its custom valid range", ty),
None,
)),
_ => {}
}
// Now, recurse.
match adt_def.variants.len() {
0 => Some((format!("0-variant enums have no valid value"), None)),
1 => {
@ -1905,6 +1981,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
ty_find_init_error(
tcx,
field.ty(tcx, substs),
init,
).map(|(mut msg, span)| if span.is_none() {
// Point to this field, should be helpful for figuring
// out where the source of the error is.
@ -1918,57 +1995,48 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
})
})
}
// Multi-variant enums are tricky: if all but one variant are
// uninhabited, we might actually do layout like for a single-variant
// enum, and then even leaving them uninitialized could be okay.
_ => None, // Conservative fallback for multi-variant enum.
}
}
Tuple(..) => {
// Proceed recursively, check all fields.
ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field))
ty.tuple_fields().find_map(|field| ty_find_init_error(tcx, field, init))
}
// FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
// FIXME: *Only for `mem::uninitialized`*, we could also warn for `bool`,
// `char`, and any multivariant enum.
// Conservative fallback.
_ => None,
}
}
if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
if cx.match_def_path(def_id, &ZEROED_PATH) ||
cx.match_def_path(def_id, &UININIT_PATH)
{
// This conjures an instance of a type out of nothing,
// using zeroed or uninitialized memory.
// We are extremely conservative with what we warn about.
let conjured_ty = cx.tables.expr_ty(expr);
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty) {
let mut err = cx.struct_span_lint(
INVALID_VALUE,
expr.span,
&format!(
"the type `{}` does not permit {}",
conjured_ty,
if cx.match_def_path(def_id, &ZEROED_PATH) {
"zero-initialization"
} else {
"being left uninitialized"
}
),
);
err.span_label(expr.span,
"this code causes undefined behavior when executed");
err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
if let Some(span) = span {
err.span_note(span, &msg);
} else {
err.note(&msg);
}
err.emit();
}
}
if let Some(init) = is_dangerous_init(cx, expr) {
// This conjures an instance of a type out of nothing,
// using zeroed or uninitialized memory.
// We are extremely conservative with what we warn about.
let conjured_ty = cx.tables.expr_ty(expr);
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
let mut err = cx.struct_span_lint(
INVALID_VALUE,
expr.span,
&format!(
"the type `{}` does not permit {}",
conjured_ty,
match init {
InitKind::Zeroed => "zero-initialization",
InitKind::Uninit => "being left uninitialized",
},
),
);
err.span_label(expr.span,
"this code causes undefined behavior when executed");
err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
if let Some(span) = span {
err.span_note(span, &msg);
} else {
err.note(&msg);
}
err.emit();
}
}
}

View file

@ -3,7 +3,7 @@
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc_plugin` respectively.
//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
//!
//! ## Note
//!

View file

@ -2,8 +2,7 @@
use crate::cstore::{self, CStore, CrateSource, MetadataBlob};
use crate::locator::{self, CratePaths};
use crate::decoder::proc_macro_def_path_table;
use crate::schema::CrateRoot;
use crate::schema::{CrateRoot};
use rustc_data_structures::sync::{Lrc, RwLock, Lock};
use rustc::hir::def_id::CrateNum;
@ -26,11 +25,11 @@ use std::{cmp, fs};
use syntax::ast;
use syntax::attr;
use syntax::ext::allocator::{global_allocator_spans, AllocatorKind};
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::symbol::{Symbol, sym};
use syntax::{span_err, span_fatal};
use syntax_pos::{Span, DUMMY_SP};
use log::{debug, info, log_enabled};
use proc_macro::bridge::client::ProcMacro;
pub struct Library {
pub dylib: Option<(PathBuf, PathKind)>,
@ -230,24 +229,13 @@ impl<'a> CrateLoader<'a> {
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
let proc_macros = crate_root.proc_macro_decls_static.map(|_| {
let raw_proc_macros = crate_root.proc_macro_data.map(|_| {
if self.sess.opts.debugging_opts.dual_proc_macros {
let host_lib = host_lib.unwrap();
self.load_derive_macros(
&host_lib.metadata.get_root(),
host_lib.dylib.map(|p| p.0),
span
)
let host_lib = host_lib.as_ref().unwrap();
self.dlsym_proc_macros(host_lib.dylib.as_ref().map(|p| p.0.clone()),
&host_lib.metadata.get_root(), span)
} else {
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
}
});
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
if let Some(proc_macros) = &proc_macros {
proc_macro_def_path_table(&crate_root, proc_macros)
} else {
crate_root.def_path_table.decode((&metadata, self.sess))
self.dlsym_proc_macros(dylib.clone().map(|p| p.0), &crate_root, span)
}
});
@ -260,13 +248,16 @@ impl<'a> CrateLoader<'a> {
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
.collect();
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
crate_root.def_path_table.decode((&metadata, self.sess))
});
let cmeta = cstore::CrateMetadata {
name: crate_root.name,
imported_name: ident,
extern_crate: Lock::new(None),
def_path_table: Lrc::new(def_path_table),
trait_impls,
proc_macros,
root: crate_root,
blob: metadata,
cnum_map,
@ -280,7 +271,10 @@ impl<'a> CrateLoader<'a> {
rlib,
rmeta,
},
private_dep
private_dep,
span,
host_lib,
raw_proc_macros
};
let cmeta = Lrc::new(cmeta);
@ -389,7 +383,7 @@ impl<'a> CrateLoader<'a> {
match result {
(LoadResult::Previous(cnum), None) => {
let data = self.cstore.get_crate_data(cnum);
if data.root.proc_macro_decls_static.is_some() {
if data.root.proc_macro_data.is_some() {
dep_kind = DepKind::UnexportedMacrosOnly;
}
data.dep_kind.with_lock(|data_dep_kind| {
@ -482,7 +476,7 @@ impl<'a> CrateLoader<'a> {
dep_kind: DepKind)
-> cstore::CrateNumMap {
debug!("resolving deps of external crate");
if crate_root.proc_macro_decls_static.is_some() {
if crate_root.proc_macro_data.is_some() {
return cstore::CrateNumMap::new();
}
@ -574,19 +568,13 @@ impl<'a> CrateLoader<'a> {
}
}
/// Loads custom derive macros.
///
/// Note that this is intentionally similar to how we load plugins today,
/// but also intentionally separate. Plugins are likely always going to be
/// implemented as dynamic libraries, but we have a possible future where
/// custom derive (and other macro-1.1 style features) are implemented via
/// executables and custom IPC.
fn load_derive_macros(&mut self, root: &CrateRoot<'_>, dylib: Option<PathBuf>, span: Span)
-> Vec<(ast::Name, Lrc<SyntaxExtension>)> {
use std::{env, mem};
fn dlsym_proc_macros(&self,
dylib: Option<PathBuf>,
root: &CrateRoot<'_>,
span: Span
) -> &'static [ProcMacro] {
use std::env;
use crate::dynamic_lib::DynamicLibrary;
use proc_macro::bridge::client::ProcMacro;
use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive};
let path = match dylib {
Some(dylib) => dylib,
@ -608,38 +596,11 @@ impl<'a> CrateLoader<'a> {
*(sym as *const &[ProcMacro])
};
let extensions = decls.iter().map(|&decl| {
let (name, kind, helper_attrs) = match decl {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let helper_attrs =
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(
trait_name,
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
client, attrs: helper_attrs.clone()
})),
helper_attrs,
)
}
ProcMacro::Attr { name, client } => (
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
),
ProcMacro::Bang { name, client } => (
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
)
};
(Symbol::intern(name), Lrc::new(SyntaxExtension {
helper_attrs,
..SyntaxExtension::default(kind, root.edition)
}))
}).collect();
// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
mem::forget(lib);
std::mem::forget(lib);
extensions
decls
}
/// Look for a plugin registrar. Returns library path, crate

View file

@ -28,6 +28,9 @@ pub use crate::cstore_impl::{provide, provide_extern};
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
pub use rustc_data_structures::sync::MetadataRef;
use crate::creader::Library;
use syntax_pos::Span;
use proc_macro::bridge::client::ProcMacro;
pub struct MetadataBlob(pub MetadataRef);
@ -82,11 +85,19 @@ pub struct CrateMetadata {
pub dep_kind: Lock<DepKind>,
pub source: CrateSource,
pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
/// Whether or not this crate should be consider a private dependency
/// for purposes of the 'exported_private_dependencies' lint
pub private_dep: bool
pub private_dep: bool,
pub host_lib: Option<Library>,
pub span: Span,
pub raw_proc_macros: Option<&'static [ProcMacro]>,
}
pub struct FullProcMacro {
pub name: ast::Name,
pub ext: Lrc<SyntaxExtension>
}
pub struct CStore {

View file

@ -426,8 +426,8 @@ impl cstore::CStore {
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
let data = self.get_crate_data(id.krate);
if let Some(ref proc_macros) = data.proc_macros {
return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
if data.is_proc_macro_crate() {
return LoadedMacro::ProcMacro(data.get_proc_macro(id.index, sess).ext);
} else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
@ -439,7 +439,8 @@ impl cstore::CStore {
}
let def = data.get_macro(id.index);
let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.imported_name);
let macro_full_name = data.def_path(id.index)
.to_string_friendly(|_| data.imported_name);
let source_name = FileName::Macros(macro_full_name);
let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);

View file

@ -1,16 +1,15 @@
// Decoding metadata from a single crate's metadata
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule, FullProcMacro};
use crate::schema::*;
use rustc_data_structures::sync::{Lrc, ReadGuard};
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions};
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc::hir;
use rustc::middle::cstore::LinkagePreference;
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::map::definitions::DefPathTable;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc::middle::lang_items;
use rustc::mir::{self, interpret};
@ -30,10 +29,11 @@ use syntax::attr;
use syntax::ast::{self, Ident};
use syntax::source_map;
use syntax::symbol::{Symbol, sym};
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::hygiene::ExpnId;
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
use syntax::ext::base::{MacroKind, SyntaxExtensionKind, SyntaxExtension};
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, symbol::{InternedString}};
use log::debug;
use proc_macro::bridge::client::ProcMacro;
use syntax::ext::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro};
pub struct DecodeContext<'a, 'tcx> {
opaque: opaque::Decoder<'a>,
@ -138,7 +138,7 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> LazySeq<T> {
pub fn decode<M: Metadata<'a, 'tcx>>(
self,
meta: M,
) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
let mut dcx = meta.decoder(self.position);
dcx.lazy_state = LazyState::NodeStart(self.position);
(0..self.len).map(move |_| T::decode(&mut dcx).unwrap())
@ -442,46 +442,16 @@ impl<'tcx> EntryKind<'tcx> {
}
}
/// Creates the "fake" DefPathTable for a given proc macro crate.
///
/// The DefPathTable is as follows:
///
/// CRATE_ROOT (DefIndex 0:0)
/// |- GlobalMetaDataKind data (DefIndex 1:0 .. DefIndex 1:N)
/// |- proc macro #0 (DefIndex 1:N)
/// |- proc macro #1 (DefIndex 1:N+1)
/// \- ...
crate fn proc_macro_def_path_table(crate_root: &CrateRoot<'_>,
proc_macros: &[(ast::Name, Lrc<SyntaxExtension>)])
-> DefPathTable
{
let mut definitions = Definitions::default();
let name = crate_root.name.as_str();
let disambiguator = crate_root.disambiguator;
debug!("creating proc macro def path table for {:?}/{:?}", name, disambiguator);
let crate_root = definitions.create_root_def(&name, disambiguator);
for (index, (name, _)) in proc_macros.iter().enumerate() {
let def_index = definitions.create_def_with_parent(
crate_root,
ast::DUMMY_NODE_ID,
DefPathData::MacroNs(name.as_interned_str()),
ExpnId::root(),
DUMMY_SP);
debug!("definition for {:?} is {:?}", name, def_index);
assert_eq!(def_index, DefIndex::from_proc_macro_index(index));
}
definitions.def_path_table().clone()
}
impl<'a, 'tcx> CrateMetadata {
pub fn is_proc_macro_crate(&self) -> bool {
self.root.proc_macro_decls_static.is_some()
}
fn is_proc_macro(&self, id: DefIndex) -> bool {
self.proc_macros.is_some() && id != CRATE_DEF_INDEX
self.is_proc_macro_crate() &&
self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
}
fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
assert!(!self.is_proc_macro(item_id));
self.root.entries_index.lookup(self.blob.raw_bytes(), item_id)
}
@ -504,13 +474,24 @@ impl<'a, 'tcx> CrateMetadata {
}
}
fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
// with items in 'raw_proc_macros'
let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap();
&self.raw_proc_macros.unwrap()[pos]
}
pub fn item_name(&self, item_index: DefIndex) -> Symbol {
self.def_key(item_index)
.disambiguated_data
.data
.get_opt_name()
.expect("no name in item_name")
.as_symbol()
if !self.is_proc_macro(item_index) {
self.def_key(item_index)
.disambiguated_data
.data
.get_opt_name()
.expect("no name in item_name")
.as_symbol()
} else {
Symbol::intern(self.raw_proc_macro(item_index).name())
}
}
pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
@ -518,15 +499,64 @@ impl<'a, 'tcx> CrateMetadata {
self.entry(index).kind.def_kind()
} else {
Some(DefKind::Macro(
self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind()
macro_kind(self.raw_proc_macro(index))
))
}
}
pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
match self.is_proc_macro(index) {
true => DUMMY_SP,
false => self.entry(index).span.decode((self, sess)),
self.entry(index).span.decode((self, sess))
}
pub fn get_proc_macro(&self, id: DefIndex, sess: &Session) -> FullProcMacro {
if sess.opts.debugging_opts.dual_proc_macros {
let host_lib = self.host_lib.as_ref().unwrap();
self.load_proc_macro(
&host_lib.metadata.get_root(),
id,
sess
)
} else {
self.load_proc_macro(&self.root, id, sess)
}
}
fn load_proc_macro(&self, root: &CrateRoot<'_>,
id: DefIndex,
sess: &Session)
-> FullProcMacro {
let raw_macro = self.raw_proc_macro(id);
let (name, kind, helper_attrs) = match *raw_macro {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let helper_attrs =
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(
trait_name,
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
client, attrs: helper_attrs.clone()
})),
helper_attrs,
)
}
ProcMacro::Attr { name, client } => (
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
),
ProcMacro::Bang { name, client } => (
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
)
};
let span = self.get_span(id, sess);
FullProcMacro {
name: Symbol::intern(name),
ext: Lrc::new(SyntaxExtension {
span,
helper_attrs,
..SyntaxExtension::default(kind, root.edition)
})
}
}
@ -723,7 +753,7 @@ impl<'a, 'tcx> CrateMetadata {
/// Iterates over the language items in the given crate.
pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
if self.proc_macros.is_some() {
if self.is_proc_macro_crate() {
// Proc macro crates do not export any lang-items to the target.
&[]
} else {
@ -738,18 +768,18 @@ impl<'a, 'tcx> CrateMetadata {
pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
where F: FnMut(def::Export<hir::HirId>)
{
if let Some(ref proc_macros) = self.proc_macros {
if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) {
/* If we are loading as a proc macro, we want to return the view of this crate
* as a proc macro crate, not as a Rust crate. See `proc_macro_def_path_table`
* for the DefPathTable we are corresponding to.
* as a proc macro crate.
*/
if id == CRATE_DEF_INDEX {
for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
for def_index in proc_macros_ids {
let raw_macro = self.raw_proc_macro(def_index);
let res = Res::Def(
DefKind::Macro(ext.macro_kind()),
self.local_def_id(DefIndex::from_proc_macro_index(id)),
DefKind::Macro(macro_kind(raw_macro)),
self.local_def_id(def_index),
);
let ident = Ident::with_dummy_span(name);
let ident = Ident::from_str(raw_macro.name());
callback(def::Export {
ident: ident,
res: res,
@ -960,11 +990,8 @@ impl<'a, 'tcx> CrateMetadata {
}
}
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
if self.is_proc_macro(node_id) {
return Lrc::new([]);
}
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
// The attributes for a tuple struct/variant are attached to the definition, not the ctor;
// we assume that someone passing in a tuple struct ctor is actually wanting to
// look at the definition
@ -1022,7 +1049,7 @@ impl<'a, 'tcx> CrateMetadata {
tcx: TyCtxt<'tcx>,
filter: Option<DefId>,
) -> &'tcx [DefId] {
if self.proc_macros.is_some() {
if self.is_proc_macro_crate() {
// proc-macro crates export no trait impls.
return &[]
}
@ -1066,7 +1093,7 @@ impl<'a, 'tcx> CrateMetadata {
pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
if self.proc_macros.is_some() {
if self.is_proc_macro_crate() {
// Proc macro crates do not have any *target* native libraries.
vec![]
} else {
@ -1075,7 +1102,7 @@ impl<'a, 'tcx> CrateMetadata {
}
pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
if self.proc_macros.is_some() {
if self.is_proc_macro_crate() {
// Proc macro crates do not have any *target* foreign modules.
&[]
} else {
@ -1098,7 +1125,7 @@ impl<'a, 'tcx> CrateMetadata {
}
pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
if self.proc_macros.is_some() {
if self.is_proc_macro_crate() {
// Proc macro crates do not depend on any target weak lang-items.
&[]
} else {
@ -1122,7 +1149,7 @@ impl<'a, 'tcx> CrateMetadata {
&self,
tcx: TyCtxt<'tcx>,
) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
if self.proc_macros.is_some() {
if self.is_proc_macro_crate() {
// If this crate is a custom derive crate, then we're not even going to
// link those in so we skip those crates.
vec![]
@ -1191,13 +1218,18 @@ impl<'a, 'tcx> CrateMetadata {
#[inline]
pub fn def_key(&self, index: DefIndex) -> DefKey {
self.def_path_table.def_key(index)
let mut key = self.def_path_table.def_key(index);
if self.is_proc_macro(index) {
let name = self.raw_proc_macro(index).name();
key.disambiguated_data.data = DefPathData::MacroNs(InternedString::intern(name));
}
key
}
// Returns the path leading to the thing with this `id`.
pub fn def_path(&self, id: DefIndex) -> DefPath {
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent))
DefPath::make(self.cnum, id, |parent| self.def_key(parent))
}
#[inline]
@ -1310,3 +1342,13 @@ impl<'a, 'tcx> CrateMetadata {
self.source_map_import_info.borrow()
}
}
// Cannot be implemented on 'ProcMacro', as libproc_macro
// does not depend on libsyntax
fn macro_kind(raw: &ProcMacro) -> MacroKind {
match raw {
ProcMacro::CustomDerive { .. } => MacroKind::Derive,
ProcMacro::Attr { .. } => MacroKind::Attr,
ProcMacro::Bang { .. } => MacroKind::Bang
}
}

View file

@ -30,6 +30,7 @@ use rustc_data_structures::sync::Lrc;
use std::u32;
use syntax::ast;
use syntax::attr;
use syntax::ext::proc_macro::is_proc_macro_attr;
use syntax::source_map::Spanned;
use syntax::symbol::{kw, sym, Ident};
use syntax_pos::{self, FileName, SourceFile, Span};
@ -383,6 +384,8 @@ impl<'tcx> EncodeContext<'tcx> {
}
fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
let mut i = self.position();
let crate_deps = self.encode_crate_deps();
@ -463,16 +466,23 @@ impl<'tcx> EncodeContext<'tcx> {
self.lazy_seq(interpret_alloc_index)
};
i = self.position();
let entries_index = self.entries_index.write_index(&mut self.opaque);
let entries_index_bytes = self.position() - i;
// Encode the proc macro data
i = self.position();
let proc_macro_data = self.encode_proc_macros();
let proc_macro_data_bytes = self.position() - i;
let attrs = tcx.hir().krate_attrs();
let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
let has_global_allocator = *tcx.sess.has_global_allocator.get();
let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false);
let root = self.lazy(&CrateRoot {
name: tcx.crate_name(LOCAL_CRATE),
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
@ -491,6 +501,7 @@ impl<'tcx> EncodeContext<'tcx> {
} else {
None
},
proc_macro_data,
proc_macro_stability: if is_proc_macro {
tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone())
} else {
@ -539,6 +550,7 @@ impl<'tcx> EncodeContext<'tcx> {
println!(" impl bytes: {}", impl_bytes);
println!(" exp. symbols bytes: {}", exported_symbols_bytes);
println!(" def-path table bytes: {}", def_path_table_bytes);
println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
println!(" item bytes: {}", item_bytes);
println!(" entries index bytes: {}", entries_index_bytes);
println!(" zero bytes: {}", zero_bytes);
@ -1470,6 +1482,22 @@ impl EncodeContext<'tcx> {
self.lazy_seq(foreign_modules.iter().cloned())
}
fn encode_proc_macros(&mut self) -> Option<LazySeq<DefIndex>> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
if is_proc_macro {
let proc_macros: Vec<_> = self.tcx.hir().krate().items.values().filter_map(|item| {
if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
Some(item.hir_id.owner)
} else {
None
}
}).collect();
Some(self.lazy_seq(proc_macros))
} else {
None
}
}
fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
let crates = self.tcx.crates();

View file

@ -716,7 +716,9 @@ impl<'a> Context<'a> {
let root = metadata.get_root();
if let Some(is_proc_macro) = self.is_proc_macro {
if root.proc_macro_decls_static.is_some() != is_proc_macro {
if root.proc_macro_data.is_some() != is_proc_macro {
info!("Rejecting via proc macro: expected {} got {}",
is_proc_macro, root.proc_macro_data.is_some());
return None;
}
}

View file

@ -182,6 +182,10 @@ pub struct CrateRoot<'tcx> {
pub entries_index: LazySeq<index::Index<'tcx>>,
/// The DefIndex's of any proc macros delcared by
/// this crate
pub proc_macro_data: Option<LazySeq<DefIndex>>,
pub compiler_builtins: bool,
pub needs_allocator: bool,
pub needs_panic_runtime: bool,

View file

@ -1190,7 +1190,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
Ok(string) => format!("move {}", string),
Ok(mut string) => {
if string.starts_with("async ") {
string.insert_str(6, "move ");
} else if string.starts_with("async|") {
string.insert_str(5, " move");
} else {
string.insert_str(0, "move ");
};
string
},
Err(_) => "move |<args>| <body>".to_string()
};

View file

@ -578,7 +578,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
})
}
hir::LifetimeName::Implicit => {
hir::LifetimeName::ImplicitObjectLifetimeDefault
| hir::LifetimeName::Implicit => {
// In this case, the user left off the lifetime; so
// they wrote something like:
//

View file

@ -657,6 +657,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
}
}
PatternKind::Or { ref pats } => {
for pat in pats {
self.visit_bindings(&pat, pattern_user_ty.clone(), f);
}
}
}
}
}

View file

@ -195,6 +195,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate.match_pairs.push(MatchPair::new(place, subpattern));
Ok(())
}
PatternKind::Or { .. } => {
Err(match_pair)
}
}
}
}

View file

@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatternKind::AscribeUserType { .. } |
PatternKind::Array { .. } |
PatternKind::Wild |
PatternKind::Or { .. } |
PatternKind::Binding { .. } |
PatternKind::Leaf { .. } |
PatternKind::Deref { .. } => {
@ -130,6 +131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatternKind::Slice { .. } |
PatternKind::Array { .. } |
PatternKind::Wild |
PatternKind::Or { .. } |
PatternKind::Binding { .. } |
PatternKind::AscribeUserType { .. } |
PatternKind::Leaf { .. } |

View file

@ -11,9 +11,8 @@ use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
use rustc::mir;
use rustc::ty::{self, TyCtxt};
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
use rustc::ty::subst::Subst;
use rustc::traits::Reveal;
use rustc_data_structures::fx::FxHashMap;
@ -415,7 +414,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
_bin_op: mir::BinOp,
_left: ImmTy<'tcx>,
_right: ImmTy<'tcx>,
) -> InterpResult<'tcx, (Scalar, bool)> {
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
Err(
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
)

View file

@ -1359,6 +1359,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
Some(vec![Slice(pat_len)])
}
}
PatternKind::Or { .. } => {
bug!("support for or-patterns has not been fully implemented yet.");
}
}
}
@ -1884,6 +1887,10 @@ fn specialize<'p, 'a: 'p, 'tcx>(
"unexpected ctor {:?} for slice pat", constructor)
}
}
PatternKind::Or { .. } => {
bug!("support for or-patterns has not been fully implemented yet.");
}
};
debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);

View file

@ -175,6 +175,12 @@ pub enum PatternKind<'tcx> {
slice: Option<Pattern<'tcx>>,
suffix: Vec<Pattern<'tcx>>,
},
/// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`.
Or {
pats: Vec<Pattern<'tcx>>,
},
}
#[derive(Copy, Clone, Debug, PartialEq)]
@ -186,6 +192,18 @@ pub struct PatternRange<'tcx> {
impl<'tcx> fmt::Display for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Printing lists is a chore.
let mut first = true;
let mut start_or_continue = |s| {
if first {
first = false;
""
} else {
s
}
};
let mut start_or_comma = || start_or_continue(", ");
match *self.kind {
PatternKind::Wild => write!(f, "_"),
PatternKind::AscribeUserType { ref subpattern, .. } =>
@ -224,9 +242,6 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
}
};
let mut first = true;
let mut start_or_continue = || if first { first = false; "" } else { ", " };
if let Some(variant) = variant {
write!(f, "{}", variant.ident)?;
@ -241,12 +256,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
continue;
}
let name = variant.fields[p.field.index()].ident;
write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
printed += 1;
}
if printed < variant.fields.len() {
write!(f, "{}..", start_or_continue())?;
write!(f, "{}..", start_or_comma())?;
}
return write!(f, " }}");
@ -257,7 +272,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
if num_fields != 0 || variant.is_none() {
write!(f, "(")?;
for i in 0..num_fields {
write!(f, "{}", start_or_continue())?;
write!(f, "{}", start_or_comma())?;
// Common case: the field is where we expect it.
if let Some(p) = subpatterns.get(i) {
@ -305,14 +320,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
let mut first = true;
let mut start_or_continue = || if first { first = false; "" } else { ", " };
write!(f, "[")?;
for p in prefix {
write!(f, "{}{}", start_or_continue(), p)?;
write!(f, "{}{}", start_or_comma(), p)?;
}
if let Some(ref slice) = *slice {
write!(f, "{}", start_or_continue())?;
write!(f, "{}", start_or_comma())?;
match *slice.kind {
PatternKind::Wild => {}
_ => write!(f, "{}", slice)?
@ -320,10 +333,16 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
write!(f, "..")?;
}
for p in suffix {
write!(f, "{}{}", start_or_continue(), p)?;
write!(f, "{}{}", start_or_comma(), p)?;
}
write!(f, "]")
}
PatternKind::Or { ref pats } => {
for pat in pats {
write!(f, "{}{}", start_or_continue(" | "), pat)?;
}
Ok(())
}
}
}
}
@ -655,6 +674,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
}
PatKind::Or(ref pats) => {
PatternKind::Or {
pats: pats.iter().map(|p| self.lower_pattern(p)).collect(),
}
}
};
Pattern {
@ -1436,6 +1461,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
slice: slice.fold_with(folder),
suffix: suffix.fold_with(folder)
},
PatternKind::Or { ref pats } => PatternKind::Or { pats: pats.fold_with(folder) },
}
}
}

View file

@ -1,4 +1,4 @@
use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::FloatTy;
@ -36,15 +36,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// The src operand does not matter, just its type
match src.layout.ty.sty {
ty::FnDef(def_id, substs) => {
// All reifications must be monomorphic, bail out otherwise.
if src.layout.ty.needs_subst() {
throw_inval!(TooGeneric);
}
if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
bug!("reifying a fn ptr that requires const arguments");
}
let instance = ty::Instance::resolve(
*self.tcx,
self.param_env,
def_id,
substs,
).ok_or_else(|| err_inval!(TooGeneric))?;
let instance = self.resolve(def_id, substs)?;
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
}
@ -67,7 +67,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// The src operand does not matter, just its type
match src.layout.ty.sty {
ty::Closure(def_id, substs) => {
let substs = self.subst_and_normalize_erasing_regions(substs)?;
// All reifications must be monomorphic, bail out otherwise.
if src.layout.ty.needs_subst() {
throw_inval!(TooGeneric);
}
let instance = ty::Instance::resolve_closure(
*self.tcx,
def_id,

View file

@ -9,7 +9,7 @@ use rustc::mir;
use rustc::ty::layout::{
self, Size, Align, HasDataLayout, LayoutOf, TyLayout
};
use rustc::ty::subst::{Subst, SubstsRef};
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::query::TyCtxtAt;
use rustc_data_structures::indexed_vec::IndexVec;
@ -291,41 +291,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
}
pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
substs: T,
) -> InterpResult<'tcx, T> {
match self.stack.last() {
Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions(
frame.instance.substs,
self.param_env,
&substs,
)),
None => if substs.needs_subst() {
throw_inval!(TooGeneric)
} else {
Ok(substs)
},
}
}
pub(super) fn resolve(
&self,
def_id: DefId,
substs: SubstsRef<'tcx>
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def_id, substs);
trace!("param_env: {:#?}", self.param_env);
let substs = self.subst_and_normalize_erasing_regions(substs)?;
trace!("substs: {:#?}", substs);
ty::Instance::resolve(
*self.tcx,
self.param_env,
def_id,
substs,
).ok_or_else(|| err_inval!(TooGeneric).into())
}
pub fn load_mir(
&self,
instance: ty::InstanceDef<'tcx>,
@ -349,34 +314,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
pub(super) fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
/// Call this on things you got out of the MIR (so it is as generic as the current
/// stack frame), to bring it into the proper environment for this interpreter.
pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
t: T,
) -> InterpResult<'tcx, T> {
match self.stack.last() {
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?),
None => if t.needs_subst() {
throw_inval!(TooGeneric)
} else {
Ok(t)
},
}
value: T,
) -> T {
self.tcx.subst_and_normalize_erasing_regions(
self.frame().instance.substs,
self.param_env,
&value,
)
}
fn monomorphize_with_substs<T: TypeFoldable<'tcx> + Subst<'tcx>>(
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
pub(super) fn resolve(
&self,
t: T,
def_id: DefId,
substs: SubstsRef<'tcx>
) -> InterpResult<'tcx, T> {
// miri doesn't care about lifetimes, and will choke on some crazy ones
// let's simply get rid of them
let substituted = t.subst(*self.tcx, substs);
if substituted.needs_subst() {
throw_inval!(TooGeneric)
}
Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted))
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def_id, substs);
trace!("param_env: {:#?}", self.param_env);
trace!("substs: {:#?}", substs);
ty::Instance::resolve(
*self.tcx,
self.param_env,
def_id,
substs,
).ok_or_else(|| err_inval!(TooGeneric).into())
}
pub fn layout_of_local(
@ -391,7 +356,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
None => {
let layout = crate::interpret::operand::from_known_layout(layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?;
let local_ty = self.tcx.subst_and_normalize_erasing_regions(
frame.instance.substs,
self.param_env,
&local_ty,
);
self.layout_of(local_ty)
})?;
if let Some(state) = frame.locals.get(local) {

View file

@ -137,7 +137,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let l = self.read_immediate(args[0])?;
let r = self.read_immediate(args[1])?;
let is_add = intrinsic_name == "saturating_add";
let (val, overflowed) = self.binary_op(if is_add {
let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
BinOp::Add
} else {
BinOp::Sub
@ -184,7 +184,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
"unchecked_shr" => BinOp::Shr,
_ => bug!("Already checked for int ops")
};
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
if overflowed {
let layout = self.layout_of(substs.type_at(0))?;
let r_val = r.to_scalar()?.to_bits(layout.size)?;

View file

@ -7,7 +7,7 @@ use std::hash::Hash;
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::{self, TyCtxt};
use rustc::ty::{self, Ty, TyCtxt};
use super::{
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
@ -176,7 +176,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
bin_op: mir::BinOp,
left: ImmTy<'tcx, Self::PointerTag>,
right: ImmTy<'tcx, Self::PointerTag>,
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
/// Heap allocations via the `box` keyword.
fn box_alloc(

View file

@ -297,7 +297,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
/// and `align`. On success, returns `None` for zero-sized accesses (where
/// nothing else is left to do) and a `Pointer` to use for the actual access otherwise.
/// Crucially, if the input is a `Pointer`, we will test it for liveness
/// *even of* the size is 0.
/// *even if* the size is 0.
///
/// Everyone accessing memory based on a `Scalar` should use this method to get the
/// `Pointer` they need. And even if you already have a `Pointer`, call this method

View file

@ -108,7 +108,7 @@ impl<'tcx, Tag> Immediate<Tag> {
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
pub struct ImmTy<'tcx, Tag=()> {
pub imm: Immediate<Tag>,
pub(crate) imm: Immediate<Tag>,
pub layout: TyLayout<'tcx>,
}
@ -155,7 +155,7 @@ impl<Tag> Operand<Tag> {
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct OpTy<'tcx, Tag=()> {
op: Operand<Tag>,
op: Operand<Tag>, // Keep this private, it helps enforce invariants
pub layout: TyLayout<'tcx>,
}
@ -187,13 +187,22 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
}
}
impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
{
impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> {
#[inline]
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
ImmTy { imm: val.into(), layout }
}
#[inline]
pub fn from_uint(i: impl Into<u128>, layout: TyLayout<'tcx>) -> Self {
Self::from_scalar(Scalar::from_uint(i, layout.size), layout)
}
#[inline]
pub fn from_int(i: impl Into<i128>, layout: TyLayout<'tcx>) -> Self {
Self::from_scalar(Scalar::from_int(i, layout.size), layout)
}
#[inline]
pub fn to_bits(self) -> InterpResult<'tcx, u128> {
self.to_scalar()?.to_bits(self.layout.size)
@ -513,7 +522,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Move(ref place) =>
self.eval_place_to_op(place, layout)?,
Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?,
Constant(ref constant) => {
let val = self.subst_from_frame_and_normalize_erasing_regions(constant.literal);
self.eval_const_to_op(val, layout)?
}
};
trace!("{:?}: {:?}", mir_op, *op);
Ok(op)
@ -531,6 +543,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Used when the miri-engine runs into a constant and for extracting information from constants
// in patterns via the `const_eval` module
/// The `val` and `layout` are assumed to already be in our interpreter
/// "universe" (param_env).
crate fn eval_const_to_op(
&self,
val: &'tcx ty::Const<'tcx>,
@ -543,7 +557,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Early-return cases.
match val.val {
ConstValue::Param(_) =>
// FIXME(oli-obk): try to monomorphize
throw_inval!(TooGeneric),
ConstValue::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
@ -556,7 +569,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
// Other cases need layout.
let layout = from_known_layout(layout, || {
self.layout_of(self.monomorphize(val.ty)?)
self.layout_of(val.ty)
})?;
let op = match val.val {
ConstValue::ByRef { alloc, offset } => {

View file

@ -1,5 +1,5 @@
use rustc::mir;
use rustc::ty::{self, layout::TyLayout};
use rustc::ty::{self, Ty, layout::{TyLayout, LayoutOf}};
use syntax::ast::FloatTy;
use rustc_apfloat::Float;
use rustc::mir::interpret::{InterpResult, Scalar};
@ -17,7 +17,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
right: ImmTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let (val, overflowed) = self.binary_op(op, left, right)?;
let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
debug_assert_eq!(
self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
dest.layout.ty,
"type mismatch for result of {:?}", op,
);
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
self.write_immediate(val, dest)
}
@ -31,7 +36,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
right: ImmTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let (val, _overflowed) = self.binary_op(op, left, right)?;
let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
self.write_scalar(val, dest)
}
}
@ -42,7 +48,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
bin_op: mir::BinOp,
l: char,
r: char,
) -> (Scalar<M::PointerTag>, bool) {
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
use rustc::mir::BinOp::*;
let res = match bin_op {
@ -54,7 +60,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ge => l >= r,
_ => bug!("Invalid operation on char: {:?}", bin_op),
};
return (Scalar::from_bool(res), false);
return (Scalar::from_bool(res), false, self.tcx.types.bool);
}
fn binary_bool_op(
@ -62,7 +68,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
bin_op: mir::BinOp,
l: bool,
r: bool,
) -> (Scalar<M::PointerTag>, bool) {
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
use rustc::mir::BinOp::*;
let res = match bin_op {
@ -77,32 +83,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
BitXor => l ^ r,
_ => bug!("Invalid operation on bool: {:?}", bin_op),
};
return (Scalar::from_bool(res), false);
return (Scalar::from_bool(res), false, self.tcx.types.bool);
}
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
&self,
bin_op: mir::BinOp,
ty: Ty<'tcx>,
l: F,
r: F,
) -> (Scalar<M::PointerTag>, bool) {
) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
use rustc::mir::BinOp::*;
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
Ne => Scalar::from_bool(l != r),
Lt => Scalar::from_bool(l < r),
Le => Scalar::from_bool(l <= r),
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
Add => (l + r).value.into(),
Sub => (l - r).value.into(),
Mul => (l * r).value.into(),
Div => (l / r).value.into(),
Rem => (l % r).value.into(),
let (val, ty) = match bin_op {
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
Add => ((l + r).value.into(), ty),
Sub => ((l - r).value.into(), ty),
Mul => ((l * r).value.into(), ty),
Div => ((l / r).value.into(), ty),
Rem => ((l % r).value.into(), ty),
_ => bug!("invalid float op: `{:?}`", bin_op),
};
return (val, false);
return (val, false, ty);
}
fn binary_int_op(
@ -113,7 +120,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
left_layout: TyLayout<'tcx>,
r: u128,
right_layout: TyLayout<'tcx>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
use rustc::mir::BinOp::*;
// Shift ops can have an RHS with a different numeric type.
@ -142,7 +149,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
};
let truncated = self.truncate(result, left_layout);
return Ok((Scalar::from_uint(truncated, size), oflo));
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
}
// For the remaining ops, the types must be the same on both sides
@ -167,7 +174,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
if let Some(op) = op {
let l = self.sign_extend(l, left_layout) as i128;
let r = self.sign_extend(r, right_layout) as i128;
return Ok((Scalar::from_bool(op(&l, &r)), false));
return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
Div if r == 0 => throw_panic!(DivisionByZero),
@ -187,7 +194,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Rem | Div => {
// int_min / -1
if r == -1 && l == (1 << (size.bits() - 1)) {
return Ok((Scalar::from_uint(l, size), true));
return Ok((Scalar::from_uint(l, size), true, left_layout.ty));
}
},
_ => {},
@ -202,25 +209,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// this may be out-of-bounds for the result type, so we have to truncate ourselves
let result = result as u128;
let truncated = self.truncate(result, left_layout);
return Ok((Scalar::from_uint(truncated, size), oflo));
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
}
}
let size = left_layout.size;
// only ints left
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
Ne => Scalar::from_bool(l != r),
let (val, ty) = match bin_op {
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
Lt => Scalar::from_bool(l < r),
Le => Scalar::from_bool(l <= r),
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
BitOr => Scalar::from_uint(l | r, size),
BitAnd => Scalar::from_uint(l & r, size),
BitXor => Scalar::from_uint(l ^ r, size),
BitOr => (Scalar::from_uint(l | r, size), left_layout.ty),
BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty),
BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty),
Add | Sub | Mul | Rem | Div => {
debug_assert!(!left_layout.abi.is_signed());
@ -236,7 +242,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
let (result, oflo) = op(l, r);
let truncated = self.truncate(result, left_layout);
return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
return Ok((
Scalar::from_uint(truncated, size),
oflo || truncated != result,
left_layout.ty,
));
}
_ => {
@ -250,17 +260,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
};
Ok((val, false))
Ok((val, false, ty))
}
/// Returns the result of the specified operation and whether it overflowed.
#[inline]
pub fn binary_op(
/// Returns the result of the specified operation, whether it overflowed, and
/// the result type.
pub fn overflowing_binary_op(
&self,
bin_op: mir::BinOp,
left: ImmTy<'tcx, M::PointerTag>,
right: ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, *left, left.layout.ty, *right, right.layout.ty);
@ -279,11 +289,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
ty::Float(fty) => {
assert_eq!(left.layout.ty, right.layout.ty);
let ty = left.layout.ty;
let left = left.to_scalar()?;
let right = right.to_scalar()?;
Ok(match fty {
FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?),
FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?),
FloatTy::F32 =>
self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?),
FloatTy::F64 =>
self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?),
})
}
_ if left.layout.ty.is_integral() => {
@ -312,11 +325,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
/// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
#[inline]
pub fn binary_op(
&self,
bin_op: mir::BinOp,
left: ImmTy<'tcx, M::PointerTag>,
right: ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
}
pub fn unary_op(
&self,
un_op: mir::UnOp,
val: ImmTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
use rustc::mir::UnOp::*;
let layout = val.layout;
@ -330,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Not => !val,
_ => bug!("Invalid bool op {:?}", un_op)
};
Ok(Scalar::from_bool(res))
Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?))
}
ty::Float(fty) => {
let res = match (un_op, fty) {
@ -338,7 +363,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
_ => bug!("Invalid float op {:?}", un_op)
};
Ok(res)
Ok(ImmTy::from_scalar(res, layout))
}
_ => {
assert!(layout.ty.is_integral());
@ -351,7 +376,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
};
// res needs tuncating
Ok(Scalar::from_uint(self.truncate(res, layout), layout.size))
Ok(ImmTy::from_uint(self.truncate(res, layout), layout))
}
}
}

View file

@ -45,7 +45,7 @@ pub enum Place<Tag=(), Id=AllocId> {
#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx, Tag=()> {
place: Place<Tag>,
place: Place<Tag>, // Keep this private, it helps enforce invariants
pub layout: TyLayout<'tcx>,
}
@ -640,8 +640,11 @@ where
// their layout on return.
PlaceTy {
place: *return_place,
layout: self
.layout_of(self.monomorphize(self.frame().body.return_ty())?)?,
layout: self.layout_of(
self.subst_from_frame_and_normalize_erasing_regions(
self.frame().body.return_ty()
)
)?,
}
}
None => throw_unsup!(InvalidNullPointerUsage),

View file

@ -177,7 +177,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// The operand always has the same type as the result.
let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
let val = self.unary_op(un_op, val)?;
self.write_scalar(val, dest)?;
assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
self.write_immediate(*val, dest)?;
}
Aggregate(ref kind, ref operands) => {
@ -253,7 +254,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
NullaryOp(mir::NullOp::SizeOf, ty) => {
let ty = self.monomorphize(ty)?;
let ty = self.subst_from_frame_and_normalize_erasing_regions(ty);
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(),
"SizeOf nullary MIR operator called for unsized type");

View file

@ -7,7 +7,7 @@ use syntax::source_map::Span;
use rustc_target::spec::abi::Abi;
use super::{
InterpResult, PointerArithmetic, Scalar,
InterpResult, PointerArithmetic,
InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
};
@ -50,11 +50,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
for (index, &const_int) in values.iter().enumerate() {
// Compare using binary_op, to also support pointer values
let const_int = Scalar::from_uint(const_int, discr.layout.size);
let (res, _) = self.binary_op(mir::BinOp::Eq,
let res = self.overflowing_binary_op(mir::BinOp::Eq,
discr,
ImmTy::from_scalar(const_int, discr.layout),
)?;
ImmTy::from_uint(const_int, discr.layout),
)?.0;
if res.to_bool()? {
target_block = targets[index];
break;

View file

@ -1,4 +1,4 @@
use rustc::ty::{self, Ty, Instance};
use rustc::ty::{self, Ty, Instance, TypeFoldable};
use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
@ -20,6 +20,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
// All vtables must be monomorphic, bail out otherwise.
if ty.needs_subst() || poly_trait_ref.needs_subst() {
throw_inval!(TooGeneric);
}
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
// This means we guarantee that there are no duplicate vtables, we will
// always use the same vtable for the same (Type, Trait) combination.
@ -77,7 +82,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
for (i, method) in methods.iter().enumerate() {
if let Some((def_id, substs)) = *method {
// resolve for vtable: insert shims where needed
let substs = self.subst_and_normalize_erasing_regions(substs)?;
let instance = ty::Instance::resolve_for_vtable(
*self.tcx,
self.param_env,

View file

@ -708,7 +708,7 @@ fn build_call_shim<'tcx>(
Adjustment::DerefMove => {
// fn(Self, ...) -> fn(*mut Self, ...)
let arg_ty = local_decls[rcvr_arg].ty;
assert!(arg_ty.is_self());
debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param);
local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty);
Operand::Move(rcvr_l.deref())

View file

@ -19,7 +19,7 @@ use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::subst::InternalSubsts;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::layout::{
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout,
};
use crate::interpret::{
@ -396,17 +396,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
if let ty::Slice(_) = mplace.layout.ty.sty {
let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
Some(ImmTy {
imm: Immediate::Scalar(
Scalar::from_uint(
len,
Size::from_bits(
self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64
)
).into(),
),
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
}.into())
Some(ImmTy::from_uint(
len,
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
).into())
} else {
trace!("not slice: {:?}", mplace.layout.ty.sty);
None
@ -414,12 +407,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
},
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
ImmTy {
imm: Immediate::Scalar(
Scalar::from_uint(n, self.tcx.data_layout.pointer_size).into()
),
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
}.into()
ImmTy::from_uint(
n,
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
).into()
))
}
Rvalue::UnaryOp(op, ref arg) => {
@ -452,11 +443,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
// Now run the actual operation.
this.ecx.unary_op(op, prim)
})?;
let res = ImmTy {
imm: Immediate::Scalar(val.into()),
layout: place_layout,
};
Some(res.into())
Some(val.into())
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
@ -510,8 +497,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
this.ecx.read_immediate(left)
})?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
let (val, overflow) = self.use_ecx(source_info, |this| {
this.ecx.binary_op(op, l, r)
let (val, overflow, _ty) = self.use_ecx(source_info, |this| {
this.ecx.overflowing_binary_op(op, l, r)
})?;
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
Immediate::ScalarPair(

View file

@ -7,7 +7,7 @@ use rustc::ty::TyCtxt;
use rustc::hir::def_id::DefId;
use rustc::hir::map::Map;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::{self, Node, Destination};
use rustc::hir::{self, Node, Destination, GeneratorMovability};
use syntax::struct_span_err;
use syntax_pos::Span;
use errors::Applicability;
@ -17,6 +17,7 @@ enum Context {
Normal,
Loop(hir::LoopSource),
Closure,
AsyncClosure,
LabeledBlock,
AnonConst,
}
@ -57,9 +58,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
hir::ExprKind::Loop(ref b, _, source) => {
self.with_context(Loop(source), |v| v.visit_block(&b));
}
hir::ExprKind::Closure(_, ref function_decl, b, _, _) => {
hir::ExprKind::Closure(_, ref function_decl, b, _, movability) => {
let cx = if let Some(GeneratorMovability::Static) = movability {
AsyncClosure
} else {
Closure
};
self.visit_fn_decl(&function_decl);
self.with_context(Closure, |v| v.visit_nested_body(b));
self.with_context(cx, |v| v.visit_nested_body(b));
}
hir::ExprKind::Block(ref b, Some(_label)) => {
self.with_context(LabeledBlock, |v| v.visit_block(&b));
@ -171,6 +177,11 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
.span_label(span, "cannot break inside of a closure")
.emit();
}
AsyncClosure => {
struct_span_err!(self.sess, span, E0267, "`{}` inside of an async block", name)
.span_label(span, "cannot break inside of an async block")
.emit();
}
Normal | AnonConst => {
struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
.span_label(span, "cannot break outside of a loop")

View file

@ -1,12 +1,12 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_plugin"
name = "rustc_plugin_impl"
version = "0.0.0"
build = false
edition = "2018"
[lib]
name = "rustc_plugin"
name = "rustc_plugin_impl"
path = "lib.rs"
doctest = false

View file

@ -0,0 +1,14 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_plugin"
version = "0.0.0"
build = false
edition = "2018"
[lib]
name = "rustc_plugin"
path = "lib.rs"
doctest = false
[dependencies]
rustc_plugin_impl = { path = ".." }

View file

@ -0,0 +1,8 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(staged_api)]
#![unstable(feature = "rustc_plugin", issue = "29597")]
#![rustc_deprecated(since = "1.38.0", reason = "\
import this through `rustc_driver::plugin` instead to make TLS work correctly. \
See https://github.com/rust-lang/rust/issues/62717")]
pub use rustc_plugin_impl::*;

View file

@ -16,12 +16,11 @@
//! #![feature(plugin_registrar)]
//! #![feature(rustc_private)]
//!
//! extern crate rustc_plugin;
//! extern crate rustc_driver;
//! extern crate syntax;
//! extern crate syntax_pos;
//!
//! use rustc_plugin::Registry;
//! use rustc_driver::plugin::Registry;
//! use syntax::ext::base::{ExtCtxt, MacResult};
//! use syntax_pos::Span;
//! use syntax::tokenstream::TokenTree;

View file

@ -160,12 +160,25 @@ impl<'a> Resolver<'a> {
Some(ext)
}
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
crate fn build_reduced_graph(
&mut self, fragment: &AstFragment, parent_scope: ParentScope<'a>
&mut self,
fragment: &AstFragment,
extra_placeholders: &[NodeId],
parent_scope: ParentScope<'a>,
) -> LegacyScope<'a> {
fragment.visit_with(&mut DefCollector::new(&mut self.definitions, parent_scope.expansion));
let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion);
fragment.visit_with(&mut def_collector);
for placeholder in extra_placeholders {
def_collector.visit_macro_invoc(*placeholder);
}
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
fragment.visit_with(&mut visitor);
for placeholder in extra_placeholders {
visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder);
}
visitor.parent_scope.legacy
}
@ -871,7 +884,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<ast::NodeId>) {
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
let parent = self.parent_scope.module;
let Export { ident, res, vis, span } = child;
// FIXME: We shouldn't create the gensym here, it should come from metadata,
@ -1060,10 +1073,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
false
}
fn visit_invoc(&mut self, id: ast::NodeId) -> LegacyScope<'a> {
fn visit_invoc(&mut self, id: NodeId) -> LegacyScope<'a> {
let invoc_id = id.placeholder_to_expn_id();
self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");

View file

@ -448,7 +448,7 @@ pub struct ModuleData<'a> {
populate_on_access: Cell<bool>,
// Macro invocations that can expand into items in this module.
unresolved_invocations: RefCell<FxHashSet<ExpnId>>,
unexpanded_invocations: RefCell<FxHashSet<ExpnId>>,
no_implicit_prelude: bool,
@ -478,7 +478,7 @@ impl<'a> ModuleData<'a> {
normal_ancestor_id,
lazy_resolutions: Default::default(),
populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
unresolved_invocations: Default::default(),
unexpanded_invocations: Default::default(),
no_implicit_prelude: false,
glob_importers: RefCell::new(Vec::new()),
globs: RefCell::new(Vec::new()),

View file

@ -10,7 +10,7 @@ use crate::resolve_imports::ImportResolver;
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
use rustc::middle::stability;
use rustc::{ty, lint, span_bug};
use syntax::ast::{self, Ident};
use syntax::ast::{self, NodeId, Ident};
use syntax::attr::StabilityLevel;
use syntax::edition::Edition;
use syntax::ext::base::{self, Indeterminate, SpecialDerives};
@ -26,7 +26,7 @@ use syntax_pos::{Span, DUMMY_SP};
use std::{mem, ptr};
use rustc_data_structures::sync::Lrc;
type Res = def::Res<ast::NodeId>;
type Res = def::Res<NodeId>;
/// Binding produced by a `macro_rules` item.
/// Not modularized, can shadow previous legacy bindings, etc.
@ -91,11 +91,11 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
}
impl<'a> base::Resolver for Resolver<'a> {
fn next_node_id(&mut self) -> ast::NodeId {
fn next_node_id(&mut self) -> NodeId {
self.session.next_node_id()
}
fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId {
fn get_module_scope(&mut self, id: NodeId) -> ExpnId {
let expn_id = ExpnId::fresh(Some(ExpnData::default(
ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
)));
@ -115,23 +115,18 @@ impl<'a> base::Resolver for Resolver<'a> {
});
}
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
fn visit_ast_fragment_with_placeholders(
&mut self, expansion: ExpnId, fragment: &AstFragment, derives: &[ExpnId]
&mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
) {
// Fill in some data for derives if the fragment is from a derive container.
// Integrate the new AST fragment into all the definition and module structures.
// We are inside the `expansion` now, but other parent scope components are still the same.
let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
let parent_def = self.definitions.invocation_parent(expansion);
self.invocation_parent_scopes.extend(derives.iter().map(|&derive| (derive, parent_scope)));
for &derive_invoc_id in derives {
self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
}
parent_scope.module.unresolved_invocations.borrow_mut().remove(&expansion);
parent_scope.module.unresolved_invocations.borrow_mut().extend(derives);
// Integrate the new AST fragment into all the definition and module structures.
let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope);
let output_legacy_scope =
self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
self.output_legacy_scopes.insert(expansion, output_legacy_scope);
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
}
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
@ -485,7 +480,7 @@ impl<'a> Resolver<'a> {
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unresolved_invocations.borrow().is_empty()
this.graph_root.unexpanded_invocations.borrow().is_empty()
))
}
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
@ -508,7 +503,7 @@ impl<'a> Resolver<'a> {
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unresolved_invocations.borrow().is_empty()
this.graph_root.unexpanded_invocations.borrow().is_empty()
)),
}
Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {

View file

@ -202,7 +202,7 @@ impl<'a> Resolver<'a> {
Err((Determined, Weak::No))
} else if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
Ok(binding)
} else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
// Macro-expanded `extern crate` items can add names to extern prelude.
Err((Undetermined, Weak::No))
} else {
@ -348,7 +348,7 @@ impl<'a> Resolver<'a> {
// progress, we have to ignore those potential unresolved invocations from other modules
// and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
// shadowing is enabled, see `macro_expanded_macro_export_errors`).
let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty();
let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
if let Some(binding) = resolution.binding {
if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
return check_usable(self, binding);

View file

@ -635,8 +635,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
});
let default_needs_object_self = |param: &ty::GenericParamDef| {
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
if is_object && has_default {
if tcx.at(span).type_of(param.def_id).has_self_ty() {
if is_object && has_default && has_self {
let self_param = tcx.types.self_param;
if tcx.at(span).type_of(param.def_id).walk().any(|ty| ty == self_param) {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;
@ -2030,7 +2031,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generics(&path.segments);
tcx.mk_self_type()
tcx.types.self_param
}
Res::SelfTy(_, Some(def_id)) => {
// `Self` in impl (we know the concrete type).

View file

@ -53,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let is_non_ref_pat = match pat.node {
PatKind::Struct(..) |
PatKind::TupleStruct(..) |
PatKind::Or(_) |
PatKind::Tuple(..) |
PatKind::Box(_) |
PatKind::Range(..) |
@ -309,6 +310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Struct(ref qpath, ref fields, etc) => {
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span)
}
PatKind::Or(ref pats) => {
let expected_ty = self.structurally_resolved_type(pat.span, expected);
for pat in pats {
self.check_pat_walk(pat, expected, def_bm, discrim_span);
}
expected_ty
}
PatKind::Tuple(ref elements, ddpos) => {
let mut expected_len = elements.len();
if ddpos.is_some() {

View file

@ -518,7 +518,7 @@ fn compare_self_type<'tcx>(
let self_string = |method: &ty::AssocItem| {
let untransformed_self_ty = match method.container {
ty::ImplContainer(_) => impl_trait_ref.self_ty(),
ty::TraitContainer(_) => tcx.mk_self_type()
ty::TraitContainer(_) => tcx.types.self_param
};
let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
let param_env = ty::ParamEnv::reveal_all();

View file

@ -191,7 +191,7 @@ fn check_associated_item(
let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id));
let (mut implied_bounds, self_ty) = match item.container {
ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
ty::TraitContainer(_) => (vec![], fcx.tcx.types.self_param),
ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
fcx.tcx.type_of(def_id))
};

View file

@ -716,7 +716,7 @@ fn super_predicates_of(
let icx = ItemCtxt::new(tcx, trait_def_id);
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
let self_param_ty = tcx.mk_self_type();
let self_param_ty = tcx.types.self_param;
let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No,
item.span);
@ -900,6 +900,20 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
let parent_id = tcx.hir().get_parent_item(hir_id);
Some(tcx.hir().local_def_id(parent_id))
}
// FIXME(#43408) enable this in all cases when we get lazy normalization.
Node::AnonConst(&anon_const) => {
// HACK(eddyb) this provides the correct generics when the workaround
// for a const parameter `AnonConst` is being used elsewhere, as then
// there won't be the kind of cyclic dependency blocking #43408.
let expr = &tcx.hir().body(anon_const.body).value;
let icx = ItemCtxt::new(tcx, def_id);
if AstConv::const_param_def_id(&icx, expr).is_some() {
let parent_id = tcx.hir().get_parent_item(hir_id);
Some(tcx.hir().local_def_id(parent_id))
} else {
None
}
}
Node::Expr(&hir::Expr {
node: hir::ExprKind::Closure(..),
..
@ -1014,13 +1028,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
synthetic,
..
} => {
if param.name.ident().name == kw::SelfUpper {
span_bug!(
param.span,
"`Self` should not be the name of a regular parameter"
);
}
if !allow_defaults && default.is_some() {
if !tcx.features().default_type_parameter_fallback {
tcx.lint_hir(
@ -1044,13 +1051,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
}
}
GenericParamKind::Const { .. } => {
if param.name.ident().name == kw::SelfUpper {
span_bug!(
param.span,
"`Self` should not be the name of a regular parameter",
);
}
ty::GenericParamDefKind::Const
}
_ => return None,
@ -1567,7 +1567,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
&format!(
"defining opaque type use restricts opaque \
type by using the generic parameter `{}` twice",
p.name
p,
),
);
return;

View file

@ -3,7 +3,6 @@ use rustc::hir::def_id::DefId;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::subst::{Kind, Subst, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::fold::TypeFoldable;
use rustc::util::nodemap::FxHashMap;
use super::explicit::ExplicitPredicatesMap;
@ -178,11 +177,11 @@ fn insert_required_predicates_to_be_wf<'tcx>(
// let _: () = substs.region_at(0);
check_explicit_predicates(
tcx,
&def.did,
def.did,
substs,
required_predicates,
explicit_map,
IgnoreSelfTy(false),
None,
);
}
@ -208,11 +207,11 @@ fn insert_required_predicates_to_be_wf<'tcx>(
.substs;
check_explicit_predicates(
tcx,
&ex_trait_ref.skip_binder().def_id,
ex_trait_ref.skip_binder().def_id,
substs,
required_predicates,
explicit_map,
IgnoreSelfTy(true),
Some(tcx.types.self_param),
);
}
}
@ -223,11 +222,11 @@ fn insert_required_predicates_to_be_wf<'tcx>(
debug!("Projection");
check_explicit_predicates(
tcx,
&tcx.associated_item(obj.item_def_id).container.id(),
tcx.associated_item(obj.item_def_id).container.id(),
obj.substs,
required_predicates,
explicit_map,
IgnoreSelfTy(false),
None,
);
}
@ -236,9 +235,6 @@ fn insert_required_predicates_to_be_wf<'tcx>(
}
}
#[derive(Debug)]
pub struct IgnoreSelfTy(bool);
/// We also have to check the explicit predicates
/// declared on the type.
///
@ -256,25 +252,25 @@ pub struct IgnoreSelfTy(bool);
/// applying the substitution as above.
pub fn check_explicit_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: &DefId,
def_id: DefId,
substs: &[Kind<'tcx>],
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
ignore_self_ty: IgnoreSelfTy,
ignored_self_ty: Option<Ty<'tcx>>,
) {
debug!(
"check_explicit_predicates(def_id={:?}, \
substs={:?}, \
explicit_map={:?}, \
required_predicates={:?}, \
ignore_self_ty={:?})",
ignored_self_ty={:?})",
def_id,
substs,
explicit_map,
required_predicates,
ignore_self_ty,
ignored_self_ty,
);
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, *def_id);
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
for outlives_predicate in explicit_predicates.iter() {
debug!("outlives_predicate = {:?}", &outlives_predicate);
@ -313,9 +309,9 @@ pub fn check_explicit_predicates<'tcx>(
// = X` binding from the object type (there must be such a
// binding) and thus infer an outlives requirement that `X:
// 'b`.
if ignore_self_ty.0 {
if let Some(self_ty) = ignored_self_ty {
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
if ty.has_self_ty() {
if ty.walk().any(|ty| ty == self_ty) {
debug!("skipping self ty = {:?}", &ty);
continue;
}

View file

@ -2303,7 +2303,7 @@ impl Clean<Item> for ty::AssocItem {
ty::ImplContainer(def_id) => {
cx.tcx.type_of(def_id)
}
ty::TraitContainer(_) => cx.tcx.mk_self_type()
ty::TraitContainer(_) => cx.tcx.types.self_param,
};
let self_arg_ty = *sig.input(0).skip_binder();
if self_arg_ty == self_ty {
@ -4107,6 +4107,9 @@ fn name_from_pat(p: &hir::Pat) -> String {
if etc { ", .." } else { "" }
)
}
PatKind::Or(ref pats) => {
pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
}
PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
.collect::<Vec<String>>().join(", ")),
PatKind::Box(ref p) => name_from_pat(&**p),

View file

@ -149,9 +149,11 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId,
return true
}
let predicates = cx.tcx.super_predicates_of(child);
debug_assert!(cx.tcx.generics_of(child).has_self);
let self_ty = cx.tcx.types.self_param;
predicates.predicates.iter().filter_map(|(pred, _)| {
if let ty::Predicate::Trait(ref pred) = *pred {
if pred.skip_binder().trait_ref.self_ty().is_self() {
if pred.skip_binder().trait_ref.self_ty() == self_ty {
Some(pred.def_id())
} else {
None

View file

@ -26,7 +26,7 @@ unwind = { path = "../libunwind" }
hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
[dependencies.backtrace]
version = "0.3.34"
version = "0.3.35"
default-features = false # don't use coresymbolication on OSX
features = [
"rustc-dep-of-std", # enable build support for integrating into libstd

View file

@ -155,7 +155,7 @@ impl Command {
_f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
) {
// Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
unimplemented!();;
unimplemented!();
}
pub fn stdin(&mut self, stdin: Stdio) {

View file

@ -572,9 +572,10 @@ impl Pat {
match &self.node {
PatKind::Ident(_, _, Some(p)) => p.walk(it),
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
s.iter().all(|p| p.walk(it))
}
PatKind::TupleStruct(_, s)
| PatKind::Tuple(s)
| PatKind::Slice(s)
| PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
PatKind::Wild
| PatKind::Rest
@ -648,6 +649,10 @@ pub enum PatKind {
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
TupleStruct(Path, Vec<P<Pat>>),
/// An or-pattern `A | B | C`.
/// Invariant: `pats.len() >= 2`.
Or(Vec<P<Pat>>),
/// A possibly qualified path pattern.
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
/// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can

View file

@ -1,4 +1,4 @@
use crate::ast::{self, Attribute, Name, PatKind};
use crate::ast::{self, NodeId, Attribute, Name, PatKind};
use crate::attr::{HasAttrs, Stability, Deprecation};
use crate::source_map::SourceMap;
use crate::edition::Edition;
@ -671,13 +671,13 @@ bitflags::bitflags! {
}
pub trait Resolver {
fn next_node_id(&mut self) -> ast::NodeId;
fn next_node_id(&mut self) -> NodeId;
fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId;
fn get_module_scope(&mut self, id: NodeId) -> ExpnId;
fn resolve_dollar_crates(&mut self);
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
derives: &[ExpnId]);
extra_placeholders: &[NodeId]);
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
fn resolve_imports(&mut self);

View file

@ -291,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
// Unresolved macros produce dummy outputs as a recovery measure.
invocations.reverse();
let mut expanded_fragments = Vec::new();
let mut derives: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
@ -347,13 +347,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let mut item = self.fully_configure(item);
item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
let derives = derives.entry(invoc.expansion_data.id).or_default();
let derive_placeholders =
all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
derives.reserve(traits.len());
derive_placeholders.reserve(traits.len());
invocations.reserve(traits.len());
for path in traits {
let expn_id = ExpnId::fresh(None);
derives.push(expn_id);
derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
invocations.push(Invocation {
kind: InvocationKind::Derive { path, item: item.clone() },
fragment_kind: invoc.fragment_kind,
@ -365,7 +366,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
let fragment = invoc.fragment_kind
.expect_from_annotatables(::std::iter::once(item));
self.collect_invocations(fragment, derives)
self.collect_invocations(fragment, derive_placeholders)
} else {
unreachable!()
};
@ -384,10 +385,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
// Finally incorporate all the expanded macros into the input AST fragment.
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
while let Some(expanded_fragments) = expanded_fragments.pop() {
for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() {
let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
placeholder_expander.add(NodeId::placeholder_from_expn_id(mark),
expanded_fragment, derives);
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
let derive_placeholders =
all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
expanded_fragment, derive_placeholders);
}
}
fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
@ -404,7 +406,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
/// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
/// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
/// prepares data for resolving paths of macro invocations.
fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[ExpnId])
fn collect_invocations(&mut self, mut fragment: AstFragment, extra_placeholders: &[NodeId])
-> (AstFragment, Vec<Invocation>) {
// Resolve `$crate`s in the fragment for pretty-printing.
self.cx.resolver.resolve_dollar_crates();
@ -423,9 +425,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
collector.invocations
};
// FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
if self.monotonic {
self.cx.resolver.visit_ast_fragment_with_placeholders(
self.cx.current_expansion.id, &fragment, derives);
self.cx.current_expansion.id, &fragment, extra_placeholders);
}
(fragment, invocations)

View file

@ -2,7 +2,6 @@ use crate::ast::{self, NodeId};
use crate::source_map::{DUMMY_SP, dummy_spanned};
use crate::ext::base::ExtCtxt;
use crate::ext::expand::{AstFragment, AstFragmentKind};
use crate::ext::hygiene::ExpnId;
use crate::tokenstream::TokenStream;
use crate::mut_visit::*;
use crate::ptr::P;
@ -86,11 +85,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
}
}
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, derives: Vec<ExpnId>) {
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
fragment.mut_visit_with(self);
if let AstFragment::Items(mut items) = fragment {
for derive in derives {
match self.remove(NodeId::placeholder_from_expn_id(derive)) {
for placeholder in placeholders {
match self.remove(placeholder) {
AstFragment::Items(derived_items) => items.extend(derived_items),
_ => unreachable!(),
}

View file

@ -559,6 +559,9 @@ declare_features! (
// Allows `impl Trait` to be used inside type aliases (RFC 2515).
(active, type_alias_impl_trait, "1.38.0", Some(63063), None),
// Allows the use of or-patterns, e.g. `0 | 1`.
(active, or_patterns, "1.38.0", Some(54883), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
@ -571,6 +574,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::impl_trait_in_bindings,
sym::generic_associated_types,
sym::const_generics,
sym::or_patterns,
sym::let_chains,
];
@ -2443,6 +2447,7 @@ pub fn check_crate(krate: &ast::Crate,
gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental");
gate_all!(async_closure_spans, async_closure, "async closures are unstable");
gate_all!(yield_spans, generators, "yield syntax is experimental");
gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental");
let visitor = &mut PostExpansionVisitor {
context: &ctx,

View file

@ -1050,7 +1050,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
vis.visit_span(span);
};
}
PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
PatKind::Box(inner) => vis.visit_pat(inner),
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
@ -1058,7 +1057,9 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
vis.visit_expr(e2);
vis.visit_span(span);
}
PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
PatKind::Tuple(elems)
| PatKind::Slice(elems)
| PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
PatKind::Paren(inner) => vis.visit_pat(inner),
PatKind::Mac(mac) => vis.visit_mac(mac),
}

View file

@ -8,9 +8,7 @@ use syntax_pos::{BytePos, Pos, Span};
use rustc_lexer::Base;
use rustc_lexer::unescape;
use std::borrow::Cow;
use std::char;
use std::iter;
use std::convert::TryInto;
use rustc_data_structures::sync::Lrc;
use log::debug;
@ -181,18 +179,7 @@ impl<'a> StringReader<'a> {
let string = self.str_from(start);
// comments with only more "/"s are not doc comments
let tok = if is_doc_comment(string) {
let mut idx = 0;
loop {
idx = match string[idx..].find('\r') {
None => break,
Some(it) => idx + it + 1
};
if string[idx..].chars().next() != Some('\n') {
self.err_span_(start + BytePos(idx as u32 - 1),
start + BytePos(idx as u32),
"bare CR not allowed in doc-comment");
}
}
self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment");
token::DocComment(Symbol::intern(string))
} else {
token::Comment
@ -217,15 +204,10 @@ impl<'a> StringReader<'a> {
}
let tok = if is_doc_comment {
let has_cr = string.contains('\r');
let string = if has_cr {
self.translate_crlf(start,
string,
"bare CR not allowed in block doc-comment")
} else {
string.into()
};
token::DocComment(Symbol::intern(&string[..]))
self.forbid_bare_cr(start,
string,
"bare CR not allowed in block doc-comment");
token::DocComment(Symbol::intern(string))
} else {
token::Comment
};
@ -516,49 +498,16 @@ impl<'a> StringReader<'a> {
&self.src[self.src_index(start)..self.src_index(end)]
}
/// Converts CRLF to LF in the given string, raising an error on bare CR.
fn translate_crlf<'b>(&self, start: BytePos, s: &'b str, errmsg: &'b str) -> Cow<'b, str> {
let mut chars = s.char_indices().peekable();
while let Some((i, ch)) = chars.next() {
if ch == '\r' {
if let Some((lf_idx, '\n')) = chars.peek() {
return translate_crlf_(self, start, s, *lf_idx, chars, errmsg).into();
}
let pos = start + BytePos(i as u32);
let end_pos = start + BytePos((i + ch.len_utf8()) as u32);
self.err_span_(pos, end_pos, errmsg);
}
}
return s.into();
fn translate_crlf_(rdr: &StringReader<'_>,
start: BytePos,
s: &str,
mut j: usize,
mut chars: iter::Peekable<impl Iterator<Item = (usize, char)>>,
errmsg: &str)
-> String {
let mut buf = String::with_capacity(s.len());
// Skip first CR
buf.push_str(&s[.. j - 1]);
while let Some((i, ch)) = chars.next() {
if ch == '\r' {
if j < i {
buf.push_str(&s[j..i]);
}
let next = i + ch.len_utf8();
j = next;
if chars.peek().map(|(_, ch)| *ch) != Some('\n') {
let pos = start + BytePos(i as u32);
let end_pos = start + BytePos(next as u32);
rdr.err_span_(pos, end_pos, errmsg);
}
}
}
if j < s.len() {
buf.push_str(&s[j..]);
}
buf
fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) {
let mut idx = 0;
loop {
idx = match s[idx..].find('\r') {
None => break,
Some(it) => idx + it + 1
};
self.err_span_(start + BytePos(idx as u32 - 1),
start + BytePos(idx as u32),
errmsg);
}
}

View file

@ -66,6 +66,8 @@ pub struct ParseSess {
// Places where `yield e?` exprs were used and should be feature gated.
pub yield_spans: Lock<Vec<Span>>,
pub injected_crate_name: Once<Symbol>,
// Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated.
pub or_pattern_spans: Lock<Vec<Span>>,
}
impl ParseSess {
@ -96,6 +98,7 @@ impl ParseSess {
async_closure_spans: Lock::new(Vec::new()),
yield_spans: Lock::new(Vec::new()),
injected_crate_name: Once::new(),
or_pattern_spans: Lock::new(Vec::new()),
}
}

View file

@ -14,7 +14,10 @@ use errors::{Applicability, DiagnosticBuilder};
impl<'a> Parser<'a> {
/// Parses a pattern.
pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
pub fn parse_pat(
&mut self,
expected: Option<&'static str>
) -> PResult<'a, P<Pat>> {
self.parse_pat_with_range_pat(true, expected)
}
@ -97,6 +100,34 @@ impl<'a> Parser<'a> {
Ok(())
}
/// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`).
fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
// Parse the first pattern.
let first_pat = self.parse_pat(expected)?;
// If the next token is not a `|`, this is not an or-pattern and
// we should exit here.
if !self.check(&token::BinOp(token::Or)) {
return Ok(first_pat)
}
let lo = first_pat.span;
let mut pats = vec![first_pat];
while self.eat(&token::BinOp(token::Or)) {
pats.push(self.parse_pat_with_range_pat(
true, expected
)?);
}
let or_pattern_span = lo.to(self.prev_span);
self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span);
Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
}
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
/// allowed).
fn parse_pat_with_range_pat(
@ -240,7 +271,9 @@ impl<'a> Parser<'a> {
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
p.parse_pat_with_or(None)
})?;
// Here, `(pat,)` is a tuple pattern.
// For backward compatibility, `(..)` is a tuple pattern as well.
@ -483,7 +516,7 @@ impl<'a> Parser<'a> {
err.span_label(self.token.span, msg);
return Err(err);
}
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?;
Ok(PatKind::TupleStruct(path, fields))
}
@ -627,7 +660,7 @@ impl<'a> Parser<'a> {
// Parsing a pattern of the form "fieldname: pat"
let fieldname = self.parse_field_name()?;
self.bump();
let pat = self.parse_pat(None)?;
let pat = self.parse_pat_with_or(None)?;
hi = pat.span;
(pat, fieldname, false)
} else {

View file

@ -436,18 +436,30 @@ pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefM
fn print_ident(&mut self, ident: ast::Ident);
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
fn strsep<T, F>(&mut self, sep: &'static str, space_before: bool,
b: Breaks, elts: &[T], mut op: F)
where F: FnMut(&mut Self, &T),
{
self.rbox(0, b);
let mut first = true;
for elt in elts {
if first { first = false; } else { self.word_space(","); }
op(self, elt);
if let Some((first, rest)) = elts.split_first() {
op(self, first);
for elt in rest {
if space_before {
self.space();
}
self.word_space(sep);
op(self, elt);
}
}
self.end();
}
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
where F: FnMut(&mut Self, &T),
{
self.strsep(",", false, b, elts, op)
}
fn maybe_print_comment(&mut self, pos: BytePos) {
while let Some(ref cmnt) = self.next_comment() {
if cmnt.pos < pos {
@ -2353,6 +2365,9 @@ impl<'a> State<'a> {
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.pclose();
}
PatKind::Or(ref pats) => {
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
}
PatKind::Path(None, ref path) => {
self.print_path(path, true, 0);
}
@ -2429,16 +2444,7 @@ impl<'a> State<'a> {
}
fn print_pats(&mut self, pats: &[P<ast::Pat>]) {
let mut first = true;
for p in pats {
if first {
first = false;
} else {
self.s.space();
self.word_space("|");
}
self.print_pat(p);
}
self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
}
fn print_arm(&mut self, arm: &ast::Arm) {

View file

@ -447,9 +447,6 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
visitor.visit_pat(&field.pat)
}
}
PatKind::Tuple(ref elems) => {
walk_list!(visitor, visit_pat, elems);
}
PatKind::Box(ref subpattern) |
PatKind::Ref(ref subpattern, _) |
PatKind::Paren(ref subpattern) => {
@ -465,7 +462,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
visitor.visit_expr(upper_bound);
}
PatKind::Wild | PatKind::Rest => {},
PatKind::Slice(ref elems) => {
PatKind::Tuple(ref elems)
| PatKind::Slice(ref elems)
| PatKind::Or(ref elems) => {
walk_list!(visitor, visit_pat, elems);
}
PatKind::Mac(ref mac) => visitor.visit_mac(mac),

Some files were not shown because too many files have changed in this diff Show more