Auto merge of #44186 - alexcrichton:rollup, r=alexcrichton
Rollup of 8 pull requests - Successful merges: #44044, #44089, #44116, #44125, #44154, #44157, #44160, #44172 - Failed merges: #44162
This commit is contained in:
commit
890c87b643
37 changed files with 691 additions and 206 deletions
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
|
@ -1038,6 +1038,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
name = "proc_macro"
|
name = "proc_macro"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"rustc_errors 0.0.0",
|
||||||
"syntax 0.0.0",
|
"syntax 0.0.0",
|
||||||
"syntax_pos 0.0.0",
|
"syntax_pos 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
The tracking issue for this feature is: [#43122]
|
The tracking issue for this feature is: [#43122]
|
||||||
|
|
||||||
[#34511]: https://github.com/rust-lang/rust/issues/43122
|
[#43122]: https://github.com/rust-lang/rust/issues/43122
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ let mut s = String::from("α is alpha, β is beta");
|
||||||
let beta_offset = s.find('β').unwrap_or(s.len());
|
let beta_offset = s.find('β').unwrap_or(s.len());
|
||||||
|
|
||||||
// Replace the range up until the β from the string
|
// Replace the range up until the β from the string
|
||||||
let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
|
s.splice(..beta_offset, "Α is capital alpha; ");
|
||||||
assert_eq!(t, "α is alpha, ");
|
|
||||||
assert_eq!(s, "Α is capital alpha; β is beta");
|
assert_eq!(s, "Α is capital alpha; β is beta");
|
||||||
```
|
```
|
|
@ -8,12 +8,12 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
/// Creates a `Vec` containing the arguments.
|
/// Creates a [`Vec`] containing the arguments.
|
||||||
///
|
///
|
||||||
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
|
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
|
||||||
/// There are two forms of this macro:
|
/// There are two forms of this macro:
|
||||||
///
|
///
|
||||||
/// - Create a `Vec` containing a given list of elements:
|
/// - Create a [`Vec`] containing a given list of elements:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let v = vec![1, 2, 3];
|
/// let v = vec![1, 2, 3];
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
/// assert_eq!(v[2], 3);
|
/// assert_eq!(v[2], 3);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// - Create a `Vec` from a given element and size:
|
/// - Create a [`Vec`] from a given element and size:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let v = vec![1; 3];
|
/// let v = vec![1; 3];
|
||||||
|
@ -30,14 +30,17 @@
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note that unlike array expressions this syntax supports all elements
|
/// Note that unlike array expressions this syntax supports all elements
|
||||||
/// which implement `Clone` and the number of elements doesn't have to be
|
/// which implement [`Clone`] and the number of elements doesn't have to be
|
||||||
/// a constant.
|
/// a constant.
|
||||||
///
|
///
|
||||||
/// This will use `clone()` to duplicate an expression, so one should be careful
|
/// This will use `clone` to duplicate an expression, so one should be careful
|
||||||
/// using this with types having a nonstandard `Clone` implementation. For
|
/// using this with types having a nonstandard `Clone` implementation. For
|
||||||
/// example, `vec![Rc::new(1); 5]` will create a vector of five references
|
/// example, `vec![Rc::new(1); 5]` will create a vector of five references
|
||||||
/// to the same boxed integer value, not five references pointing to independently
|
/// to the same boxed integer value, not five references pointing to independently
|
||||||
/// boxed integers.
|
/// boxed integers.
|
||||||
|
///
|
||||||
|
/// [`Vec`]: ../std/vec/struct.Vec.html
|
||||||
|
/// [`Clone`]: ../std/clone/trait.Clone.html
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -67,10 +70,22 @@ macro_rules! vec {
|
||||||
($($x:expr,)*) => (vec![$($x),*])
|
($($x:expr,)*) => (vec![$($x),*])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use the syntax described in `std::fmt` to create a value of type `String`.
|
/// Creates a `String` using interpolation of runtime expressions.
|
||||||
/// See [`std::fmt`][fmt] for more information.
|
///
|
||||||
|
/// The first argument `format!` recieves is a format string. This must be a string
|
||||||
|
/// literal. The power of the formatting string is in the `{}`s contained.
|
||||||
|
///
|
||||||
|
/// Additional parameters passed to `format!` replace the `{}`s within the
|
||||||
|
/// formatting string in the order given unless named or positional parameters
|
||||||
|
/// are used, see [`std::fmt`][fmt] for more information.
|
||||||
|
///
|
||||||
|
/// A common use for `format!` is concatenation and interpolation of strings.
|
||||||
|
/// The same convention is used with [`print!`] and [`write!`] macros,
|
||||||
|
/// depending on the intended destination of the string.
|
||||||
///
|
///
|
||||||
/// [fmt]: ../std/fmt/index.html
|
/// [fmt]: ../std/fmt/index.html
|
||||||
|
/// [`print!`]: ../std/macro.print.html
|
||||||
|
/// [`write!`]: ../std/macro.write.html
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
|
|
@ -1392,11 +1392,11 @@ impl String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a splicing iterator that removes the specified range in the string,
|
/// Creates a splicing iterator that removes the specified range in the string,
|
||||||
/// replaces with the given string, and yields the removed chars.
|
/// and replaces it with the given string.
|
||||||
/// The given string doesn’t need to be the same length as the range.
|
/// The given string doesn't need to be the same length as the range.
|
||||||
///
|
///
|
||||||
/// Note: The element range is removed when the [`Splice`] is dropped,
|
/// Note: Unlike [`Vec::splice`], the replacement happens eagerly, and this
|
||||||
/// even if the iterator is not consumed until the end.
|
/// method does not return the removed chars.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -1404,7 +1404,7 @@ impl String {
|
||||||
/// boundary, or if they're out of bounds.
|
/// boundary, or if they're out of bounds.
|
||||||
///
|
///
|
||||||
/// [`char`]: ../../std/primitive.char.html
|
/// [`char`]: ../../std/primitive.char.html
|
||||||
/// [`Splice`]: ../../std/string/struct.Splice.html
|
/// [`Vec::splice`]: ../../std/vec/struct.Vec.html#method.splice
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -1416,45 +1416,32 @@ impl String {
|
||||||
/// let beta_offset = s.find('β').unwrap_or(s.len());
|
/// let beta_offset = s.find('β').unwrap_or(s.len());
|
||||||
///
|
///
|
||||||
/// // Replace the range up until the β from the string
|
/// // Replace the range up until the β from the string
|
||||||
/// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
|
/// s.splice(..beta_offset, "Α is capital alpha; ");
|
||||||
/// assert_eq!(t, "α is alpha, ");
|
|
||||||
/// assert_eq!(s, "Α is capital alpha; β is beta");
|
/// assert_eq!(s, "Α is capital alpha; β is beta");
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
||||||
pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b>
|
pub fn splice<R>(&mut self, range: R, replace_with: &str)
|
||||||
where R: RangeArgument<usize>
|
where R: RangeArgument<usize>
|
||||||
{
|
{
|
||||||
// Memory safety
|
// Memory safety
|
||||||
//
|
//
|
||||||
// The String version of Splice does not have the memory safety issues
|
// The String version of Splice does not have the memory safety issues
|
||||||
// of the vector version. The data is just plain bytes.
|
// of the vector version. The data is just plain bytes.
|
||||||
// Because the range removal happens in Drop, if the Splice iterator is leaked,
|
|
||||||
// the removal will not happen.
|
match range.start() {
|
||||||
let len = self.len();
|
Included(&n) => assert!(self.is_char_boundary(n)),
|
||||||
let start = match range.start() {
|
Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
|
||||||
Included(&n) => n,
|
Unbounded => {},
|
||||||
Excluded(&n) => n + 1,
|
|
||||||
Unbounded => 0,
|
|
||||||
};
|
};
|
||||||
let end = match range.end() {
|
match range.end() {
|
||||||
Included(&n) => n + 1,
|
Included(&n) => assert!(self.is_char_boundary(n + 1)),
|
||||||
Excluded(&n) => n,
|
Excluded(&n) => assert!(self.is_char_boundary(n)),
|
||||||
Unbounded => len,
|
Unbounded => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Take out two simultaneous borrows. The &mut String won't be accessed
|
unsafe {
|
||||||
// until iteration is over, in Drop.
|
self.as_mut_vec()
|
||||||
let self_ptr = self as *mut _;
|
}.splice(range, replace_with.bytes());
|
||||||
// slicing does the appropriate bounds checks
|
|
||||||
let chars_iter = self[start..end].chars();
|
|
||||||
|
|
||||||
Splice {
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
iter: chars_iter,
|
|
||||||
string: self_ptr,
|
|
||||||
replace_with,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this `String` into a [`Box`]`<`[`str`]`>`.
|
/// Converts this `String` into a [`Box`]`<`[`str`]`>`.
|
||||||
|
@ -2241,61 +2228,3 @@ impl<'a> DoubleEndedIterator for Drain<'a> {
|
||||||
|
|
||||||
#[unstable(feature = "fused", issue = "35602")]
|
#[unstable(feature = "fused", issue = "35602")]
|
||||||
impl<'a> FusedIterator for Drain<'a> {}
|
impl<'a> FusedIterator for Drain<'a> {}
|
||||||
|
|
||||||
/// A splicing iterator for `String`.
|
|
||||||
///
|
|
||||||
/// This struct is created by the [`splice()`] method on [`String`]. See its
|
|
||||||
/// documentation for more.
|
|
||||||
///
|
|
||||||
/// [`splice()`]: struct.String.html#method.splice
|
|
||||||
/// [`String`]: struct.String.html
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
|
||||||
pub struct Splice<'a, 'b> {
|
|
||||||
/// Will be used as &'a mut String in the destructor
|
|
||||||
string: *mut String,
|
|
||||||
/// Start of part to remove
|
|
||||||
start: usize,
|
|
||||||
/// End of part to remove
|
|
||||||
end: usize,
|
|
||||||
/// Current remaining range to remove
|
|
||||||
iter: Chars<'a>,
|
|
||||||
replace_with: &'b str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
|
||||||
unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
|
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
|
||||||
unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}
|
|
||||||
|
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
|
||||||
impl<'a, 'b> Drop for Splice<'a, 'b> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
let vec = (*self.string).as_mut_vec();
|
|
||||||
vec.splice(self.start..self.end, self.replace_with.bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
|
||||||
impl<'a, 'b> Iterator for Splice<'a, 'b> {
|
|
||||||
type Item = char;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<char> {
|
|
||||||
self.iter.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
self.iter.size_hint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
|
|
||||||
impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
|
|
||||||
#[inline]
|
|
||||||
fn next_back(&mut self) -> Option<char> {
|
|
||||||
self.iter.next_back()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -442,9 +442,8 @@ fn test_drain() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_splice() {
|
fn test_splice() {
|
||||||
let mut s = "Hello, world!".to_owned();
|
let mut s = "Hello, world!".to_owned();
|
||||||
let t: String = s.splice(7..12, "世界").collect();
|
s.splice(7..12, "世界");
|
||||||
assert_eq!(s, "Hello, 世界!");
|
assert_eq!(s, "Hello, 世界!");
|
||||||
assert_eq!(t, "world");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -457,12 +456,10 @@ fn test_splice_char_boundary() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_splice_inclusive_range() {
|
fn test_splice_inclusive_range() {
|
||||||
let mut v = String::from("12345");
|
let mut v = String::from("12345");
|
||||||
let t: String = v.splice(2...3, "789").collect();
|
v.splice(2...3, "789");
|
||||||
assert_eq!(v, "127895");
|
assert_eq!(v, "127895");
|
||||||
assert_eq!(t, "34");
|
v.splice(1...2, "A");
|
||||||
let t2: String = v.splice(1...2, "A").collect();
|
|
||||||
assert_eq!(v, "1A895");
|
assert_eq!(v, "1A895");
|
||||||
assert_eq!(t2, "27");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -482,24 +479,15 @@ fn test_splice_inclusive_out_of_bounds() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_splice_empty() {
|
fn test_splice_empty() {
|
||||||
let mut s = String::from("12345");
|
let mut s = String::from("12345");
|
||||||
let t: String = s.splice(1..2, "").collect();
|
s.splice(1..2, "");
|
||||||
assert_eq!(s, "1345");
|
assert_eq!(s, "1345");
|
||||||
assert_eq!(t, "2");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_splice_unbounded() {
|
fn test_splice_unbounded() {
|
||||||
let mut s = String::from("12345");
|
let mut s = String::from("12345");
|
||||||
let t: String = s.splice(.., "").collect();
|
s.splice(.., "");
|
||||||
assert_eq!(s, "");
|
assert_eq!(s, "");
|
||||||
assert_eq!(t, "12345");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_splice_forget() {
|
|
||||||
let mut s = String::from("12345");
|
|
||||||
::std::mem::forget(s.splice(2..4, "789"));
|
|
||||||
assert_eq!(s, "12345");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -62,11 +62,13 @@ macro_rules! panic {
|
||||||
/// # Custom Messages
|
/// # Custom Messages
|
||||||
///
|
///
|
||||||
/// This macro has a second form, where a custom panic message can
|
/// This macro has a second form, where a custom panic message can
|
||||||
/// be provided with or without arguments for formatting.
|
/// be provided with or without arguments for formatting. See [`std::fmt`]
|
||||||
|
/// for syntax for this form.
|
||||||
///
|
///
|
||||||
/// [`panic!`]: macro.panic.html
|
/// [`panic!`]: macro.panic.html
|
||||||
/// [`debug_assert!`]: macro.debug_assert.html
|
/// [`debug_assert!`]: macro.debug_assert.html
|
||||||
/// [testing]: ../book/first-edition/testing.html
|
/// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro
|
||||||
|
/// [`std::fmt`]: ../std/fmt/index.html
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -252,13 +254,15 @@ macro_rules! debug_assert {
|
||||||
/// On panic, this macro will print the values of the expressions with their
|
/// On panic, this macro will print the values of the expressions with their
|
||||||
/// debug representations.
|
/// debug representations.
|
||||||
///
|
///
|
||||||
/// Unlike `assert_eq!`, `debug_assert_eq!` statements are only enabled in non
|
/// Unlike [`assert_eq!`], `debug_assert_eq!` statements are only enabled in non
|
||||||
/// optimized builds by default. An optimized build will omit all
|
/// optimized builds by default. An optimized build will omit all
|
||||||
/// `debug_assert_eq!` statements unless `-C debug-assertions` is passed to the
|
/// `debug_assert_eq!` statements unless `-C debug-assertions` is passed to the
|
||||||
/// compiler. This makes `debug_assert_eq!` useful for checks that are too
|
/// compiler. This makes `debug_assert_eq!` useful for checks that are too
|
||||||
/// expensive to be present in a release build but may be helpful during
|
/// expensive to be present in a release build but may be helpful during
|
||||||
/// development.
|
/// development.
|
||||||
///
|
///
|
||||||
|
/// [`assert_eq!`]: ../std/macro.assert_eq.html
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -277,13 +281,15 @@ macro_rules! debug_assert_eq {
|
||||||
/// On panic, this macro will print the values of the expressions with their
|
/// On panic, this macro will print the values of the expressions with their
|
||||||
/// debug representations.
|
/// debug representations.
|
||||||
///
|
///
|
||||||
/// Unlike `assert_ne!`, `debug_assert_ne!` statements are only enabled in non
|
/// Unlike [`assert_ne!`], `debug_assert_ne!` statements are only enabled in non
|
||||||
/// optimized builds by default. An optimized build will omit all
|
/// optimized builds by default. An optimized build will omit all
|
||||||
/// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the
|
/// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the
|
||||||
/// compiler. This makes `debug_assert_ne!` useful for checks that are too
|
/// compiler. This makes `debug_assert_ne!` useful for checks that are too
|
||||||
/// expensive to be present in a release build but may be helpful during
|
/// expensive to be present in a release build but may be helpful during
|
||||||
/// development.
|
/// development.
|
||||||
///
|
///
|
||||||
|
/// [`assert_ne!`]: ../std/macro.assert_ne.html
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -300,10 +306,9 @@ macro_rules! debug_assert_ne {
|
||||||
/// Helper macro for reducing boilerplate code for matching `Result` together
|
/// Helper macro for reducing boilerplate code for matching `Result` together
|
||||||
/// with converting downstream errors.
|
/// with converting downstream errors.
|
||||||
///
|
///
|
||||||
/// Prefer using `?` syntax to `try!`. `?` is built in to the language and is
|
/// The `?` operator was added to replace `try!` and should be used instead.
|
||||||
/// more succinct than `try!`. It is the standard method for error propagation.
|
|
||||||
///
|
///
|
||||||
/// `try!` matches the given `Result`. In case of the `Ok` variant, the
|
/// `try!` matches the given [`Result`]. In case of the `Ok` variant, the
|
||||||
/// expression has the value of the wrapped value.
|
/// expression has the value of the wrapped value.
|
||||||
///
|
///
|
||||||
/// In case of the `Err` variant, it retrieves the inner error. `try!` then
|
/// In case of the `Err` variant, it retrieves the inner error. `try!` then
|
||||||
|
@ -312,7 +317,9 @@ macro_rules! debug_assert_ne {
|
||||||
/// error is then immediately returned.
|
/// error is then immediately returned.
|
||||||
///
|
///
|
||||||
/// Because of the early return, `try!` can only be used in functions that
|
/// Because of the early return, `try!` can only be used in functions that
|
||||||
/// return `Result`.
|
/// return [`Result`].
|
||||||
|
///
|
||||||
|
/// [`Result`]: ../std/result/enum.Result.html
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -331,12 +338,19 @@ macro_rules! debug_assert_ne {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
/// // The prefered method of quick returning Errors
|
||||||
|
/// fn write_to_file_question() -> Result<(), MyError> {
|
||||||
|
/// let mut file = File::create("my_best_friends.txt")?;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // The previous method of quick returning Errors
|
||||||
/// fn write_to_file_using_try() -> Result<(), MyError> {
|
/// fn write_to_file_using_try() -> Result<(), MyError> {
|
||||||
/// let mut file = try!(File::create("my_best_friends.txt"));
|
/// let mut file = try!(File::create("my_best_friends.txt"));
|
||||||
/// try!(file.write_all(b"This is a list of my best friends."));
|
/// try!(file.write_all(b"This is a list of my best friends."));
|
||||||
/// println!("I wrote to the file");
|
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
/// // This is equivalent to:
|
/// // This is equivalent to:
|
||||||
/// fn write_to_file_using_match() -> Result<(), MyError> {
|
/// fn write_to_file_using_match() -> Result<(), MyError> {
|
||||||
/// let mut file = try!(File::create("my_best_friends.txt"));
|
/// let mut file = try!(File::create("my_best_friends.txt"));
|
||||||
|
@ -344,7 +358,6 @@ macro_rules! debug_assert_ne {
|
||||||
/// Ok(v) => v,
|
/// Ok(v) => v,
|
||||||
/// Err(e) => return Err(From::from(e)),
|
/// Err(e) => return Err(From::from(e)),
|
||||||
/// }
|
/// }
|
||||||
/// println!("I wrote to the file");
|
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -365,7 +378,7 @@ macro_rules! try {
|
||||||
/// formatted according to the specified format string and the result will be passed to the writer.
|
/// formatted according to the specified format string and the result will be passed to the writer.
|
||||||
/// The writer may be any value with a `write_fmt` method; generally this comes from an
|
/// The writer may be any value with a `write_fmt` method; generally this comes from an
|
||||||
/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro
|
/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro
|
||||||
/// returns whatever the 'write_fmt' method returns; commonly a [`std::fmt::Result`], or an
|
/// returns whatever the `write_fmt` method returns; commonly a [`std::fmt::Result`], or an
|
||||||
/// [`io::Result`].
|
/// [`io::Result`].
|
||||||
///
|
///
|
||||||
/// See [`std::fmt`] for more information on the format string syntax.
|
/// See [`std::fmt`] for more information on the format string syntax.
|
||||||
|
@ -470,10 +483,20 @@ macro_rules! writeln {
|
||||||
/// * Loops that dynamically terminate.
|
/// * Loops that dynamically terminate.
|
||||||
/// * Iterators that dynamically terminate.
|
/// * Iterators that dynamically terminate.
|
||||||
///
|
///
|
||||||
|
/// If the determination that the code is unreachable proves incorrect, the
|
||||||
|
/// program immediately terminates with a [`panic!`]. The function [`unreachable`],
|
||||||
|
/// which belongs to the [`std::intrinsics`] module, informs the compilier to
|
||||||
|
/// optimize the code out of the release version entirely.
|
||||||
|
///
|
||||||
|
/// [`panic!`]: ../std/macro.panic.html
|
||||||
|
/// [`unreachable`]: ../std/intrinsics/fn.unreachable.html
|
||||||
|
/// [`std::intrinsics`]: ../std/intrinsics/index.html
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This will always [panic!](macro.panic.html)
|
/// This will always [`panic!`]
|
||||||
///
|
///
|
||||||
|
/// [`panic!`]: ../std/macro.panic.html
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Match arms:
|
/// Match arms:
|
||||||
|
@ -516,13 +539,18 @@ macro_rules! unreachable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A standardized placeholder for marking unfinished code. It panics with the
|
/// A standardized placeholder for marking unfinished code.
|
||||||
/// message `"not yet implemented"` when executed.
|
///
|
||||||
|
/// It panics with the message `"not yet implemented"` when executed.
|
||||||
///
|
///
|
||||||
/// This can be useful if you are prototyping and are just looking to have your
|
/// This can be useful if you are prototyping and are just looking to have your
|
||||||
/// code typecheck, or if you're implementing a trait that requires multiple
|
/// code typecheck, or if you're implementing a trait that requires multiple
|
||||||
/// methods, and you're only planning on using one of them.
|
/// methods, and you're only planning on using one of them.
|
||||||
///
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This macro always panics.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Here's an example of some in-progress code. We have a trait `Foo`:
|
/// Here's an example of some in-progress code. We have a trait `Foo`:
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2a5b50b7f7f539a0fd201331d6c1e0534aa332f5
|
Subproject commit 04a5e75c99dc92afab490c38fcbbeac9b4bc8104
|
|
@ -10,3 +10,4 @@ crate-type = ["dylib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
syntax_pos = { path = "../libsyntax_pos" }
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
|
|
134
src/libproc_macro/diagnostic.rs
Normal file
134
src/libproc_macro/diagnostic.rs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use Span;
|
||||||
|
|
||||||
|
use rustc_errors as rustc;
|
||||||
|
|
||||||
|
/// An enum representing a diagnostic level.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Level {
|
||||||
|
/// An error.
|
||||||
|
Error,
|
||||||
|
/// A warning.
|
||||||
|
Warning,
|
||||||
|
/// A note.
|
||||||
|
Note,
|
||||||
|
/// A help message.
|
||||||
|
Help,
|
||||||
|
#[doc(hidden)]
|
||||||
|
__Nonexhaustive,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A structure representing a diagnostic message and associated children
|
||||||
|
/// messages.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Diagnostic {
|
||||||
|
level: Level,
|
||||||
|
message: String,
|
||||||
|
span: Option<Span>,
|
||||||
|
children: Vec<Diagnostic>
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! diagnostic_child_methods {
|
||||||
|
($spanned:ident, $regular:ident, $level:expr) => (
|
||||||
|
/// Add a new child diagnostic message to `self` with the level
|
||||||
|
/// identified by this methods name with the given `span` and `message`.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn $spanned<T: Into<String>>(mut self, span: Span, message: T) -> Diagnostic {
|
||||||
|
self.children.push(Diagnostic::spanned(span, $level, message));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new child diagnostic message to `self` with the level
|
||||||
|
/// identified by this method's name with the given `message`.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
|
||||||
|
self.children.push(Diagnostic::new($level, message));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostic {
|
||||||
|
/// Create a new diagnostic with the given `level` and `message`.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
|
||||||
|
Diagnostic {
|
||||||
|
level: level,
|
||||||
|
message: message.into(),
|
||||||
|
span: None,
|
||||||
|
children: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new diagnostic with the given `level` and `message` pointing to
|
||||||
|
/// the given `span`.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn spanned<T: Into<String>>(span: Span, level: Level, message: T) -> Diagnostic {
|
||||||
|
Diagnostic {
|
||||||
|
level: level,
|
||||||
|
message: message.into(),
|
||||||
|
span: Some(span),
|
||||||
|
children: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostic_child_methods!(span_error, error, Level::Error);
|
||||||
|
diagnostic_child_methods!(span_warning, warning, Level::Warning);
|
||||||
|
diagnostic_child_methods!(span_note, note, Level::Note);
|
||||||
|
diagnostic_child_methods!(span_help, help, Level::Help);
|
||||||
|
|
||||||
|
/// Returns the diagnostic `level` for `self`.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn level(&self) -> Level {
|
||||||
|
self.level
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit the diagnostic.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn emit(self) {
|
||||||
|
::__internal::with_sess(move |(sess, _)| {
|
||||||
|
let handler = &sess.span_diagnostic;
|
||||||
|
let level = __internal::level_to_internal_level(self.level);
|
||||||
|
let mut diag = rustc::DiagnosticBuilder::new(handler, level, &*self.message);
|
||||||
|
|
||||||
|
if let Some(span) = self.span {
|
||||||
|
diag.set_span(span.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for child in self.children {
|
||||||
|
let span = child.span.map(|s| s.0);
|
||||||
|
let level = __internal::level_to_internal_level(child.level);
|
||||||
|
diag.sub(level, &*child.message, span);
|
||||||
|
}
|
||||||
|
|
||||||
|
diag.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod __internal {
|
||||||
|
use super::{Level, rustc};
|
||||||
|
|
||||||
|
pub fn level_to_internal_level(level: Level) -> rustc::Level {
|
||||||
|
match level {
|
||||||
|
Level::Error => rustc::Level::Error,
|
||||||
|
Level::Warning => rustc::Level::Warning,
|
||||||
|
Level::Note => rustc::Level::Note,
|
||||||
|
Level::Help => rustc::Level::Help,
|
||||||
|
Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,12 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate syntax_pos;
|
extern crate syntax_pos;
|
||||||
|
extern crate rustc_errors;
|
||||||
|
|
||||||
|
mod diagnostic;
|
||||||
|
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub use diagnostic::{Diagnostic, Level};
|
||||||
|
|
||||||
use std::{ascii, fmt, iter};
|
use std::{ascii, fmt, iter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -188,12 +194,28 @@ pub fn quote_span(span: Span) -> TokenStream {
|
||||||
TokenStream(quote::Quote::quote(&span.0))
|
TokenStream(quote::Quote::quote(&span.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! diagnostic_method {
|
||||||
|
($name:ident, $level:expr) => (
|
||||||
|
/// Create a new `Diagnostic` with the given `message` at the span
|
||||||
|
/// `self`.
|
||||||
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
|
pub fn $name<T: Into<String>>(self, message: T) -> Diagnostic {
|
||||||
|
Diagnostic::spanned(self, $level, message)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
/// The span of the invocation of the current procedural macro.
|
/// The span of the invocation of the current procedural macro.
|
||||||
#[unstable(feature = "proc_macro", issue = "38356")]
|
#[unstable(feature = "proc_macro", issue = "38356")]
|
||||||
pub fn call_site() -> Span {
|
pub fn call_site() -> Span {
|
||||||
::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
|
::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diagnostic_method!(error, Level::Error);
|
||||||
|
diagnostic_method!(warning, Level::Warning);
|
||||||
|
diagnostic_method!(note, Level::Note);
|
||||||
|
diagnostic_method!(help, Level::Help);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
|
/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
|
|
||||||
use hir::def_id::{CrateNum, DefId};
|
use hir::def_id::{CrateNum, DefId};
|
||||||
use hir::map::DefPathHash;
|
use hir::map::DefPathHash;
|
||||||
|
use hir::HirId;
|
||||||
|
|
||||||
use ich::Fingerprint;
|
use ich::Fingerprint;
|
||||||
use ty::{TyCtxt, Instance, InstanceDef};
|
use ty::{TyCtxt, Instance, InstanceDef};
|
||||||
|
@ -527,6 +528,9 @@ define_dep_nodes!( <'tcx>
|
||||||
[] HasGlobalAllocator(DefId),
|
[] HasGlobalAllocator(DefId),
|
||||||
[] ExternCrate(DefId),
|
[] ExternCrate(DefId),
|
||||||
[] LintLevels,
|
[] LintLevels,
|
||||||
|
[] Specializes { impl1: DefId, impl2: DefId },
|
||||||
|
[] InScopeTraits(HirId),
|
||||||
|
[] ModuleExports(HirId),
|
||||||
);
|
);
|
||||||
|
|
||||||
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
|
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
|
||||||
|
|
|
@ -205,13 +205,15 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ast::N
|
||||||
// corresponding entry in the `trait_map` we need to hash that.
|
// corresponding entry in the `trait_map` we need to hash that.
|
||||||
// Make sure we don't ignore too much by checking that there is
|
// Make sure we don't ignore too much by checking that there is
|
||||||
// no entry in a debug_assert!().
|
// no entry in a debug_assert!().
|
||||||
debug_assert!(hcx.tcx.trait_map.get(self).is_none());
|
let hir_id = hcx.tcx.hir.node_to_hir_id(*self);
|
||||||
|
debug_assert!(hcx.tcx.in_scope_traits(hir_id).is_none());
|
||||||
}
|
}
|
||||||
NodeIdHashingMode::HashDefPath => {
|
NodeIdHashingMode::HashDefPath => {
|
||||||
hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher);
|
hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
NodeIdHashingMode::HashTraitsInScope => {
|
NodeIdHashingMode::HashTraitsInScope => {
|
||||||
if let Some(traits) = hcx.tcx.trait_map.get(self) {
|
let hir_id = hcx.tcx.hir.node_to_hir_id(*self);
|
||||||
|
if let Some(traits) = hcx.tcx.in_scope_traits(hir_id) {
|
||||||
// The ordering of the candidates is not fixed. So we hash
|
// The ordering of the candidates is not fixed. So we hash
|
||||||
// the def-ids and then sort them and hash the collection.
|
// the def-ids and then sort them and hash the collection.
|
||||||
let mut candidates: AccumulateVec<[_; 8]> =
|
let mut candidates: AccumulateVec<[_; 8]> =
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
|
||||||
pub use self::object_safety::ObjectSafetyViolation;
|
pub use self::object_safety::ObjectSafetyViolation;
|
||||||
pub use self::object_safety::MethodViolationCode;
|
pub use self::object_safety::MethodViolationCode;
|
||||||
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
|
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
|
||||||
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
|
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
|
||||||
pub use self::specialize::{SpecializesCache, find_associated_item};
|
pub use self::specialize::{SpecializesCache, find_associated_item};
|
||||||
pub use self::util::elaborate_predicates;
|
pub use self::util::elaborate_predicates;
|
||||||
pub use self::util::supertraits;
|
pub use self::util::supertraits;
|
||||||
|
@ -831,6 +831,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
|
||||||
*providers = ty::maps::Providers {
|
*providers = ty::maps::Providers {
|
||||||
is_object_safe: object_safety::is_object_safe_provider,
|
is_object_safe: object_safety::is_object_safe_provider,
|
||||||
specialization_graph_of: specialize::specialization_graph_provider,
|
specialization_graph_of: specialize::specialization_graph_provider,
|
||||||
|
specializes: specialize::specializes,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -839,6 +840,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
|
||||||
*providers = ty::maps::Providers {
|
*providers = ty::maps::Providers {
|
||||||
is_object_safe: object_safety::is_object_safe_provider,
|
is_object_safe: object_safety::is_object_safe_provider,
|
||||||
specialization_graph_of: specialize::specialization_graph_provider,
|
specialization_graph_of: specialize::specialization_graph_provider,
|
||||||
|
specializes: specialize::specializes,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ use infer;
|
||||||
use infer::{InferCtxt, InferOk, TypeFreshener};
|
use infer::{InferCtxt, InferOk, TypeFreshener};
|
||||||
use ty::subst::{Kind, Subst, Substs};
|
use ty::subst::{Kind, Subst, Substs};
|
||||||
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
||||||
use traits;
|
|
||||||
use ty::fast_reject;
|
use ty::fast_reject;
|
||||||
use ty::relate::TypeRelation;
|
use ty::relate::TypeRelation;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
|
@ -1865,7 +1864,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||||
if other.evaluation == EvaluatedToOk {
|
if other.evaluation == EvaluatedToOk {
|
||||||
if let ImplCandidate(victim_def) = victim.candidate {
|
if let ImplCandidate(victim_def) = victim.candidate {
|
||||||
let tcx = self.tcx().global_tcx();
|
let tcx = self.tcx().global_tcx();
|
||||||
return traits::specializes(tcx, other_def, victim_def) ||
|
return tcx.specializes((other_def, victim_def)) ||
|
||||||
tcx.impls_are_allowed_to_overlap(other_def, victim_def);
|
tcx.impls_are_allowed_to_overlap(other_def, victim_def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,15 +150,12 @@ pub fn find_associated_item<'a, 'tcx>(
|
||||||
/// Specialization is determined by the sets of types to which the impls apply;
|
/// Specialization is determined by the sets of types to which the impls apply;
|
||||||
/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
|
/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
|
||||||
/// to.
|
/// to.
|
||||||
pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
impl1_def_id: DefId,
|
(impl1_def_id, impl2_def_id): (DefId, DefId))
|
||||||
impl2_def_id: DefId) -> bool {
|
-> bool
|
||||||
|
{
|
||||||
debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
|
debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
|
||||||
|
|
||||||
if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The feature gate should prevent introducing new specializations, but not
|
// The feature gate should prevent introducing new specializations, but not
|
||||||
// taking advantage of upstream ones.
|
// taking advantage of upstream ones.
|
||||||
if !tcx.sess.features.borrow().specialization &&
|
if !tcx.sess.features.borrow().specialization &&
|
||||||
|
@ -188,7 +185,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
|
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
|
||||||
|
|
||||||
// Create a infcx, taking the predicates of impl1 as assumptions:
|
// Create a infcx, taking the predicates of impl1 as assumptions:
|
||||||
let result = tcx.infer_ctxt().enter(|infcx| {
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
// Normalize the trait reference. The WF rules ought to ensure
|
// Normalize the trait reference. The WF rules ought to ensure
|
||||||
// that this always succeeds.
|
// that this always succeeds.
|
||||||
let impl1_trait_ref =
|
let impl1_trait_ref =
|
||||||
|
@ -204,10 +201,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
|
||||||
// Attempt to prove that impl2 applies, given all of the above.
|
// Attempt to prove that impl2 applies, given all of the above.
|
||||||
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
|
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
|
||||||
});
|
})
|
||||||
|
|
||||||
tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to fulfill all obligations of `target_impl` after unification with
|
/// Attempt to fulfill all obligations of `target_impl` after unification with
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use super::{OverlapError, specializes};
|
use super::OverlapError;
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use traits;
|
use traits;
|
||||||
|
@ -118,8 +118,8 @@ impl<'a, 'gcx, 'tcx> Children {
|
||||||
return Ok((false, false));
|
return Ok((false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
let le = specializes(tcx, impl_def_id, possible_sibling);
|
let le = tcx.specializes((impl_def_id, possible_sibling));
|
||||||
let ge = specializes(tcx, possible_sibling, impl_def_id);
|
let ge = tcx.specializes((possible_sibling, impl_def_id));
|
||||||
|
|
||||||
if le == ge {
|
if le == ge {
|
||||||
// overlap, but no specialization; error out
|
// overlap, but no specialization; error out
|
||||||
|
|
|
@ -14,8 +14,8 @@ use dep_graph::DepGraph;
|
||||||
use errors::DiagnosticBuilder;
|
use errors::DiagnosticBuilder;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use middle;
|
use middle;
|
||||||
use hir::{TraitMap};
|
use hir::{TraitCandidate, HirId};
|
||||||
use hir::def::{Def, ExportMap};
|
use hir::def::{Def, Export};
|
||||||
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
use hir::map as hir_map;
|
use hir::map as hir_map;
|
||||||
use hir::map::DefPathHash;
|
use hir::map::DefPathHash;
|
||||||
|
@ -808,8 +808,6 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
pub sess: &'tcx Session,
|
pub sess: &'tcx Session,
|
||||||
|
|
||||||
pub specializes_cache: RefCell<traits::SpecializesCache>,
|
|
||||||
|
|
||||||
pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
|
pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
|
||||||
|
|
||||||
pub dep_graph: DepGraph,
|
pub dep_graph: DepGraph,
|
||||||
|
@ -819,10 +817,10 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
/// Map indicating what traits are in scope for places where this
|
/// Map indicating what traits are in scope for places where this
|
||||||
/// is relevant; generated by resolve.
|
/// is relevant; generated by resolve.
|
||||||
pub trait_map: TraitMap,
|
trait_map: FxHashMap<HirId, Rc<Vec<TraitCandidate>>>,
|
||||||
|
|
||||||
/// Export map produced by name resolution.
|
/// Export map produced by name resolution.
|
||||||
pub export_map: ExportMap,
|
export_map: FxHashMap<HirId, Rc<Vec<Export>>>,
|
||||||
|
|
||||||
pub named_region_map: resolve_lifetime::NamedRegionMap,
|
pub named_region_map: resolve_lifetime::NamedRegionMap,
|
||||||
|
|
||||||
|
@ -1072,14 +1070,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
tls::enter_global(GlobalCtxt {
|
tls::enter_global(GlobalCtxt {
|
||||||
sess: s,
|
sess: s,
|
||||||
trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
|
trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
|
||||||
specializes_cache: RefCell::new(traits::SpecializesCache::new()),
|
|
||||||
global_arenas: arenas,
|
global_arenas: arenas,
|
||||||
global_interners: interners,
|
global_interners: interners,
|
||||||
dep_graph: dep_graph.clone(),
|
dep_graph: dep_graph.clone(),
|
||||||
types: common_types,
|
types: common_types,
|
||||||
named_region_map,
|
named_region_map,
|
||||||
trait_map: resolutions.trait_map,
|
trait_map: resolutions.trait_map.into_iter().map(|(k, v)| {
|
||||||
export_map: resolutions.export_map,
|
(hir.node_to_hir_id(k), Rc::new(v))
|
||||||
|
}).collect(),
|
||||||
|
export_map: resolutions.export_map.into_iter().map(|(k, v)| {
|
||||||
|
(hir.node_to_hir_id(k), Rc::new(v))
|
||||||
|
}).collect(),
|
||||||
hir,
|
hir,
|
||||||
def_path_hash_to_def_id,
|
def_path_hash_to_def_id,
|
||||||
maps: maps::Maps::new(providers),
|
maps: maps::Maps::new(providers),
|
||||||
|
@ -1997,3 +1998,20 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
|
||||||
Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
|
Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn in_scope_traits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: HirId)
|
||||||
|
-> Option<Rc<Vec<TraitCandidate>>>
|
||||||
|
{
|
||||||
|
tcx.gcx.trait_map.get(&id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module_exports<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: HirId)
|
||||||
|
-> Option<Rc<Vec<Export>>>
|
||||||
|
{
|
||||||
|
tcx.gcx.export_map.get(&id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn provide(providers: &mut ty::maps::Providers) {
|
||||||
|
providers.in_scope_traits = in_scope_traits;
|
||||||
|
providers.module_exports = module_exports;
|
||||||
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
use dep_graph::{DepConstructor, DepNode, DepNodeIndex};
|
use dep_graph::{DepConstructor, DepNode, DepNodeIndex};
|
||||||
use errors::{Diagnostic, DiagnosticBuilder};
|
use errors::{Diagnostic, DiagnosticBuilder};
|
||||||
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
use hir::def::Def;
|
use hir::def::{Def, Export};
|
||||||
use hir;
|
use hir::{self, TraitCandidate, HirId};
|
||||||
use lint;
|
use lint;
|
||||||
use middle::const_val;
|
use middle::const_val;
|
||||||
use middle::cstore::{ExternCrate, LinkagePreference};
|
use middle::cstore::{ExternCrate, LinkagePreference};
|
||||||
|
@ -80,6 +80,15 @@ impl Key for CrateNum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Key for HirId {
|
||||||
|
fn map_crate(&self) -> CrateNum {
|
||||||
|
LOCAL_CRATE
|
||||||
|
}
|
||||||
|
fn default_span(&self, _tcx: TyCtxt) -> Span {
|
||||||
|
DUMMY_SP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Key for DefId {
|
impl Key for DefId {
|
||||||
fn map_crate(&self) -> CrateNum {
|
fn map_crate(&self) -> CrateNum {
|
||||||
self.krate
|
self.krate
|
||||||
|
@ -540,6 +549,24 @@ impl<'tcx> QueryDescription for queries::lint_levels<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> QueryDescription for queries::specializes<'tcx> {
|
||||||
|
fn describe(_tcx: TyCtxt, _: (DefId, DefId)) -> String {
|
||||||
|
format!("computing whether impls specialize one another")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> QueryDescription for queries::in_scope_traits<'tcx> {
|
||||||
|
fn describe(_tcx: TyCtxt, _: HirId) -> String {
|
||||||
|
format!("fetching the traits in scope at a particular ast node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> QueryDescription for queries::module_exports<'tcx> {
|
||||||
|
fn describe(_tcx: TyCtxt, _: HirId) -> String {
|
||||||
|
format!("fetching the exported items for a module")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If enabled, send a message to the profile-queries thread
|
// If enabled, send a message to the profile-queries thread
|
||||||
macro_rules! profq_msg {
|
macro_rules! profq_msg {
|
||||||
($tcx:expr, $msg:expr) => {
|
($tcx:expr, $msg:expr) => {
|
||||||
|
@ -1108,6 +1135,10 @@ define_maps! { <'tcx>
|
||||||
[] extern_crate: ExternCrate(DefId) -> Rc<Option<ExternCrate>>,
|
[] extern_crate: ExternCrate(DefId) -> Rc<Option<ExternCrate>>,
|
||||||
|
|
||||||
[] lint_levels: lint_levels(CrateNum) -> Rc<lint::LintLevelMap>,
|
[] lint_levels: lint_levels(CrateNum) -> Rc<lint::LintLevelMap>,
|
||||||
|
|
||||||
|
[] specializes: specializes_node((DefId, DefId)) -> bool,
|
||||||
|
[] in_scope_traits: InScopeTraits(HirId) -> Option<Rc<Vec<TraitCandidate>>>,
|
||||||
|
[] module_exports: ModuleExports(HirId) -> Option<Rc<Vec<Export>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
|
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
|
||||||
|
@ -1183,3 +1214,7 @@ fn layout_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'
|
||||||
fn lint_levels<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
|
fn lint_levels<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
|
||||||
DepConstructor::LintLevels
|
DepConstructor::LintLevels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> {
|
||||||
|
DepConstructor::Specializes { impl1: a, impl2: b }
|
||||||
|
}
|
||||||
|
|
|
@ -2517,6 +2517,7 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
|
||||||
pub fn provide(providers: &mut ty::maps::Providers) {
|
pub fn provide(providers: &mut ty::maps::Providers) {
|
||||||
util::provide(providers);
|
util::provide(providers);
|
||||||
|
context::provide(providers);
|
||||||
*providers = ty::maps::Providers {
|
*providers = ty::maps::Providers {
|
||||||
associated_item,
|
associated_item,
|
||||||
associated_item_def_ids,
|
associated_item_def_ids,
|
||||||
|
|
|
@ -288,7 +288,7 @@ impl Diagnostic {
|
||||||
|
|
||||||
/// Convenience function for internal use, clients should use one of the
|
/// Convenience function for internal use, clients should use one of the
|
||||||
/// public methods above.
|
/// public methods above.
|
||||||
fn sub(&mut self,
|
pub(crate) fn sub(&mut self,
|
||||||
level: Level,
|
level: Level,
|
||||||
message: &str,
|
message: &str,
|
||||||
span: MultiSpan,
|
span: MultiSpan,
|
||||||
|
|
|
@ -110,6 +110,19 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience function for internal use, clients should use one of the
|
||||||
|
/// span_* methods instead.
|
||||||
|
pub fn sub<S: Into<MultiSpan>>(
|
||||||
|
&mut self,
|
||||||
|
level: Level,
|
||||||
|
message: &str,
|
||||||
|
span: Option<S>,
|
||||||
|
) -> &mut Self {
|
||||||
|
let span = span.map(|s| s.into()).unwrap_or(MultiSpan::new());
|
||||||
|
self.diagnostic.sub(level, message, span, None);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Delay emission of this diagnostic as a bug.
|
/// Delay emission of this diagnostic as a bug.
|
||||||
///
|
///
|
||||||
/// This can be useful in contexts where an error indicates a bug but
|
/// This can be useful in contexts where an error indicates a bug but
|
||||||
|
|
|
@ -548,12 +548,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||||
&hir::Visibility)>)
|
&hir::Visibility)>)
|
||||||
-> Entry<'tcx> {
|
-> Entry<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
let hir_id = tcx.hir.node_to_hir_id(id);
|
||||||
let def_id = tcx.hir.local_def_id(id);
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
debug!("IsolatedEncoder::encode_info_for_mod({:?})", def_id);
|
debug!("IsolatedEncoder::encode_info_for_mod({:?})", def_id);
|
||||||
|
|
||||||
let data = ModData {
|
let data = ModData {
|
||||||
reexports: match tcx.export_map.get(&id) {
|
reexports: match tcx.module_exports(hir_id) {
|
||||||
Some(exports) if *vis == hir::Public => {
|
Some(ref exports) if *vis == hir::Public => {
|
||||||
self.lazy_seq_from_slice(exports.as_slice())
|
self.lazy_seq_from_slice(exports.as_slice())
|
||||||
}
|
}
|
||||||
_ => LazySeq::empty(),
|
_ => LazySeq::empty(),
|
||||||
|
|
|
@ -325,8 +325,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
||||||
// This code is here instead of in visit_item so that the
|
// This code is here instead of in visit_item so that the
|
||||||
// crate module gets processed as well.
|
// crate module gets processed as well.
|
||||||
if self.prev_level.is_some() {
|
if self.prev_level.is_some() {
|
||||||
if let Some(exports) = self.tcx.export_map.get(&id) {
|
let hir_id = self.tcx.hir.node_to_hir_id(id);
|
||||||
for export in exports {
|
if let Some(exports) = self.tcx.module_exports(hir_id) {
|
||||||
|
for export in exports.iter() {
|
||||||
if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) {
|
if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) {
|
||||||
self.update(node_id, Some(AccessLevel::Exported));
|
self.update(node_id, Some(AccessLevel::Exported));
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,7 +402,8 @@ impl<'a> Resolver<'a> {
|
||||||
let ast::Path { ref segments, span } = *path;
|
let ast::Path { ref segments, span } = *path;
|
||||||
let path: Vec<_> = segments.iter().map(|seg| respan(seg.span, seg.identifier)).collect();
|
let path: Vec<_> = segments.iter().map(|seg| respan(seg.span, seg.identifier)).collect();
|
||||||
let invocation = self.invocations[&scope];
|
let invocation = self.invocations[&scope];
|
||||||
self.current_module = invocation.module.get();
|
let module = invocation.module.get();
|
||||||
|
self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
|
||||||
|
|
||||||
if path.len() > 1 {
|
if path.len() > 1 {
|
||||||
if !self.use_extern_macros && self.gated_errors.insert(span) {
|
if !self.use_extern_macros && self.gated_errors.insert(span) {
|
||||||
|
|
|
@ -639,10 +639,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||||
fn assemble_extension_candidates_for_traits_in_scope(&mut self,
|
fn assemble_extension_candidates_for_traits_in_scope(&mut self,
|
||||||
expr_id: ast::NodeId)
|
expr_id: ast::NodeId)
|
||||||
-> Result<(), MethodError<'tcx>> {
|
-> Result<(), MethodError<'tcx>> {
|
||||||
|
if expr_id == ast::DUMMY_NODE_ID {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
let mut duplicates = FxHashSet();
|
let mut duplicates = FxHashSet();
|
||||||
let opt_applicable_traits = self.tcx.trait_map.get(&expr_id);
|
let expr_hir_id = self.tcx.hir.node_to_hir_id(expr_id);
|
||||||
|
let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
|
||||||
if let Some(applicable_traits) = opt_applicable_traits {
|
if let Some(applicable_traits) = opt_applicable_traits {
|
||||||
for trait_candidate in applicable_traits {
|
for trait_candidate in applicable_traits.iter() {
|
||||||
let trait_did = trait_candidate.def_id;
|
let trait_did = trait_candidate.def_id;
|
||||||
if duplicates.insert(trait_did) {
|
if duplicates.insert(trait_did) {
|
||||||
let import_id = trait_candidate.import_id;
|
let import_id = trait_candidate.import_id;
|
||||||
|
|
|
@ -199,8 +199,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||||
self.visit_item(item, None, &mut om);
|
self.visit_item(item, None, &mut om);
|
||||||
}
|
}
|
||||||
self.inside_public_path = orig_inside_public_path;
|
self.inside_public_path = orig_inside_public_path;
|
||||||
if let Some(exports) = self.cx.tcx.export_map.get(&id) {
|
let hir_id = self.cx.tcx.hir.node_to_hir_id(id);
|
||||||
for export in exports {
|
if let Some(exports) = self.cx.tcx.module_exports(hir_id) {
|
||||||
|
for export in exports.iter() {
|
||||||
if let Def::Macro(def_id, ..) = export.def {
|
if let Def::Macro(def_id, ..) = export.def {
|
||||||
if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) {
|
if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) {
|
||||||
continue // These are `krate.exported_macros`, handled in `self.visit()`.
|
continue // These are `krate.exported_macros`, handled in `self.visit()`.
|
||||||
|
|
|
@ -26,13 +26,33 @@ macro_rules! __rust_unstable_column {
|
||||||
|
|
||||||
/// The entry point for panic of Rust threads.
|
/// The entry point for panic of Rust threads.
|
||||||
///
|
///
|
||||||
|
/// This allows a program to to terminate immediately and provide feedback
|
||||||
|
/// to the caller of the program. `panic!` should be used when a program reaches
|
||||||
|
/// an unrecoverable problem.
|
||||||
|
///
|
||||||
|
/// This macro is the perfect way to assert conditions in example code and in
|
||||||
|
/// tests. `panic!` is closely tied with the `unwrap` method of both [`Option`]
|
||||||
|
/// and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set
|
||||||
|
/// to None or Err variants.
|
||||||
|
///
|
||||||
/// This macro is used to inject panic into a Rust thread, causing the thread to
|
/// This macro is used to inject panic into a Rust thread, causing the thread to
|
||||||
/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
|
/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
|
||||||
/// and the single-argument form of the `panic!` macro will be the value which
|
/// and the single-argument form of the `panic!` macro will be the value which
|
||||||
/// is transmitted.
|
/// is transmitted.
|
||||||
///
|
///
|
||||||
|
/// [`Result`] enum is often a better solution for recovering from errors than
|
||||||
|
/// using the `panic!` macro. This macro should be used to avoid proceeding using
|
||||||
|
/// incorrect values, such as from external sources. Detailed information about
|
||||||
|
/// error handling is found in the [book].
|
||||||
|
///
|
||||||
/// The multi-argument form of this macro panics with a string and has the
|
/// The multi-argument form of this macro panics with a string and has the
|
||||||
/// `format!` syntax for building a string.
|
/// [`format!`] syntax for building a string.
|
||||||
|
///
|
||||||
|
/// [runwrap]: ../std/result/enum.Result.html#method.unwrap
|
||||||
|
/// [`Option`]: ../std/option/enum.Option.html#method.unwrap
|
||||||
|
/// [`Result`]: ../std/result/enum.Result.html
|
||||||
|
/// [`format!`]: ../std/macro.format.html
|
||||||
|
/// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html
|
||||||
///
|
///
|
||||||
/// # Current implementation
|
/// # Current implementation
|
||||||
///
|
///
|
||||||
|
@ -78,15 +98,19 @@ macro_rules! panic {
|
||||||
|
|
||||||
/// Macro for printing to the standard output.
|
/// Macro for printing to the standard output.
|
||||||
///
|
///
|
||||||
/// Equivalent to the `println!` macro except that a newline is not printed at
|
/// Equivalent to the [`println!`] macro except that a newline is not printed at
|
||||||
/// the end of the message.
|
/// the end of the message.
|
||||||
///
|
///
|
||||||
/// Note that stdout is frequently line-buffered by default so it may be
|
/// Note that stdout is frequently line-buffered by default so it may be
|
||||||
/// necessary to use `io::stdout().flush()` to ensure the output is emitted
|
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
|
||||||
/// immediately.
|
/// immediately.
|
||||||
///
|
///
|
||||||
/// Use `print!` only for the primary output of your program. Use
|
/// Use `print!` only for the primary output of your program. Use
|
||||||
/// `eprint!` instead to print error and progress messages.
|
/// [`eprint!`] instead to print error and progress messages.
|
||||||
|
///
|
||||||
|
/// [`println!`]: ../std/macro.println.html
|
||||||
|
/// [flush]: ../std/io/trait.Write.html#tymethod.flush
|
||||||
|
/// [`eprint!`]: ../std/macro.eprint.html
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -118,16 +142,20 @@ macro_rules! print {
|
||||||
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
|
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Macro for printing to the standard output, with a newline. On all
|
/// Macro for printing to the standard output, with a newline.
|
||||||
/// platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
|
///
|
||||||
|
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
|
||||||
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
|
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
|
||||||
///
|
///
|
||||||
/// Use the `format!` syntax to write data to the standard output.
|
/// Use the [`format!`] syntax to write data to the standard output.
|
||||||
/// See `std::fmt` for more information.
|
/// See [`std::fmt`] for more information.
|
||||||
///
|
///
|
||||||
/// Use `println!` only for the primary output of your program. Use
|
/// Use `println!` only for the primary output of your program. Use
|
||||||
/// `eprintln!` instead to print error and progress messages.
|
/// [`eprintln!`] instead to print error and progress messages.
|
||||||
///
|
///
|
||||||
|
/// [`format!`]: ../std/macro.format.html
|
||||||
|
/// [`std::fmt`]: ../std/fmt/index.html
|
||||||
|
/// [`eprintln!`]: ../std/macro.eprint.html
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if writing to `io::stdout` fails.
|
/// Panics if writing to `io::stdout` fails.
|
||||||
|
@ -149,16 +177,25 @@ macro_rules! println {
|
||||||
|
|
||||||
/// Macro for printing to the standard error.
|
/// Macro for printing to the standard error.
|
||||||
///
|
///
|
||||||
/// Equivalent to the `print!` macro, except that output goes to
|
/// Equivalent to the [`print!`] macro, except that output goes to
|
||||||
/// `io::stderr` instead of `io::stdout`. See `print!` for
|
/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for
|
||||||
/// example usage.
|
/// example usage.
|
||||||
///
|
///
|
||||||
/// Use `eprint!` only for error and progress messages. Use `print!`
|
/// Use `eprint!` only for error and progress messages. Use `print!`
|
||||||
/// instead for the primary output of your program.
|
/// instead for the primary output of your program.
|
||||||
///
|
///
|
||||||
|
/// [`io::stderr`]: ../std/io/struct.Stderr.html
|
||||||
|
/// [`print!`]: ../std/macro.print.html
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if writing to `io::stderr` fails.
|
/// Panics if writing to `io::stderr` fails.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// eprint!("Error: Could not complete task");
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "eprint", since = "1.19.0")]
|
#[stable(feature = "eprint", since = "1.19.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable]
|
||||||
|
@ -168,16 +205,25 @@ macro_rules! eprint {
|
||||||
|
|
||||||
/// Macro for printing to the standard error, with a newline.
|
/// Macro for printing to the standard error, with a newline.
|
||||||
///
|
///
|
||||||
/// Equivalent to the `println!` macro, except that output goes to
|
/// Equivalent to the [`println!`] macro, except that output goes to
|
||||||
/// `io::stderr` instead of `io::stdout`. See `println!` for
|
/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for
|
||||||
/// example usage.
|
/// example usage.
|
||||||
///
|
///
|
||||||
/// Use `eprintln!` only for error and progress messages. Use `println!`
|
/// Use `eprintln!` only for error and progress messages. Use `println!`
|
||||||
/// instead for the primary output of your program.
|
/// instead for the primary output of your program.
|
||||||
///
|
///
|
||||||
|
/// [`io::stderr`]: ../std/io/struct.Stderr.html
|
||||||
|
/// [`println!`]: ../std/macro.println.html
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if writing to `io::stderr` fails.
|
/// Panics if writing to `io::stderr` fails.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// eprintln!("Error: Could not complete task");
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "eprint", since = "1.19.0")]
|
#[stable(feature = "eprint", since = "1.19.0")]
|
||||||
macro_rules! eprintln {
|
macro_rules! eprintln {
|
||||||
|
@ -267,13 +313,23 @@ pub mod builtin {
|
||||||
|
|
||||||
/// The core macro for formatted string creation & output.
|
/// The core macro for formatted string creation & output.
|
||||||
///
|
///
|
||||||
|
/// This macro functions by taking a formatting string literal containing
|
||||||
|
/// `{}` for each additional argument passed. `format_args!` prepares the
|
||||||
|
/// additional parameters to ensure the output can be interpreted as a string
|
||||||
|
/// and canonicalizes the arguments into a single type. Any value that implements
|
||||||
|
/// the [`Display`] trait can be passed to `format_args!`, as can any
|
||||||
|
/// [`Debug`] implementation be passed to a `{:?}` within the formatting string.
|
||||||
|
///
|
||||||
/// This macro produces a value of type [`fmt::Arguments`]. This value can be
|
/// This macro produces a value of type [`fmt::Arguments`]. This value can be
|
||||||
/// passed to the functions in [`std::fmt`] for performing useful functions.
|
/// passed to the macros within [`std::fmt`] for performing useful redirection.
|
||||||
/// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are
|
/// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are
|
||||||
/// proxied through this one.
|
/// proxied through this one. `format_args!`, unlike its derived macros, avoids
|
||||||
|
/// heap allocations.
|
||||||
///
|
///
|
||||||
/// For more information, see the documentation in [`std::fmt`].
|
/// For more information, see the documentation in [`std::fmt`].
|
||||||
///
|
///
|
||||||
|
/// [`Display`]: ../std/fmt/trait.Display.html
|
||||||
|
/// [`Debug`]: ../std/fmt/trait.Debug.html
|
||||||
/// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html
|
/// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html
|
||||||
/// [`std::fmt`]: ../std/fmt/index.html
|
/// [`std::fmt`]: ../std/fmt/index.html
|
||||||
/// [`format!`]: ../std/macro.format.html
|
/// [`format!`]: ../std/macro.format.html
|
||||||
|
@ -301,9 +357,11 @@ pub mod builtin {
|
||||||
/// compile time, yielding an expression of type `&'static str`.
|
/// compile time, yielding an expression of type `&'static str`.
|
||||||
///
|
///
|
||||||
/// If the environment variable is not defined, then a compilation error
|
/// If the environment variable is not defined, then a compilation error
|
||||||
/// will be emitted. To not emit a compile error, use the `option_env!`
|
/// will be emitted. To not emit a compile error, use the [`option_env!`]
|
||||||
/// macro instead.
|
/// macro instead.
|
||||||
///
|
///
|
||||||
|
/// [`option_env!`]: ../std/macro.option_env.html
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -319,11 +377,14 @@ pub mod builtin {
|
||||||
/// If the named environment variable is present at compile time, this will
|
/// If the named environment variable is present at compile time, this will
|
||||||
/// expand into an expression of type `Option<&'static str>` whose value is
|
/// expand into an expression of type `Option<&'static str>` whose value is
|
||||||
/// `Some` of the value of the environment variable. If the environment
|
/// `Some` of the value of the environment variable. If the environment
|
||||||
/// variable is not present, then this will expand to `None`.
|
/// variable is not present, then this will expand to `None`. See
|
||||||
|
/// [`Option<T>`][option] for more information on this type.
|
||||||
///
|
///
|
||||||
/// A compile time error is never emitted when using this macro regardless
|
/// A compile time error is never emitted when using this macro regardless
|
||||||
/// of whether the environment variable is present or not.
|
/// of whether the environment variable is present or not.
|
||||||
///
|
///
|
||||||
|
/// [option]: ../std/option/enum.Option.html
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -385,10 +446,16 @@ pub mod builtin {
|
||||||
|
|
||||||
/// A macro which expands to the line number on which it was invoked.
|
/// A macro which expands to the line number on which it was invoked.
|
||||||
///
|
///
|
||||||
|
/// With [`column!`] and [`file!`], these macros provide debugging information for
|
||||||
|
/// developers about the location within the source.
|
||||||
|
///
|
||||||
/// The expanded expression has type `u32`, and the returned line is not
|
/// The expanded expression has type `u32`, and the returned line is not
|
||||||
/// the invocation of the `line!()` macro itself, but rather the first macro
|
/// the invocation of the `line!()` macro itself, but rather the first macro
|
||||||
/// invocation leading up to the invocation of the `line!()` macro.
|
/// invocation leading up to the invocation of the `line!()` macro.
|
||||||
///
|
///
|
||||||
|
/// [`column!`]: macro.column.html
|
||||||
|
/// [`file!`]: macro.file.html
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -401,9 +468,15 @@ pub mod builtin {
|
||||||
|
|
||||||
/// A macro which expands to the column number on which it was invoked.
|
/// A macro which expands to the column number on which it was invoked.
|
||||||
///
|
///
|
||||||
|
/// With [`line!`] and [`file!`], these macros provide debugging information for
|
||||||
|
/// developers about the location within the source.
|
||||||
|
///
|
||||||
/// The expanded expression has type `u32`, and the returned column is not
|
/// The expanded expression has type `u32`, and the returned column is not
|
||||||
/// the invocation of the `column!()` macro itself, but rather the first macro
|
/// the invocation of the `column!` macro itself, but rather the first macro
|
||||||
/// invocation leading up to the invocation of the `column!()` macro.
|
/// invocation leading up to the invocation of the `column!` macro.
|
||||||
|
///
|
||||||
|
/// [`line!`]: macro.line.html
|
||||||
|
/// [`file!`]: macro.file.html
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -417,11 +490,18 @@ pub mod builtin {
|
||||||
|
|
||||||
/// A macro which expands to the file name from which it was invoked.
|
/// A macro which expands to the file name from which it was invoked.
|
||||||
///
|
///
|
||||||
|
/// With [`line!`] and [`column!`], these macros provide debugging information for
|
||||||
|
/// developers about the location within the source.
|
||||||
|
///
|
||||||
|
///
|
||||||
/// The expanded expression has type `&'static str`, and the returned file
|
/// The expanded expression has type `&'static str`, and the returned file
|
||||||
/// is not the invocation of the `file!()` macro itself, but rather the
|
/// is not the invocation of the `file!` macro itself, but rather the
|
||||||
/// first macro invocation leading up to the invocation of the `file!()`
|
/// first macro invocation leading up to the invocation of the `file!`
|
||||||
/// macro.
|
/// macro.
|
||||||
///
|
///
|
||||||
|
/// [`line!`]: macro.line.html
|
||||||
|
/// [`column!`]: macro.column.html
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
|
|
||||||
use fmt;
|
use fmt;
|
||||||
|
|
||||||
#[cfg(any(target_os = "emscripten",
|
#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
|
||||||
all(target_os = "linux", any(target_arch = "aarch64",
|
|
||||||
target_arch = "arm",
|
target_arch = "arm",
|
||||||
target_arch = "powerpc",
|
target_arch = "powerpc",
|
||||||
target_arch = "powerpc64",
|
target_arch = "powerpc64",
|
||||||
|
@ -24,8 +23,7 @@ use fmt;
|
||||||
target_arch = "arm")),
|
target_arch = "arm")),
|
||||||
all(target_os = "fuchsia", target_arch = "aarch64")))]
|
all(target_os = "fuchsia", target_arch = "aarch64")))]
|
||||||
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
|
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
|
||||||
#[cfg(not(any(target_os = "emscripten",
|
#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
|
||||||
all(target_os = "linux", any(target_arch = "aarch64",
|
|
||||||
target_arch = "arm",
|
target_arch = "arm",
|
||||||
target_arch = "powerpc",
|
target_arch = "powerpc",
|
||||||
target_arch = "powerpc64",
|
target_arch = "powerpc64",
|
||||||
|
|
|
@ -71,13 +71,21 @@ impl FileDesc {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use super::android::cvt_pread64;
|
use super::android::cvt_pread64;
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(target_os = "emscripten")]
|
||||||
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
|
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
|
||||||
-> io::Result<isize>
|
-> io::Result<isize>
|
||||||
{
|
{
|
||||||
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
|
|
||||||
use libc::pread64;
|
use libc::pread64;
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
|
cvt(pread64(fd, buf, count, offset as i32))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
|
||||||
|
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
|
||||||
|
-> io::Result<isize>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use libc::pread64;
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
use libc::pread as pread64;
|
use libc::pread as pread64;
|
||||||
cvt(pread64(fd, buf, count, offset))
|
cvt(pread64(fd, buf, count, offset))
|
||||||
}
|
}
|
||||||
|
@ -104,13 +112,21 @@ impl FileDesc {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use super::android::cvt_pwrite64;
|
use super::android::cvt_pwrite64;
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(target_os = "emscripten")]
|
||||||
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
|
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
|
||||||
-> io::Result<isize>
|
-> io::Result<isize>
|
||||||
{
|
{
|
||||||
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
|
|
||||||
use libc::pwrite64;
|
use libc::pwrite64;
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
|
cvt(pwrite64(fd, buf, count, offset as i32))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
|
||||||
|
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
|
||||||
|
-> io::Result<isize>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use libc::pwrite64;
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
use libc::pwrite as pwrite64;
|
use libc::pwrite as pwrite64;
|
||||||
cvt(pwrite64(fd, buf, count, offset))
|
cvt(pwrite64(fd, buf, count, offset))
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,6 +514,8 @@ impl File {
|
||||||
SeekFrom::End(off) => (libc::SEEK_END, off),
|
SeekFrom::End(off) => (libc::SEEK_END, off),
|
||||||
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
|
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
|
||||||
};
|
};
|
||||||
|
#[cfg(target_os = "emscripten")]
|
||||||
|
let pos = pos as i32;
|
||||||
let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
|
let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
|
||||||
Ok(n as u64)
|
Ok(n as u64)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
use io::{self, Error, ErrorKind};
|
use io::{self, Error, ErrorKind};
|
||||||
use libc::{self, c_int, gid_t, pid_t, uid_t};
|
use libc::{self, c_int, gid_t, pid_t, uid_t};
|
||||||
use mem;
|
|
||||||
use ptr;
|
use ptr;
|
||||||
|
|
||||||
use sys::cvt;
|
use sys::cvt;
|
||||||
|
@ -184,7 +183,9 @@ impl Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NaCl has no signal support.
|
// NaCl has no signal support.
|
||||||
if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) {
|
#[cfg(not(any(target_os = "nacl", target_os = "emscripten")))]
|
||||||
|
{
|
||||||
|
use mem;
|
||||||
// Reset signal handling so the child process starts in a
|
// Reset signal handling so the child process starts in a
|
||||||
// standardized state. libstd ignores SIGPIPE, and signal-handling
|
// standardized state. libstd ignores SIGPIPE, and signal-handling
|
||||||
// libraries often set a mask. Child processes inherit ignored
|
// libraries often set a mask. Child processes inherit ignored
|
||||||
|
|
28
src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
Normal file
28
src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:attr-on-trait.rs
|
||||||
|
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate attr_on_trait;
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
#[attr_on_trait::foo]
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for i32 {
|
||||||
|
fn foo(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
3i32.foo();
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
drop(attr);
|
||||||
|
assert_eq!(item.to_string(), "fn foo() { }");
|
||||||
|
"fn foo(&self);".parse().unwrap()
|
||||||
|
}
|
56
src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
Normal file
56
src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::{TokenStream, TokenNode, Span, Diagnostic};
|
||||||
|
|
||||||
|
fn parse(input: TokenStream) -> Result<(), Diagnostic> {
|
||||||
|
let mut count = 0;
|
||||||
|
let mut last_span = Span::default();
|
||||||
|
for tree in input {
|
||||||
|
let span = tree.span;
|
||||||
|
if count >= 3 {
|
||||||
|
return Err(span.error(format!("expected EOF, found `{}`.", tree))
|
||||||
|
.span_note(last_span, "last good input was here")
|
||||||
|
.help("input must be: `===`"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let TokenNode::Op('=', _) = tree.kind {
|
||||||
|
count += 1;
|
||||||
|
} else {
|
||||||
|
return Err(span.error(format!("expected `=`, found `{}`.", tree)));
|
||||||
|
}
|
||||||
|
|
||||||
|
last_span = span;
|
||||||
|
}
|
||||||
|
|
||||||
|
if count < 3 {
|
||||||
|
return Err(Span::default()
|
||||||
|
.error(format!("found {} equal signs, need exactly 3", count))
|
||||||
|
.help("input must be: `===`"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn three_equals(input: TokenStream) -> TokenStream {
|
||||||
|
if let Err(diag) = parse(input) {
|
||||||
|
diag.emit();
|
||||||
|
return TokenStream::empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
"3".parse().unwrap()
|
||||||
|
}
|
38
src/test/ui-fulldeps/proc-macro/three-equals.rs
Normal file
38
src/test/ui-fulldeps/proc-macro/three-equals.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:three-equals.rs
|
||||||
|
// ignore-stage1
|
||||||
|
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate three_equals;
|
||||||
|
|
||||||
|
use three_equals::three_equals;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// This one is okay.
|
||||||
|
three_equals!(===);
|
||||||
|
|
||||||
|
// Need exactly three equals.
|
||||||
|
three_equals!(==);
|
||||||
|
|
||||||
|
// Need exactly three equals.
|
||||||
|
three_equals!(=====);
|
||||||
|
|
||||||
|
// Only equals accepted.
|
||||||
|
three_equals!(abc);
|
||||||
|
|
||||||
|
// Only equals accepted.
|
||||||
|
three_equals!(!!);
|
||||||
|
|
||||||
|
// Only three characters expected.
|
||||||
|
three_equals!(===a);
|
||||||
|
}
|
48
src/test/ui-fulldeps/proc-macro/three-equals.stderr
Normal file
48
src/test/ui-fulldeps/proc-macro/three-equals.stderr
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
error: found 2 equal signs, need exactly 3
|
||||||
|
--> $DIR/three-equals.rs:25:5
|
||||||
|
|
|
||||||
|
25 | three_equals!(==);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: input must be: `===`
|
||||||
|
|
||||||
|
error: expected EOF, found `=`.
|
||||||
|
--> $DIR/three-equals.rs:28:21
|
||||||
|
|
|
||||||
|
28 | three_equals!(=====);
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
note: last good input was here
|
||||||
|
--> $DIR/three-equals.rs:28:21
|
||||||
|
|
|
||||||
|
28 | three_equals!(=====);
|
||||||
|
| ^^
|
||||||
|
= help: input must be: `===`
|
||||||
|
|
||||||
|
error: expected `=`, found `abc`.
|
||||||
|
--> $DIR/three-equals.rs:31:19
|
||||||
|
|
|
||||||
|
31 | three_equals!(abc);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: expected `=`, found `!`.
|
||||||
|
--> $DIR/three-equals.rs:34:19
|
||||||
|
|
|
||||||
|
34 | three_equals!(!!);
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: expected EOF, found `a`.
|
||||||
|
--> $DIR/three-equals.rs:37:22
|
||||||
|
|
|
||||||
|
37 | three_equals!(===a);
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
note: last good input was here
|
||||||
|
--> $DIR/three-equals.rs:37:21
|
||||||
|
|
|
||||||
|
37 | three_equals!(===a);
|
||||||
|
| ^
|
||||||
|
= help: input must be: `===`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue